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 java.net.Socket;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  
  import  org.jboss.logging.Logger;
MultiplexServerInvoker is the server side of the Multiplex transport. For more information, see Remoting documentation on labs.jboss.org.

Deprecated:
As of release 2.4.0 the multiplex transport will no longer be actively supported.
Author(s):
Tom Elrod
Ron Sigal
  
  public class MultiplexServerInvoker extends SocketServerInvoker
  {
     protected static final Logger log = Logger.getLogger(MultiplexServerInvoker.class);
     private static boolean trace = .isTraceEnabled();
     
     private static Map socketGroupMap = new HashMap();
     private static Map addressPairMap = new HashMap();
  
     private boolean isVirtual = false;
     private Map virtualServerInvokers;
     private Socket connectPrimingSocket;
     private SocketGroupInfo socketGroupInfo;
     private AddressPair addressPair;
     private String bindHost;
     private int bindPort;
     private int originalBindPort;
     private InetAddress bindAddress;
     private boolean readyToStart = true
     private boolean needsSocketGroupConfiguration = true;
     private boolean cleanedUp;
     private boolean hasMaster;
     private int errorCount;
     
     private ServerSocket serverSocket;
     
    /////////////////////////////////////////////////////////////////////////////////////
    //                    configurable Multiplex parameters                            //
    /////////////////////////////////////////////////////////////////////////////////////
    /*
     * The following parameters may be set in any of four ways:
     * 
     * 1. They may be appended to an <code>InvokerLocator</code> passed to a
     *    <code>Connector</code> constructor.
     * 2. They may be included in a configuration <code>Map</code> passed to a
     *    <code>Connector</code> constructor.
     * 3. They may be described in a <config> XML element passed to
     *    <code>Connector.setConfiguration()</code>.
     * 4. In some cases, a <code>MultiplexServerInvoker</code> setter methods may be invoked.
     * 
     * Of those of the following parameters destined for <code>MultiplexServerInvoker</code>,
     * there are two categories.
     * 
     * 1. <code>serverMultiplexId</code>, <code>multiplexConnectHost</code>, and
     *    <code>multiplexConnectPort</code> are used to
     *    match up <code>MultiplexClientInvoker</code>s and virtual
     *    <code>MultiplexServerInvokers</code> so that
     *    they share an underlying socket connection.  Depending on the way in which
     *    the information is provided (see Remoting documentation), the connection may
     *    be created any time during or after the call to <code>Connector.create()</code>. Note,
     *    however, that if a callback <code>MultiplexServerInvoker</code> is created with just a 
     *    <code>serverMultiplexId</code> parameter (server rule 3 in the Remoting documentation),
     *    then calling <code>setMultiplexConnectHost()</code> and
     *    <code>setMultiplexConnectPort()</code> will
     *    not trigger the creation of a connection.  Moreover, when a <code>Client</code> comes
     *    along, the connect information supplied by the <code>Client</code> will be used, so there
     *    is no point to having setter methods for these parameters.
     *    
     * 2. <code>maxAcceptErrors</code> is used in the
     *    <code>MultiplexServerInvoker</code> <code>accept()</code> loop, and it
     *    may be changed at any time by calling <code>setMaxAcceptErrors()</code>. 
     * 
     * Those of the following parameters which are destined for the <code>MultiplexingManager</code>,
     * <code>InputMultiplexor</code>, and <code>OutputMultiplexor</code> classes are
     * passed to them by way of a configuration <code>Map</code> passed to
     * <code>VirtualSocket</code> and <code>VirtualServerSocket</code> constructors.
     * 
     * A <code>VirtualServerSocket</code> is created when a server side master
     * <code>MultiplexServerInvoker</code>
     * accepts a connection request generated by the creation of a priming socket on a client.  
     * Since this can happen any time after <code>Connector.start()</code> is created, the values of
     * these parameters can be changed by calling their respective setter methods any
     * time before <code>Connector.start()</code> is called.
     * 
     * A <code>VirtualSocket</code> is created when a client side
     * <code>MultiplexClientInvoker</code> or callback
     * <code>MultiplexServerInvoker</code> opens a priming socket, and this happens when
     * <code>Connector.create()</code> is called.  Therefore, the values of these parameters can be 
     * changed by calling their respective setter methods any time before
     * <code>Connector.create()</code> is called.
     */
    // MultiplexingManager:
    private int staticThreadsMonitorPeriod;
    private int shutdownRequestTimeout;
    private int shutdownRefusalsMaximum;
    private int shutdownMonitorPeriod;
    
    // InputMultiplexor:
    private int inputBufferSize;
    private int inputMaxErrors;
 
    // OutputMultiplexor: 
    private int outputMessagePoolSize;
    private int outputMessageSize;
    private int outputMaxChunkSize;
    private int outputMaxTimeSlice;
    private int outputMaxDataSlice;
 
    // MultiplexServerInvoker
    private int     maxAcceptErrors;
    private String  serverMultiplexId;
    private String  multiplexConnectHost;
    private int     multiplexConnectPort;
    private boolean multiplexConnectPortIsSet;  // to check for missing configuration information
 
    public static Map getAddressPairMap()
    {
       return ;
    }
    
    public static Map getSocketGroupMap()
    {
       return ;
    }
   
   
Create a new MultiplexServerInvoker.

Parameters:
locator
 
    public MultiplexServerInvoker(InvokerLocator locator)
    {
       super(locator);
 //      virtualServerInvokers = Collections.synchronizedMap(new HashMap());
        = new HashMap();
    }

   
Create a new MultiplexServerInvoker.
 
    public MultiplexServerInvoker(InvokerLocator locatorMap configuration)
    {
       super(locatorconfiguration);
 //      virtualServerInvokers = Collections.synchronizedMap(new HashMap());
        = new HashMap();
    }


   
Create a new MultiplexServerInvoker.
 
    protected MultiplexServerInvoker(InvokerLocator locatorMap configuration,
                                     List serverSocketsSocket socket,
                                     Map virtualServerInvokers)
    {
       super(locatorconfiguration);
       this. = serverSockets;
        = (ServerSocketserverSockets.get(0);
        = socket;
       this. = virtualServerInvokers;
        = true;
        = false;
       
       try
       {
          getParameters();
       }
       catch (Exception e)
       {
          .error(e);
       }
    }
   

   
Each implementation of the remote client invoker should have a default data type that is uses in the case it is not specified in the invoker locator uri.
 
    protected String getDefaultDataType()
    {
       return .;
    }
 
    //TODO: -TME Need to check on synchronization after initial hook up
    public void start() throws IOException
    { 
       if ()
          finishStart();
    }
    
    
    public void run()
    {
       if()
       {
          .trace("Started execution of method run");
       }
       ServerSocketRefresh thread=new ServerSocketRefresh();
       thread.setDaemon(true);
       thread.start();
       
       try
       {
          while()
          {
             try
             {
                if()
                {
                   .trace("Socket is going to be accepted");
                }
                thread.release(); //goes on if serversocket refresh is completed
                Socket socket = .accept();
                if()
                {
                   .trace("Accepted: " + socket);
                }
                processInvocation(socket);
             }
             catch (SocketException e)
             {
                if ("Socket is closed".equals(e.getMessage())
                      || "Socket closed".equals(e.getMessage()))
                {
                   .info("socket is closed: stopping thread");
                   // If this invoker was started by a Connector, let the Connector stop it.
                   if (
                      stop();
                   return;
                }
                else if (++ > )
                {
                   .error("maximum accept errors exceeded: stopping thread");
                   // If this invoker was started by a Connector, let the Connector stop it.
                   if ()
                      stop();
                   return;
                }
                else
                {
                   .info(e);
                }
             }
             catch (SocketTimeoutException e)
             {
                if()
                {
                   // If remote MultiplexClientInvoker and optional callback MultiplexServerInvoker
                   // have shutdown, it's safe to stop.
                   if ( != null && ((VirtualSocket)).hasReceivedDisconnectMessage())
                   {
                      .info("Client has closed: stopping thread");
                      // If this invoker was started by a Connector, let the Connector stop it.
                      if ()
                         stop();
                      return;
                   }
                }
             }
             catch (javax.net.ssl.SSLHandshakeException e)
             {
                .info("SSLHandshakeException"e);
             }
             catch(Throwable ex)
             {
                if()
                {
                   .error("Failed to accept socket connection"ex);
                   if (++ > )
                   {
                      .error("maximum accept errors exceeded: stopping");
                      // If this invoker was started by a Connector, let the Connector stop it.
                      if ()
                         stop();
                      return;
                   }
                }
                else
                {
                   .info(ex);
                }
             }
          }
       }
       finally
       {
          thread.interrupt();
       }
    }
    
    
    public boolean isSafeToShutdown()
    {
    }
    
    
    public void notifyDisconnected(VirtualSocket virtualSocket)
    {
       if (virtualSocket != )
       {
          .error("notified about disconnection of unrecognized virtual socket");
          return;
       }
       
       .debug("remote peer socket has closed: stopping");
       stop();
    }
    
    
    public void stop()
    {
       // If running == false, super.stop() will not call cleanup().
       // However, MultiplexServerInvoker could have stuff to clean up
       // (socket group information) even if it didn't start.
       if (!)
          cleanup();
     
       super.stop();
    }
    
    
    public String toString()
    {
       if ()
       {
          if (vss != null)
             return "MultiplexServerInvoker[virtual:"
                + vss.getInetAddress() + ":" + vss.getLocalPort()
                + "->"
                + vss.getRemoteAddress() + ":" + vss.getRemotePort()
                + "]";
          else
             return "MultiplexServerInvoker[virtual]";
       }
       else
          if ( != null)
             return "MultiplexServerInvoker[master:"
                + .getInetAddress() + ":" + .getLocalPort()
                + "]";
          else
             return "MultiplexServerInvoker[master]";
    }
    
    
    protected void setup() throws Exception
    {
        = this.getLocator().getPort();
       super.setup();
       getParameters();
       setBindingInfo();
       
 //      socketFactory = createSocketFactory(configuration);
 //      if (socketFactory != null)
 //         configuration.put(Multiplex.SOCKET_FACTORY, socketFactory);
       
       if (!.isEmpty())
       {
          if ()
          {
             try
             {
                configureSocketGroupParameters();
             }
             catch (IOException e)
             {
                .error("error configuring socket group parameters"e);
                cleanup();
                throw e;
             }
          }
       }
    }
   
   
   
Finishes start up process when suitable bind and connect information is available. For more information, see the Multiplex subsystem documentation at labs.jboss.org.
 
    protected void finishStart() throws IOException
    {
       .debug("entering finishStart()");
       
       if (isStarted())
          return;
       
       if ( != null &&  == null)
       {
          InetAddress connectAddress = .getConnectAddress();
          int connectPort = .getConnectPort();
           = new InetSocketAddress(connectAddressconnectPort);
       }
       
       if ( != null &&  == null)
       {
          String connectHost = .getConnectAddress().getHostName();
          int connectPort = .getConnectPort();
           = new AddressPair(connectHostconnectPort);
       }
       
       try
       {
          super.start();
       }
       catch(IOException e)
       {
          .error("Error starting MultiplexServerInvoker."e);
          cleanup();
       }
       
       if ()
          .debug("MultiplexServerInvoker started.");
      }
   
   
   
   
Called by MultiplexClientInvoker.createSocket() when it finds connection is broken and binds virtual socket group to new bind port.

Parameters:
bindPort
 
    protected void resetLocator(int bindPort)
    {
       this. = bindPort;
       final InvokerLocator newLocator = new InvokerLocator(.getProtocol(),
                                                            .getHost(),
                                                            bindPort,
                                                            .getPath(),
                                                            .getParameters());
       
       AccessController.doPrivilegednew PrivilegedAction()
       {
          public Object run()
          {
             InvokerRegistry.updateServerInvokerLocator(newLocator);
             return null;
          }
       });
       
        = newLocator;
    }
    
    
    protected void configureSocketGroupParameters(Map parametersthrows IOException
    {
       .debug("entering configureSocketGroupParameters()");
       .debug();
 
       synchronized (SocketGroupInfo.class)
       {
          if ( != null)
          {
             if ( != null)
             {
                rule1();
                return;
             }
          }
          
          if ( != null && !this.)
             throw new IOException("multiplexConnectHost != null and multiplexConnectPort is not set");
          
          if ( == null && this.)
             throw new IOException("multiplexConnectHost == null and multiplexConnectPort is set");
          
          // server rule 2.
          if ( != null)
          {
             rule2();
             return;
          }
          
          // server rule 3.
          if ( != null)
          {
             rule3();
             return;
          }
          
          // server rule 4.
          rule4();
       }
    }
    
    
    protected static void createPrimingSocket(SocketGroupInfo socketGroupInfo,
                                              String connectHostint connectPort,
                                              Map configurationint timeout)
    throws IOException
    {
       createPrimingSocket(socketGroupInfoconnectHostconnectPortnull, -1, configurationtimeout);
    }
    
    
    protected static void createPrimingSocket(SocketGroupInfo socketGroupInfo,
                                              String connectHostint connectPort,
                                              InetAddress bindAddressint bindPort,
                                              Map configurationint timeout)
    throws IOException
    {  
       .debug("entering createPrimingSocket()");
       
       boolean needed = true;
       InetSocketAddress csa = new InetSocketAddress(connectHostconnectPort);
       InetSocketAddress bsa = null;
       
       if (bindAddress != null)
       {
          bsa = new InetSocketAddress(bindAddressbindPort);
          needed = !MultiplexingManager.checkForShareableManagerByAddressPair(bsacsa);
       }
       else
       {
          needed = !MultiplexingManager.checkForShareableManager(csa);
       }
       
       if (socketGroupInfo != null)
          socketGroupInfo.setPrimingSocketNeeded(needed);
       
       if (!needed)
       {
          .debug("priming socket is not necessary");
          return;
       }
       
       // If the configuration Map has an SSL HandshakeCompletedListener, we register to
       // receive the HandshakeCompletedEvent with a HandshakeRepeater and, if the event
       // arrives within 60 seconds, we pass it on to the configured listener.  Otherwise,
       // HandshakeRepeater.waitForHandshake() will throw an SSLException. 
       Object obj = configuration.get(.);
       HandshakeCompletedListener externalListener = null;
       HandshakeRepeater internalListener = null;
       if (obj != null && obj instanceof HandshakeCompletedListener)
       {
          externalListener = (HandshakeCompletedListenerobj;
          internalListener = new HandshakeRepeater(new InternalHandshakeListener());
          configuration.put(.internalListener);
       }
       
       VirtualSocket socket = new VirtualSocket(configuration);
       
       if (bindAddress != null)
          socket.connect(csabsatimeout);
       else
          socket.connect(csatimeout);
       
       MultiplexingManager manager = socket.getManager();
       
       if (externalListener != null)
       {
          if (manager.getHandshakeCompletedEvent() != null)
          {
             externalListener.handshakeCompleted(manager.getHandshakeCompletedEvent());
          }
          else
          {
             internalListener.waitForHandshake();
             externalListener.handshakeCompleted();
          }
       }
       
       if (!manager.waitForRemoteServerSocketRegistered())
          throw new IOException("error waiting for remote server socket to be registered");
       
       if (socketGroupInfo != null)
          socketGroupInfo.setPrimingSocket(socket);
       
       .debug("created priming socket: " + socket.getLocalSocketId());
    }
    
 
    protected String getThreadName(int i)
    {
       String virtualTag =  ? "v" : "m";
       return "MultiplexServerInvoker#" + i + virtualTag + "-" + .toString();
    }
 
 
    protected void processInvocation(Socket socketthrows Exception
    {
       if ()
          super.processInvocation(socket);
       else
       {
          .debug("creating VSS");
          ServerSocket ss = new VirtualServerSocket((VirtualSocketsocket);
          ss.setSoTimeout(getTimeout());
          List serverSockets = new ArrayList();
          serverSockets.add(ss);
          MultiplexServerInvoker si = new MultiplexServerInvoker(serverSocketssocket);
          si.hasMaster = true;
          si.clientCallbackListener = ;
          si.handlers = ;
          si.setMBeanServer(this.getMBeanServer());
          si.setServerSocketFactory(this.getServerSocketFactory());
          si.setSocketFactory(this.);
          synchronized ()
          {
             .put(socket.getRemoteSocketAddress(), si);
          }
          si.connectionNotifier = ;
          si.create();
          si.start();
          .debug("created virtual MultiplexServerInvoker: " + si);
       }
    }
 
   
    protected void cleanup()
    {  
       // If running == false, SocketServerInvoker doesn't want to call cleanup().
       if ()
       {
          super.cleanup();
       }
       
       // If the Finalizer thread gets here after clean up has occurred, return.
       if ()
          return;
       
        = true;
       
       if ()
       {
          if ( != null)
          {
             .debug("connect priming != null");
             // If !virtualServerInvokers.containsKey(connectPrimingSocket.getRemoteSocketAddress()),
             // the master MultiplexServerInvoker might be iterating through virtualServerInvokers
             // and shutting them down.  This test avoids a NullPointerException.
             Object key = .getRemoteSocketAddress();
             synchronized ()
             {
                if (.containsKey(key))
                   .remove(key);
             }
             
             try
             {
                .debug("MultiplexServerInvoker: closing connect priming socket");
                .close();
             }
             catch (IOException e)
             {
                .error("Error closing connect priming socket during cleanup upon stopping"e);
             }
          }
          else
          {
             .debug("connect priming socket == null");
          }
          
          // Remove all callback handlers (if any ServerInvocationHandlers are registered).
          Iterator it = .values().iterator();
          
          if (it.hasNext())
          {
             .debug("removing callback handlers");
             ServerInvocationHandler defaultHandler = (ServerInvocationHandlerit.next();
             ServerInvocationHandler handler = null;
             ServerInvokerCallbackHandler callbackHandler = null;
             it = .values().iterator();
             
             while (it.hasNext())
             {
                callbackHandler = (ServerInvokerCallbackHandlerit.next();
                String subsystem = callbackHandler.getSubsystem();
                
                if (subsystem == null)
                   handler = defaultHandler;
                else
                   handler = (ServerInvocationHandler.get(subsystem.toUpperCase());
                
                handler.removeListener(callbackHandler);
             }
          }
       }
       else
       {
 //         Iterator it = virtualServerInvokers.values().iterator();
          Iterator it = null;
          synchronized ()
          {
             it = new HashMap().values().iterator();
          }
          
          while (it.hasNext())
          {
             ServerInvoker serverInvoker = ((ServerInvokerit.next());
             it.remove();
             serverInvoker.stop();
          }
       }
       
       if ( != null)
       {
          synchronized (MultiplexServerInvoker.SocketGroupInfo.class)
          {
             .removeServerInvoker(this);
             VirtualSocket ps = null;
             
             if (.getClientInvokers().isEmpty())
             {
                .debug("invoker group shutting down: " + .getSocketGroupId());
                
                if ((ps = .getPrimingSocket()) != null)
                {
                   // When the remote virtual MultiplexServerInvoker learns that the
                   // priming socket has closed, it will close its VirtualServerSocket,
                   // rendering unshareable the MultiplexingManager that underlies this
                   // socket group.  We mark it as unshareable immediately so that it will
                   // not be reused by any other socket group.
                   ps.getManager().unregisterShareable();
                   
                   .debug("MultiplexServerInvoker: closing bind priming socket");
                   try
                   {
                      ps.close();
                   }
                   catch (IOException e)
                   {
                      .error("Error closing bind priming socket during cleanup upon stopping"e);
                   }
                }
                
                 = .getSocketGroupId();
                .debug("serverMultiplexId: " + );
                if ( != null)
                {
                   getSocketGroupMap().remove();
                   .debug("removed serverMultiplexId: " + );
                   .debug("socketGroupInfo: " + getSocketGroupMap().get());
                }
                
                // addressPair is set in finishStart().
                if ( != null)
                {
                   getAddressPairMap().remove();
                }
             }
          }
       }
    }


In creating the server socket, createServerSocket() determines whether multiplexing will be supported by this ServerInvoker. The determination is made according to the presence or absence of certain parameters in the ServerInvoker's locator. In particular, a VirtualServerSocket, which supports multiplexing, needs to connect to a remote MasterServerSocket before it can begin to accept connection requests. In order to know which MasterServerSocket to connect to, it looks for parameters "connectHost" and "connectPort" in the locator. The presence of these parameters indicates that a VirtualServerSocket should be created, and their absence indicates that a MasterServerSocket, which does not support multiplexing, should be created.

Parameters:
bindPort
backlog
bindAddress
Returns:
Throws:
IOException
 
    protected ServerSocket createServerSocket(int bindPortint backlogInetAddress bindAddressthrows IOException
 //   private ServerSocket createServerSocket() throws IOException
    {
       // The following commented code represents an attempt to make an automatic determination as to whether
       // a VirtualServerSocket should be created.  The idea is to see if a ClientInvoker already
       // exists on the local port to which the new server socket wants to bind.  The existence of such a
       // ClientInvoker would indicate that multiplexing is desired.  However, it appears that a ClientInvoker
       // has no control over which local port(s) it uses.
 
       //    if (InvokerRegistry.isClientInvokerRegistered(getLocator()))
       //    {
       //       try
       //       {
       //          Invoker clientInvoker = InvokerRegistry.createClientInvoker(getLocator());
       //          InvokerLocator connectLocator = clientInvoker.getLocator();
       //          InetSocketAddress connectSocketAddress = new InetSocketAddress(connectLocator.getHost(), connectLocator.getPort());
       //          InetSocketAddress bindSocketAddress = new InetSocketAddress(bindAddress, serverBindPort);
       //          svrSocket = new VirtualServerSocket(connectSocketAddress, bindSocketAddress);
       //       }
       //       catch (Exception e)
       //       {
       //          throw new IOException(e.getMessage());
       //       }
       //    }
       
       // If this is a virtual MultiplexServerInvoker created by a master MultiplexServerInvoker,
       // then the server socket has already been created.
       if ( != null)
          return ;
       
       ServerSocket svrSocket = null;
 
       if ()
       {
          InetSocketAddress bindSocketAddress = new InetSocketAddress(bindAddressthis.);
          svrSocket = new VirtualServerSocket(bindSocketAddressgetTimeout(), );
          svrSocket.setSoTimeout(getTimeout());
          
          if ( != null)
             .setPrimingSocketNeeded(false);
       }
       else
       {
 //         svrSocket = new MasterServerSocket(getServerSocketFactory(), bindPort, backlog, bindAddress);
          ServerSocketFactory ssf = getServerSocketFactory();
          if (ssf != null && !ssf.getClass().equals(ServerSocketFactory.getDefault().getClass()))
          {
             .put(.ssf);
          }
          svrSocket = new MasterServerSocket(bindPortbacklogbindAddress);
          svrSocket.setSoTimeout(getTimeout());
       }
 
       .debug("Created " + svrSocket.getClass() + ": " + svrSocket);
       return svrSocket;
    }
 
 
    protected void rule1() throws IOException
    {
       .debug("server rule 1");
       
       // If we get here, it's because a MultiplexClientInvoker created a SocketGroupInfo with matching
       // group id.  We want to make sure that it didn't get a bind address or bind port different
       // than the ones passed in through the parameters map.
       InetAddress socketGroupBindAddress = .getBindAddress();
       int socketGroupBindPort = .getBindPort();
       
       if (socketGroupBindAddress != null && !socketGroupBindAddress.equals())
       {
          String message = "socket group bind address (" + socketGroupBindAddress + 
                           ") does not match bind address (" +  + ")";
          .error(message);
           = null;  // We don't belong to this group.
          throw new IOException(message);
       }
       
       if (socketGroupBindPort > 0 &&  > 0 && socketGroupBindPort != )
       {
          String message = "socket group bind port (" + socketGroupBindPort + 
                           ") does not match bind port (" +  + ")";
          .error(message);
           = null;  // We don't belong to this group.
          throw new IOException(message);
       }
       
       if ( <= 0)
       {
          if (socketGroupBindPort > 0)
              = socketGroupBindPort;
          else
          {
              = PortUtil.findFreePort();
             socketGroupBindPort = ;
          }
          
          // re-write locator since the port is different
          final InvokerLocator newLocator = new InvokerLocator(.getProtocol(), .getHost(), .getPath(), .getParameters());
 
          // need to update the locator key used in the invoker registry
          AccessController.doPrivilegednew PrivilegedAction()
          {
             public Object run()
             {
                InvokerRegistry.updateServerInvokerLocator(newLocator);
                return null;
             }
          });
          
          this. = newLocator;
       }
       
        = true;
       InetAddress connectAddress = .getConnectAddress();
       int connectPort = .getConnectPort();
        = new InetSocketAddress(connectAddressconnectPort);
       
       while (it.hasNext())
       {
          ((MultiplexClientInvokerit.next()).finishStart();
       }
       
        = true;
 
       if (.getPrimingSocket() == null)
       {
          if ( != null)
          
          createPrimingSocket(connectAddress.getHostName(), connectPort,
                              getTimeout());
       }
 
       // We got socketGroupInfo by socketGroupId.  Make sure it is also stored by AddressPair.
       String connectHost = connectAddress.getHostName();
        = new AddressPair(connectHostconnectPort);
    }
    
    
    protected void rule2(String connectHostint connectPort)
    throws IOException
    {
       .debug("server rule 2");
        = true;
 
        = new InetSocketAddress(connectHostconnectPort);    
        = new AddressPair(connectHostconnectPort);
       
       // If socketGroupInfo exists, it's because it was created, along with a priming socket (if necessary),
       // by a MultiplexClientInvoker.
       if ( != null)
       {
          // We got socketGroupInfo by AddressPair.  Make sure it is stored by socketGroupId, if we have one.
          if ( != null)
          {
             String socketGroupSocketGroupId = .getSocketGroupId();
             
             if (socketGroupSocketGroupId != null && socketGroupSocketGroupId != )
             {
               String message = "socket group multiplexId (" + socketGroupSocketGroupId + 
                                ") does not match multiplexId (" +  + ")";
               .error(message);
                = null// Assume we weren't meant to join this group.
               throw new IOException(message);
            }
               
            if (socketGroupSocketGroupId == null)
            {
               getSocketGroupMap().put();
            }
         }
         
         .setServerInvoker(this);
          = true;
         return;
      }
      
       = new SocketGroupInfo();
      
      // Set connectAddress and connectPort to be able to test for inconsistencies with connect address
      // and connect port determined by companion MultiplexClientInvoker.
      InetAddress connectAddress = InetAddress.getByName(connectHost);
      .setConnectAddress(connectAddress);
      .setConnectPort(connectPort);
      
      if ( != null)
      
      createPrimingSocket(connectHostconnectPort,
                          getTimeout());
      
      if ( != null)
      {
      }
      
       = true;
   }
   
   
   protected void rule3() throws IOException
   {
      .debug("server rule 3");
       = new SocketGroupInfo();
       = true;
       = false;
   }
   
   
   protected void rule4()
   {
      .debug("server rule 4");
       = false;
       = true;
   }
   
   
   protected void refreshServerSocket() throws IOException
   {
      super.refreshServerSocket();
   }
   
   
Returns ServerSocket used to accept invocation requests. It is added to facilitate unit tests.

Returns:
ServerSocket used to accept invocation requests.
   {
      return ;
   }
   
   
Provides access to a virtual MultiplexServerInvoker in a master MultiplexServerInvoker's invoker farm.
   {
      synchronized ()
      {
         return (MultiplexServerInvoker.get(address);
      }
   }
   
   
Provides access to all virtual MultiplexServerInvokers in a master MultiplexServerInvoker's invoker farm.
   {
      synchronized ()
      {
         return .values();
      }
   }
   
   protected void setBindingInfo() throws IOException
   {
      String originalUri = getLocator().getOriginalURI();
      String pastProtocol = originalUri.substring(originalUri.indexOf("://") + 3);
      int colon = pastProtocol.indexOf(":");
      int slash = pastProtocol.indexOf("/");
      String originalHost = null;
      int originalPort = 0;
      if(colon != -1)
      {
         originalHost = pastProtocol.substring(0, colon).trim();
   &