Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
   * JBoss, Home of Professional Open Source
   * Copyright 2005, JBoss Inc., and individual contributors as indicated
   * by the @authors tag. See the copyright.txt in the distribution for a
   * full listing of individual contributors.
   *
   * This is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as
   * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
  
  package org.jboss.remoting.transport.multiplex;
  
  import  org.jboss.logging.Logger;
  
  import java.net.Socket;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.Timer;
MultiplexingManager is the heart of the Multiplex system. It is the implementation of the virtual socket group concept. See the Multiplex documentation on the labs.jboss.org website for more information about virtual socket groups.

MultiplexingManager wraps a single real java.net.Socket. It creates the socket when it is running on the client side, and it is passed a socket by MasterServerSocket when it is running on the server side.

MultiplexingManager creates the infrastructure which supports multiplexing, including an OutputMultiplexor output thread and one or more InputMultiplexor input threads. When the last member leaves the socket group, a MultiplexingManager is responsible for negotiating with its remote peer for permission to shut down, and for tearing down the multiplexing infrastructure when the negotiations succeed.

MultiplexingManager also provides the mechanism by which a virtual socket joins a virtual socket group, identifying the new socket to the InputMultiplexor input thread.

Copyright (c) 2005

Deprecated:
As of release 2.4.0 the multiplex transport will no longer be actively supported.
Author(s):
Ron Sigal
  
  public class MultiplexingManager
  {
     private static final Logger log = Logger.getLogger(MultiplexingManager.class);


   
Determines how often to check that no MultiplexingManagers have been running, in which case the static threads can be shut down.
  
     private static int staticThreadsMonitorPeriod;

   
True if and only if the MultiplexingManager static threads are running
  
     private static boolean staticThreadsRunning;

   
This object is used to synchronized operations on the managersByRemoteAddress map.
  
    private static Object shareableMapLock = new Object();

   
A HashMap<InetSocketAddress, HasnSet<MultiplexingManager>> of sets of MultiplexingManager's indexed by remote address. Holds all MultiplexingManagers whose peer has an attached VirtualServerSocket.
 
    private static Map shareableManagers = new HashMap();

   
This object is used to synchronize operations on the managersByLocalAddress map.
 
    private static Object localAddressMapLock = new Object();

   
A HashMap<InetSocketAddress, HasnSet<MultiplexingManager>> of sets of MultiplexingManager's indexed by local address
 
    private static Map managersByLocalAddress = new HashMap();

   
This object is used to synchronized operations on the managersByRemoteAddress map.
 
    private static Object remoteAddressMapLock = new Object();

   
A HashMap<InetSocketAddress, HasnSet<MultiplexingManager>> of sets of MultiplexingManager's indexed by remote address
 
 //   private static Map managersByRemoteAddress = Collections.synchronizedMap(new HashMap());
    private static Map managersByRemoteAddress = new HashMap();

   
Set of all MultiplexingManagers
 
    private static Set allManagers = Collections.synchronizedSet(new HashSet());

   
InputMultiplexor in this JVM
 
    private static InputMultiplexor inputMultiplexor;

   
OutputMultiplexor in this JVM
 
    private static OutputMultiplexor outputMultiplexor;

   
Thread for writing to socket's OutputStream
 
    private static OutputMultiplexor.OutputThread outputThread;

   
MultiGroupInputThread reading from socket's InputStream and distributing to virtual sockets Processes all NIO sockets
 
    private static MultiGroupInputThread multiGroupInputThread;

   
MultiplexingInputStreams register with virtualSelector when they have bytes to read
 
    private static VirtualSelector virtualSelector;

   
Thread for getting asynchronous messages from remote Protocol
 
    private static Protocol.BackChannelThread backChannelThread;

   
Holds PendingActions waiting to be performed
 
    private static List pendingActions = new ArrayList();

   
Removes virtual sockets from closingSockets and closes them.
 
    private static PendingActionThread pendingActionThread;

   
Thread for stashing potentially long activities, as well as periodic activities
 
    private static Timer timer;

   
Used to determine when to shut down static threads
 
    private static boolean hasBeenIdle;

   
Used to distinguish the static threads in this jvm
 
    private final static short time = (short) System.currentTimeMillis();

   
If shutdown request is not answered within this time period, assume a problem snd shut down.
 
    private int shutdownRequestTimeout;

   
Determines how often ShutdownMonitorTimerTask should check for response to ShutdownRequestThread.
 
    private int shutdownMonitorPeriod;

   
If the peer MultiplexingManager has refused to shutdown this many times, shut down anyway.
 
    private int shutdownRefusalsMaximum;

   
Holds configuration parameters
 
    private static Map configuration = new HashMap();

   
A HashMap<SocketId, VirtualSocket> of VirtualSocket's indexed by local SocketId
 
    private Map socketMap = Collections.synchronizedMap(new HashMap());

   
A HashSet of SocketId's registered on this MultiplexingManager
 
    private Set registeredSockets = Collections.synchronizedSet(new HashSet());

   
A HashMap<Long, OutputStream> of piped OutputStreams associated with InputStreams
 
    private Map outputStreamMap = Collections.synchronizedMap(new HashMap());

   
A HashMap<Long, InputStream> of InputStreams associated with virtual sockets
 
    private Map inputStreamMap = Collections.synchronizedMap(new HashMap());

   
Holds OutputStreams associated with virtual sockets
 
    private Set outputStreamSet = Collections.synchronizedSet(new HashSet());

   
Protocol back channel OutputStream
 
    private OutputStream backchannelOutputStream;

   
Threads waiting to be notified of registration of remote server socket
 
    private Set threadsWaitingForRemoteServerSocket = new HashSet();

   
Protocol object for handling connection/disconnection communications
 
    private Protocol protocol;

   
Actual local socket upon which this family of virtual sockets is based
 
    private Socket socket;

   
Returned by toString() and used in log messages
 
    String description;

   
bound state of actual local socket
 
    private boolean bound = false;

   
connected state of actual local socket
 
    private boolean connected = false;

   
SocketAddress of remote actual socket to which this Manager's socket is connected
 
    private InetSocketAddress remoteSocketAddress;

   
SocketAddress to which this manager's actual socket is bound
 
    private InetSocketAddress localSocketAddress;

   
Represents local port on which this manager's actual socket is bound, with any local address
 
InputStream of real socket
 
    private InputStream inputStream;

   
OutputStream of real socket
 
    private OutputStream outputStream;

   
Currently registered server socket
 
    private ServerSocket serverSocket;

   
Indicates if remote server socket has been registered
 
    private boolean remoteServerSocketRegistered = false;

   
True if and only if this MultiplexingManager was originally created by a call to MasterServerSocket.acceptServerSocketConnection().
 
    private boolean createdForRemoteServerSocket;

   
SingleGroupInputThread reading from socket's InputStream and distributing to virtual sockets
 
OutputStream for unknown virtual sockets
 
Manages the shutdown handshaking protocol between peer MultiplexingManagers
 
    private ShutdownManager shutdownManager = new ShutdownManager();

   
Thread that carries out shut down process
 
    private ShutdownThread shutdownThread;

   
true if and only MultiplexingManager is completely shut down
 
    private boolean shutdown = false;

   
Indicates if log trace level is enabled
 
    private boolean trace;

   
Indicates if log debug level is enabled
 
    private boolean debug;

   
Indicates if log info level is enabled
 
    private boolean info;
 
    private long id;

   
SocketFactory to use for creating sockets
 
    private SocketFactory socketFactory;

   
Saves HandshakeCompletedEvent for SSLSocket
 
Holds IOException thrown by real InputStream
 
    private IOException readException;

   
Holds IOException thrown by real OutputStream
 
    private IOException writeException;
 
 
    protected synchronized static void init(Map configurationthrows IOException
    {
       try
       {
          if ()
             return;
 
          .debug("starting static threads");
 
          // Start output thread.
           = new OutputMultiplexor(configuration);
          .setName("output:" + );
          .setDaemon(true);
          .start();
          .debug("started output thread");
 
          // Start input thread.
           = new InputMultiplexor(configuration);
          .setName("input:" + );
          .setDaemon(true);
          .start();
          .debug("started input thread");
 
          // Start back channel thread.
           = new VirtualSelector();
           = Protocol.getBackChannelThread();
          .setName("backchannel:" + );
          .setDaemon(true);
          .start();
          .debug("started backchannel thread");
 
          // Start timer.
           = new Timer(true);
          TimerTask shutdownMonitorTask = new TimerTask()
          {
             public void run()
             {
                .trace("allManagers.isEmpty(): " + .isEmpty());
                .trace("hasBeenIdle: " + );
                if (.isEmpty())
                {
                   if ()
                   {
                      MultiplexingManager.shutdownThreads();
                      this.cancel();
                   }
                   else
                       = true;
                }
                else
                {
                    = false;
                }
             }
 
          };
 
          // Start pending actions thread.
           = new PendingActionThread();
          .setName("pending actions:" + );
          .setDaemon(true);
          .start();
          .debug("started pendingAction thread");
 
           = true;
       }
       catch (IOException e)
       {
          .error(e);
          throw e;
       }
    }
 
 
    protected MultiplexingManager(Map configurationthrows IOException
    {
       if (configuration != null)
          ..putAll(configuration);
        = (SocketFactoryconfiguration.get(.);
        = new Date().getTime();
        = createSocket();
       .add(this);
       if (.debug("new MultiplexingManager(" +  + "): " + );
    }


Parameters:
socket
configuration
Throws:
IOException
 
    protected MultiplexingManager(Socket socketMap configurationthrows IOException
    {
       this. = socket;
       if (configuration != null)
          ..putAll(configuration);
        = new Date().getTime();
       setup();
       .add(this);
       if (.debug("new MultiplexingManager(" +  + "): " + );
    }


Parameters:
address
timeout
configuration
Throws:
IOException
 
    protected MultiplexingManager(InetSocketAddress addressint timeoutMap configuration)
    throws IOException
    {
       if (configuration != null)
          ..putAll(configuration);
        = (SocketFactoryconfiguration.get(.);
        = new Date().getTime();
        = createSocket(addresstimeout);
       setup();
       .add(this);
       if (.debug("new MultiplexingManager(" +  + "): " + );
    }


 
    protected synchronized void setup() throws IOException
    {
        = .toString();
        = .isTraceEnabled();
        = .isDebugEnabled();
        = .isInfoEnabled();
 
       // Initialize MultiplexingManager parameters.
 
       // Make sure static threads are running.
       synchronized (MultiplexingManager.class)
       {
          if (!)
             init();
       }
 
       // Get InputStream and OutputStream
       if (.getChannel() == null)
       {
 //         inputStream = new BufferedInputStream(socket.getInputStream());
 //         outputStream = new BufferedOutputStream(socket.getOutputStream());
           = .getInputStream();
           = .getOutputStream();
       }
       else
       {
           = Channels.newInputStream(.getChannel());
           = Channels.newOutputStream(.getChannel());
          .setTcpNoDelay(false);
       }
 
       // register dead letter output stream (for unrecognized destinations)
 
       // TODO: what was this for???
 
       // set up standard piped streams
 
       // Create protocol backchannel streams
        = new Protocol(this);
       bcis.register(this);
       if (.debug("registered backchannel input stream");
 
       // Register with OutputMultiplexor
       .register(this);
 
       // Create or register with input thread
       if (.getChannel() == null)
       {
          // start input thread
          .debug("creating single group input thread");
 
          if ( == null)
              = new InputMultiplexor();
 
          .setName(.getName() + ":input(" +  + ")");
          .start();
       }
       else
       {
          .getChannel().configureBlocking(false);
          .debug("registered socket group");
       }
 
        = true;
        = true;
 
       if ( instanceof SSLSocket)
       {
 //         Object o = configuration.get(Multiplex.SSL_HANDSHAKE_LISTENER);
 //         if (o != null)
 //         {
 //            HandshakeCompletedListener hcl = (HandshakeCompletedListener) o;
 //            ((SSLSocket) socket).addHandshakeCompletedListener(hcl);
 //         }
          ((SSLSocket).addHandshakeCompletedListener(this);
       }
    }
 
 
    protected void initParameters(Map configuration)
    {
       this. = configuration;
 
          = Multiplex.getOneParameter(configuration,
                                      "staticThreadsMonitorPeriod",
                                       .,
                                       .);
 
          = Multiplex.getOneParameter(configuration,
                                      "shutdownRequestTimeout",
                                      .,
                                      .);
 
          = Multiplex.getOneParameter(configuration,
                                      "shutdownRefusalsMaximum",
                                      .,
                                      .);
 
          = Multiplex.getOneParameter(configuration,
                                      "shutdownMonitorPeriod",
                                      .,
                                      .);
    }


Parameters:
socket
configuration
Returns:
Throws:
IOException TODO: what if multiplexor already exists?
 
    public static MultiplexingManager getaManager(Socket socketMap configurationthrows IOException
    {
       .debug("entering getaManager(Socket socket)");
       return new MultiplexingManager(socketconfiguration);
    }


Parameters:
address
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    {
       return getaManagerByLocalAddress(addressnull);
    }


Parameters:
address
conf
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    {
       .debug("entering getaManagerByLocalAddress(InetSocketAddress address)");
       MultiplexingManager m = null;
 
       synchronized ()
       {
          HashSet managers = (HashSet.get(address);
 
          if (managers != null)
          {
             Iterator it = managers.iterator();
             while (it.hasNext())
             {
                m = (MultiplexingManagerit.next();
                try
                {
                   m.shutdownManager.incrementReferences();
                   return m;
                }
                catch (IOException e)
                {
                }
             }
          }
       }
 
       .debug("There is no joinable MultiplexingManager. Creating new one.");
       m = new MultiplexingManager(conf);
       m.bind(address);
       return m;
    }


Parameters:
address
timeout
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    getaManagerByRemoteAddress(InetSocketAddress addressint timeoutthrows IOException
    {
       return getaManagerByRemoteAddress(addresstimeoutnull);
    }


Parameters:
address
timeout
configuration
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    getaManagerByRemoteAddress(InetSocketAddress addressint timeoutMap conf)
    throws IOException
    {
       .debug("entering getaManagerByRemoteAddress(InetSocketAddress address)");
 
 //      if (isOnServer())
 //      {
 
       // Check each of the MultiplexingManagers connected to the target remote address, looking
       // for one which is not shutting down.
       synchronized()
       {
          HashSet managers = (HashSet.get(address);
 
          if (managers != null && !managers.isEmpty())
          {
             Iterator it = managers.iterator();
             while (it.hasNext())
             {
                MultiplexingManager m = (MultiplexingManagerit.next();
                try
                {
                   m.shutdownManager.incrementReferences();
                   return m;
                }
                catch (Exception e)
                {
                   .debug("manager shutting down: " + m);
                }
             }
          }
       }
 
       return new MultiplexingManager(addresstimeoutconf);
    }



Parameters:
remoteAddress
localAddress
timeout
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    getaManagerByAddressPair(InetSocketAddress remoteAddressInetSocketAddress localAddressint timeout)
    throws IOException
    {
       return getaManagerByAddressPair(remoteAddresslocalAddresstimeoutnull);
    }


Parameters:
remoteAddress
localAddress
timeout
configuration
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    getaManagerByAddressPair(InetSocketAddress remoteAddressInetSocketAddress localAddress,
                             int timeoutMap conf)
    throws IOException
    {
       .debug("entering getaManagerByRemoteAddress(InetSocketAddress address)");
       MultiplexingManager m;
 
       // Check each of the MultiplexingManagers connected to the target remote address, looking
       // for one which is not shutting down.
       synchronized()
       {
          HashSet managers = (HashSet.get(remoteAddress);
 
          if (managers != null && !managers.isEmpty())
          {
             Iterator it = managers.iterator();
 
             while (it.hasNext())
             {
                m = (MultiplexingManagerit.next();
                if (m.getSocket().getLocalAddress().equals(localAddress.getAddress()) &&
                    m.getSocket().getLocalPort() == localAddress.getPort())
                {
                   try
                   {
                      m.shutdownManager.incrementReferences();
                      return m;
                   }
                   catch (Exception e)
                   {
                      .debug("manager shutting down: " + m);
                   }
                }
             }
          }
       }
 
       .debug("There is no joinable MultiplexingManager. Creating new one.");
       m = new MultiplexingManager(conf);
       m.bind(localAddress);
       return m;
    }


Parameters:
address
timeout
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    getaShareableManager(InetSocketAddress addressint timeoutthrows IOException
    {
       return getaShareableManager(addresstimeoutnull);
    }


Parameters:
address
timeout
conf
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    getaShareableManager(InetSocketAddress addressint timeoutMap confthrows IOException
    {
       .debug("entering getaShareableManager(InetSocketAddress address)");
 
       // Check each of the shareable MultiplexingManagers connected to the target remote address, looking
       // for one which is not shutting down.
       synchronized()
       {
          HashSet managers = (HashSet.get(address);
 
          if (managers != null && !managers.isEmpty())
          {
             Iterator it = managers.iterator();
             while (it.hasNext())
             {
                MultiplexingManager m = (MultiplexingManagerit.next();
                try
                {
                   m.shutdownManager.incrementReferences();
                   return m;
                }
                catch (Exception e)
                {
                   .debug("manager shutting down: " + m);
                }
             }
          }
       }
 
       return new MultiplexingManager(addresstimeoutconf);
    }


Parameters:
address
timeout
conf
Returns:
Throws:
IOException
 
    public static  MultiplexingManager
    throws IOException
    {
       .debug("entering getAnExistingShareableManager()");
 
       // Check each of the shareable MultiplexingManagers connected to the target remote address, looking
       // for one which is not shutting down.
       synchronized()
       {
          HashSet managers = (HashSet.get(address);
 
          if (managers != null && !managers.isEmpty())
          {
             Iterator it = managers.iterator();
 
             while (it.hasNext())
             {
                MultiplexingManager m = (MultiplexingManagerit.next();
                try
                {
                   m.shutdownManager.incrementReferences();
                   return m;
                }
                catch (Exception e)
                {
                   .debug("manager shutting down: " + m);
                }
             }
          }
       }
 
       return null;
    }


Parameters:
remoteAddress
localAddress
timeout
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
    getaShareableManagerByAddressPair(InetSocketAddress remoteAddressInetSocketAddress localAddressint timeout)
    throws IOException
    {
       return getaShareableManagerByAddressPair(remoteAddresslocalAddresstimeoutnull);
    }


Parameters:
remoteAddress
localAddress
timeout
conf
Returns:
Throws:
IOException
 
    public static synchronized MultiplexingManager
                                      int timeoutMap conf)
    throws IOException
    {
       MultiplexingManager m;
 
       // Check each of the shareable MultiplexingManagers connected to the target remote address, looking
       // for one which is not shutting down.
       synchronized()
       {
          HashSet managers = (HashSet.get(remoteAddress);
          if (managers != null && !managers.isEmpty())
          {
             Iterator it = managers.iterator();
 
             while (it.hasNext())
             {
                m = (MultiplexingManagerit.next();
                if (m.getSocket().getLocalAddress().equals(localAddress.getAddress()) &&
                    m.getSocket().getLocalPort() == localAddress.getPort())
                {
                   try
                   {
                      m.shutdownManager.incrementReferences();
                      return m;
                   }
                   catch (Exception e)
                   {
                      .debug("manager shutting down: " + m);
                   }
                }
             }
          }
       }
 
       .debug("There is no joinable MultiplexingManager. Creating new one.");
       m = new MultiplexingManager(conf);
       m.bind(localAddress);
       return m;
    }


Parameters:
remoteAddress
localAddress
conf
Returns:
Throws:
IOException
 
    public static MultiplexingManager
                                               InetSocketAddress localAddress,
                                               Map conf)
    throws IOException
    {
       .debug("entering getaShareableManager(InetSocketAddress address)");
       MultiplexingManager m;
 
       // Check each of the shareable MultiplexingManagers connected to the target remote address, looking
       // for one which is not shutting down.
       synchronized()
       {
          HashSet managers = (HashSet.get(remoteAddress);
 
          if (managers != null && !managers.isEmpty())
          {
             Iterator it = managers.iterator();
 
             while (it.hasNext())
             {
                m = (MultiplexingManagerit.next();
                if (m.getSocket().getLocalAddress().equals(localAddress.getAddress()) &&
                    m.getSocket().getLocalPort() == localAddress.getPort())
                {
                   try
                   {
                      m.shutdownManager.incrementReferences();
                      return m;
                   }
                   catch (Exception e)
                   {
                      .debug("manager shutting down: " + m);
                   }
                }
             }
          }
       }
 
       return null;
    }


Parameters:
address
Returns:
Throws:
IOException
 
    public static boolean checkForShareableManager(InetSocketAddress address)
    throws IOException
    {
       .debug("entering checkForShareableManager(InetSocketAddress address)");
 
       // Check each if there is at least one shareable MultiplexingManagers connected to the target remote address.
       synchronized ()
       {
          HashSet managers = (HashSet.get(address);
 
          if (managers != null && !managers.isEmpty())
             return true;
 
          return false;
       }
    }


Parameters:
localAddress
remoteAddress
Returns:
 
    public static boolean checkForManagerByAddressPair(InetSocketAddress localAddress,
                                                       InetSocketAddress remoteAddress)
    {
       .debug("entering checkForManagerByAddressPair()");
 
       // Check each of the MultiplexingManagers connected to the target remote address, looking
       // for one bound to the local address.
       synchronized()
       {
          HashSet managers = (HashSet.get(remoteAddress);
 
          if (managers != null && !managers.isEmpty())
          {
             Iterator it = managers.iterator();
 
             while (it.hasNext())
             {
                MultiplexingManager m = (MultiplexingManagerit.next();
 
                if (m.localSocketAddress.equals(localAddress))
                   return true;
             }
          }
       }
 
       return false;
    }


Parameters:
localAddress
remoteAddress
Returns:
   public static boolean checkForShareableManagerByAddressPair(InetSocketAddress localAddress,
                                                               InetSocketAddress remoteAddress)
   {
      .debug("entering checkForShareableManagerByAddressPair()");
      // Check each of the shareable MultiplexingManagers connected to the target remote address, looking
      // for one bound to the local address.
      synchronized ()
      {
         HashSet managers = (HashSet.get(remoteAddress);
         if (managers != null && !managers.isEmpty())
         {
            Iterator it = managers.iterator();
            while (it.hasNext())
            {
               MultiplexingManager m = (MultiplexingManagerit.next();
               if (m.localSocketAddress.equals(localAddress))
                  return true;
            }
         }
      }
      return false;
   }


Returns:
   public static int getStaticThreadMonitorPeriod()
   {
      return ;
   }


Parameters:
period
   public static void setStaticThreadsMonitorPeriod(int period)
   {
       = period;
   }


   protected synchronized static void shutdownThreads()
   {
      .debug("entering shutdownThreads");
      if ( != null)
         .shutdown();
      if ( != null)
         .shutdown();
      if ( != null)
         .shutdown();
      if ( != null)
         .shutdown();
      .debug("cancelling timer");
      if ( != null)
         .cancel();
      while (true)
      {
         try
         {
            if ( != null)
               .join();
            if ( != null)
               .join();
            if ( != null)
               .join();
            if ( != null)
               .join();
            break;
         }
         catch (InterruptedException ignored) {}
      }
       = false;
      .debug("static threads shut down");
   }


Adds a PendingAction to the list of actions waiting to be executed.

Parameters:
pendingAction
   protected static void addToPendingActions(PendingAction pendingAction)
   {
      synchronized ()
      {
         .add(pendingAction);
         .notifyAll();
      }
   }


Binds the wrapped socket.

Parameters:
address
Throws:
IOException
   public synchronized void bind(InetSocketAddress addressthrows IOException
   {
      if ()
         throw new IOException("socket is already bound");
      if ( == null)
          = createSocket();
      if ( == null)
          = address;
      else
         .bind(address);
       = true;
   }

Connects the wrapped socket.

Parameters:
address
timeout
Throws:
IOException
   public synchronized void connect(InetSocketAddress addressint timeoutthrows IOException
   {
      if ()
      {
         if (.getRemoteSocketAddress().equals(address))
            return;
         else
            throw new IOException("socket is already connected");
      }
      if (.debug("connecting to: " + address);
      if ( == null)
          = createSocket(addresstimeout);
      else
         .connect(addresstimeout);
       = true;
      setup();
   }


Identifies a VirtualServerSocket as the one associated with this virtual socket group.

Returns:
a MultiplexingInputStream for use by serverSocket.
   public synchronized MultiplexingInputStream registerServerSocket(ServerSocket serverSocketthrows IOException
   {
      if (this. != null && this. != serverSocket)
      {
         .error("[" +  + "]: " + "attempt to register a second server socket");
         .error("current server socket: " + this..toString());
         .error("new server socket:     " + serverSocket.toString());
         throw new IOException("attempt to register a second server socket");
      }
      if (.debug(serverSocket.toString());
      this. = serverSocket;
      return getAnInputStream(.null);
   }


Indicates a VirtualServerSocket is leaving this virtual socket group.

Parameters:
serverSocket
Throws:
IOException
   public synchronized void unRegisterServerSocket(ServerSocket serverSocketthrows IOException
   {
      if (this. != serverSocket)
      {
         .error("server socket attempting unregister but is not registered");
         throw new IOException("server socket is not registered");
      }
      .debug("server socket unregistering");
      this. = null;
   }


Adds a VirtualSocket to this virtual socket group.

Parameters:
socket
Returns:
a MultiplexingInputStream for use by socket
Throws:
IOException
   public synchronized MultiplexingInputStream registerSocket(VirtualSocket socketthrows IOException
   {
      SocketId localSocketId = socket.getLocalSocketId();
      VirtualSocket currentSocket = (VirtualSocket.put(localSocketIdsocket);
      if (currentSocket != null)
      {
         String errorMessage = "attempting to register socket on currently used port:"
                              + currentSocket.getLocalVirtualPort();
         .error(errorMessage);
         throw new IOException(errorMessage);
      }
      if (.debug("registering virtual socket on port: " + localSocketId.getPort());
      return getAnInputStream(localSocketIdsocket);
   }


Indicates that a VirtualSocket is leaving a virtual socket group.

Parameters:
socket
Throws:
IOException
   public synchronized void unRegisterSocket(VirtualSocket socketthrows IOException
   {
      try
      {
         if (.debug(this + ": entering unRegisterSocket()");
         SocketId localSocketId = socket.getLocalSocketId();
         if (localSocketId == null)
            return;
         VirtualSocket currentSocket = (VirtualSocket.remove(localSocketId);
         if (currentSocket == null)
         {
            String errorMessage = "attempting to unregister unrecognized socket: " + socket.getLocalSocketId().getPort();
            .error(errorMessage);
            throw new IOException(errorMessage);
         }
         if (.debug("unregistering virtual socket on port: " + localSocketId.getPort());
         .remove(localSocketId);
         removeAnInputStream(localSocketId);
         if (.debug(this + ": leaving unRegisterSocket()");
      }
      finally
      {
         socket.close();
      }
   }


 
Indicates that a VirtualServerSocket belongs the virtual socket group at the remote end of the connection. This virtual socket groupD becomes "joinable", in the sense that a new VirtualSocket <it>v</it> can join this virtual group because there is a VirtualServerSocket at the other end of the connection to create a remote peer for v.
    public synchronized void registerRemoteServerSocket() throws IOException
    {
       .debug("registerRemoteServerSocket()");
       {
          .error("duplicate remote server socket registration");
          throw new IOException("duplicate remote server socket registration");
       }
       else
       {
           = true;
          // Now that remote MultiplexingManager has a VirtualServerSocket, we
          // add it to set of managers eligible to accept new clients.
          synchronized ()
          {
          }
          if (!)
             incrementReferences();
       }
    }


Indicates there will no longer be a VirtualServeSocket at the remote end of this connection. This virtual socket group will no longer be "joinable". (See registerRemoteServerSocket().)
   public synchronized void unRegisterRemoteServerSocket()
   {
         .error("no remote server socket is registered");
      else
      {
         if (.debug(this + ": remote VSS unregistering");
          = false;
         unregisterShareable();
         MultiplexingManager.addToPendingActions
         (
               new PendingAction()
               {
                  void doAction()
                  {
                     try
                     {
                        decrementReferences();
                     }
                     catch (IOException e)
                     {
                        .error(e);
                     }
                  }
               }
         );
      }
   }