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;
  
  import  org.jboss.logging.Logger;
  import  org.jboss.util.id.GUID;
  import  org.jboss.util.threadpool.BasicThreadPool;
  import  org.jboss.util.threadpool.BlockingMode;
  import  org.jboss.util.threadpool.ThreadPool;
  
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.Timer;
Client is a convience class for invoking remote methods for a given subsystem. It is intended to be the main user interface for making remote invocation on the client side.

Author(s):
Jeff Haynie
Tom Elrod
Ovidiu Feodorov
Version:
$Revision: 3928 $
  
  public class Client implements Externalizable
  {
     // Constants ------------------------------------------------------------------------------------
  
   
Key to be used to determine if invocation is to be oneway (async).
  
     public static final String ONEWAY_FLAG = "oneway";

   
Key to be used when tracking callback listeners.
  
     public static final String LISTENER_ID_KEY = "listenerId";

   
Specifies the default number of work threads in the pool for executing one way invocations on the client. Value is 10.
  
     public static final int MAX_NUM_ONEWAY_THREADS_DEFAULT = 10;

   
The key to use for the metadata Map passed when making a invoke() call and wish for the invocation payload to be sent as is and not wrapped within a remoting invocation request object. This should be used when want to make direct calls on systems outside of remoting (e.g. making a http POST request to a web service).
 
    public static final String RAW = "rawPayload";

   
Key for the configuration map passed to the Client constructor to indicate that client should make initial request to establish lease with server. The value for this should be either a String that java.lang.Boolean can evaluate or a java.lang.Boolean. Client leasing is turned off by default, so would need to use this property to turn client leasing on.
 
    public static final String ENABLE_LEASE = "enableLease";

   
Key for the configuration map passed to the Client constructor providing a ssl javax.net.ssl.HandshakeCompletedListener implementation, which will be called on when ssl handshake completed with server.
 
    public static final String HANDSHAKE_COMPLETED_LISTENER = "handshakeCompletedListener";

   
Key for the configuration when adding a callback handler and internal callback server connector is created. The value should be the transport protocol to be used. By default will use the same protocol as being used by this client (e.g. http, socket, rmi, multiplex, etc.)
 
    public static final String CALLBACK_SERVER_PROTOCOL = "callbackServerProtocol";

   
Key for the configuration when adding a callback handler and internal callback server connector is created. The value should be the host name to be used. By default will use the result of calling InetAddress.getLocalHost().getHostAddress().
 
    public static final String CALLBACK_SERVER_HOST = "callbackServerHost";

   
Key for the configuration when adding a callback handler and internal callback server connector is created. The value should be the port to be used. By default will find a random unused port.
 
    public static final String CALLBACK_SERVER_PORT = "callbackServerPort";

   
Key for the configuration map that determines the threadpool size for asynchrouous invocations.
 
    public static final String MAX_NUM_ONEWAY_THREADS = "maxNumThreadsOneway";

   
Key for the configuration map that determines the queue size for waiting asynchronous invocations.
 
    public static final String MAX_ONEWAY_THREAD_POOL_QUEUE_SIZE = "maxOnewayThreadPoolQueueSize";

   
Default timeout period for network i/o in disconnect() and removeListener(). -1 indicates that no special per invocation timeout will be set.
 
    public static final int DEFAULT_DISCONNECT_TIMEOUT = -1;
   
   
Key for setting delay before client invoker is destroyed by disconnect().
 
    public static final String INVOKER_DESTRUCTION_DELAY = "invokerDestructionDelay";
    
    public static final String THROW_CALLBACK_EXCEPTION = "throwCallbackException";
 
    private static final Logger log = Logger.getLogger(Client.class);
 
    private static final long serialVersionUID = 5679279425009837934L;
 
    // Static ---------------------------------------------------------------------------------------
 
    // Attributes -----------------------------------------------------------------------------------
 
   
Indicated the max number of threads used within oneway thread pool.
 
    private int maxOnewayThreadPoolQueueSize = -1;
    private ClientInvoker invoker;
    private ClassLoader classloader;
    private String subsystem;
    private String sessionId;
    private Object onewayThreadPoolLock = new Object();
    private ThreadPool onewayThreadPool;
    private InvokerLocator locator;
 
    private ConnectionValidator connectionValidator = null;
    private Map configuration = new HashMap();
 
    private Map callbackConnectors = new HashMap();
    private Map callbackPollers = new HashMap();
 
    private Map listeners = new HashMap();
 
    private SocketFactory socketFactory;
 
 
    private boolean connected = false;
    
    private int invokerDestructionDelay = 0;
    private Object invokerDestructionTimerLock = new Object();
 
    // Constructors ---------------------------------------------------------------------------------
 
   
PLEASE DO NOT USE THIS CONSTRUCTOR OR YOUR COMPUTER WILL BURST INTO FLAMES!!! It is only here so can externalize object and will provide a dead object if invoker is not explicitly set. Please use other contructors provided.
 
    public Client()
    {
    }

   
Constructs a remoting client with intended target server specified via the locator, without specifing a remote subsystem or including any metadata. Same as calling Client(locator, null, null).
 
    public Client(InvokerLocator locatorthrows Exception
    {
       this(locatornullnull);
    }

   
Constructs a remoting client with intended target server specified via the locator and configuration metadata. The metadata supplied will be used when creating client invoker (in the case specific data is required) and also for passing along additional data to connection listeners on the server side in the case that the client fails, will be able to use this extra information when notified.
 
    public Client(InvokerLocator locatorMap configurationthrows Exception
    {
       this(locatornullconfiguration);
    }

   
Constructs a remoting client with intended target server specified via the locator and intended subsystem on server for invocations to be routed to.
 
    public Client(InvokerLocator locatorString subsystemthrows Exception
    {
       this(locatorsubsystemnull);
    }

   
Constructs a remoting client with intended target server specified via the locator, intended subsystem on the server for invocations to be routed to, and configuration metadata. The metadata supplied will be used when creating client invoker (in the case specific data is required) and also for passing along additional data to connection listeners on the server side in the case that the client fails, will be able to use this extra information when notified.
 
    public Client(InvokerLocator locatorString subsystemMap configurationthrows Exception
    {
       this(nulllocatorsubsystemconfiguration);
    }

   
Constructs a remoting client with intended target server specified via the locator, intended subsystem on the server for invocations to be routed to, and configuration metadata. The metadata supplied will be used when creating client invoker (in the case specific data is required) and also for passing along additional data to connection listeners on the server side in the case that the client fails, will be able to use this extra information when notified (which will happen when connect() method is called.

Deprecated:
This constructor should not be used any more as will no longer take into account the classloader specified as a parameter.
Parameters:
cl - the classloader that should be used by remoting.
 
    public Client(ClassLoader clInvokerLocator locatorString subsystemMap configuration)
          throws Exception
    {
       if (cl == null)
       {
          this. = (ClassLoader) AccessController.doPrivilegednew PrivilegedAction()
          {
             public Object run()
             {
                return Thread.currentThread().getContextClassLoader();
             }
          });
       }
       else
       {
          this. = cl;
       }
       this. = locator;
       this. = subsystem == null ? null : subsystem.toUpperCase();
       if (configuration != null)
       {
          this. = new HashMap(configuration);
       }
       this. = new GUID().toString();
       processParameters();
    }

   
Constructs a remoting client with intended target server specified via the locator and intended subsystem on server for invocations to be routed to.

Deprecated:
This constructor should not be used any more as will no longer take into account the classloader specified as a parameter.
 
    public Client(ClassLoader clClientInvoker invokerString subsystemthrows Exception
    {
       this. = cl;
       this. = subsystem == null ? null : subsystem.toUpperCase();
       this. = invoker;
       this. = new GUID().toString();
    }
 
    // Externalizable implementation ----------------------------------------------------------------
 
    public void readExternal(ObjectInput inthrows IOExceptionClassNotFoundException
    {
       int version = in.readInt();
 
       switch (version)
       {
          case .:
          case .:
          {
             this. = (InvokerLocatorin.readObject();
             this. = (Stringin.readObject();
             this. = (Mapin.readObject();
             boolean wasConnected = in.readBoolean();
 
             this. = (ClassLoader) AccessController.doPrivilegednew PrivilegedAction()
             {
                public Object run()
                {
                   return Thread.currentThread().getContextClassLoader();
                }
             });
             
             try
             {
                this. = InvokerRegistry.createClientInvoker();
                if(wasConnected)
                {
                   connect();
                }
             }
             catch (Exception e)
             {
                .debug(e);
                throw new IOException(e.getMessage());
             }
 
             break;
          }
          default:
             throw new StreamCorruptedException("Unkown version seen: " + version);
       }
    }
 
    public void writeExternal(ObjectOutput outthrows IOException
    {
       out.writeInt(Version.getDefaultVersion());
       out.writeObject( != null ? .getLocator() : );
       out.writeObject();
       out.writeObject();
       out.writeBoolean(isConnected());
       out.flush();
    }
 
    // Public ---------------------------------------------------------------------------------------
 
   
Adds a connection listener that will be notified if/when the connection to the server fails while the client is idle (no calls being made). The default behavior is to ping for connection every two seconds.
 
    public void addConnectionListener(ConnectionListener listener)
    {
    }

   
Adds a connection listener that will be notified if/when the connection to the server fails while the client is idle (no calls being made). The current behavior is to ping the server periodically. The time period is defined by the pingPeriod (which should be in milliseconds).
 
    public void addConnectionListener(ConnectionListener listenerint pingPeriod)
    {
       HashMap metadata = new HashMap();
       metadata.put(., Integer.toString(pingPeriod));
       addConnectionListener(listenermetadata);
    }
   
   
Adds a connection listener that will be notified if/when the connection to the server fails while the client is idle (no calls being made). The current behavior is to ping the server periodically. Various parameters may be specified in metadata.

See also:
org.jboss.remoting.ConnectionValidator
 
    public void addConnectionListener(ConnectionListener listenerMap metadata)
    {
       if ( == null)
       {
          throw new RuntimeException("Can not add connection listener to remoting client " +
                                     "until client has been connected.");
       }
       else
       {
          // if local, then no point in having connection listener
          if ( instanceof LocalClientInvoker)
          {
             return;
          }
       }
 
       if ( == null)
       {
           = new ConnectionValidator(thismetadata);
       }
    }

   
Removes specified connection listener. Will return true if it has already been registered, false otherwise.
 
    public boolean removeConnectionListener(ConnectionListener listener)
    {
       if ( == null)
       {
          return false;
       }
       return .removeConnectionListener(listener);
    }

   
This will set the session id used when making invocations on server invokers. There is a default unique id automatically generated for each Client instance, so unless you have a good reason to set this, do not set this.
 
    public void setSessionId(String sessionId)
    {
       this. = sessionId;
    }

   
Gets the configuration map passed when constructing this object.
 
    public Map getConfiguration()
    {
       return ;
    }

   
Gets the session id used when making invocations on server invokers. This is the id that will be used for tracking client connections on the server side, to include client failures that are sent to connection listeners on the server side.
 
    public String getSessionId()
    {
       return this.;
    }

   
Indicates if the underlying transport has been connected to the target server.
 
    public boolean isConnected()
    {
       return ;
    }

   
Will cause the underlying transport to make connection to the target server. This is important for any stateful transports, like socket or multiplex. This is also when a client lease with the server is started.
 
    public void connect() throws Exception
    {
       if (isConnected())
          return;
 
       if ( == null)
       {
          throw new IllegalStateException("Cannot connect a client with a null locator");
       }
 
       if ( == null)
       {
          if ( != null)
          {
             this. = null;
          }
           = InvokerRegistry.createClientInvoker();
       }
 
       connect();
 
        = true;
    }

   
Disconnects the underlying transport from the target server. Also notifies the target server to terminate client lease. Is important that this method is called when no longer using the remoting client. Otherwise resource will not be cleaned up and if the target server requires a lease, it will be maintained in the background.
 
    public void disconnect()
    {
       if ( != null)
       {
          // this is a noop if no lease is active
 
          if ( != null)
          {
             .stop();
              = null;
          }
 
          // Need to remove myself from registry so will not keep reference to me since I am of no
          // use now. Will have to create a new one.
 
          if ( > 0)
          {
             synchronized ()
             {
                InvokerDestructionTimerTask task = new InvokerDestructionTimerTask();
                if ( == null)
                {
                    = new Timer(true);
                }
 
                try
                {
                   .schedule(task);
                }
                catch (IllegalStateException e)
                {
                   .debug("Unable to schedule InvokerDestructionTimerTask on existing Timer"e);
                    = new Timer(true);
                   .schedule(task);
                }
                
                .trace(this + " scheduled destruction of " + );
             }
          }
          else
          {
             InvokerRegistry.destroyClientInvoker(.getLocator(), );
          }
          
           = null;
       }
 
        = false;
    }

   
Get the client invoker (transport implementation).
 
    public ClientInvoker getInvoker()
    {
       return ;
    }

   
Set the client invoker (transport implementation).
 
    public void setInvoker(ClientInvoker invoker)
    {
       this. = invoker;
    }

   
Gets the subsystem being used when routing invocation request on the server side.
 
    public String getSubsystem()
    {
       return ;
    }

   
Sets the subsystem being used when routing invocation requests on the server side. Specifing a subsystem is only needed when server has multiple handlers registered (which will each have their own associated subsystem).
 
    public void setSubsystem(String subsystem)
    {
       this. = subsystem;
    }

   
Invokes the server invoker handler with the payload parameter passed. Same as calling invoke(param, null);
 
    public Object invoke(Object paramthrows Throwable
    {
       return invoke(paramnull);
    }

   
Invoke the method remotely.

Parameters:
param - payload for the server invoker handler.
metadata - any extra metadata that may be needed by the transport (i.e. GET or POST if using http invoker) or if need to pass along extra data to the server invoker handler.
 
    public Object invoke(Object paramMap metadatathrows Throwable
    {
       return invoke(parammetadatanull);
    }

   
Will invoke a oneway call to server without a return object. This should be used when not expecting a return value from the server and wish to achieve higher performance, since the client will not wait for a return. This is done one of two ways. The first is to pass true as the clientSide param. This will cause the execution of the remote call to be excuted in a new thread on the client side and will return the calling thread before making call to server side.

The second, is to pass false as the clientSide param. This will allow the current calling thread to make the call to the remote server, at which point, the server side processing of the thread will be executed on the remote server in a new executing thread.

NOTE: The treatment of server side oneway invocations may vary with the transport. The client side transport is not required to wait for a reply from the server.

 
    public void invokeOneway(final Object paramfinal Map sendPayloadboolean clientSide
       throws Throwable
    {
       final Map internalSendPayload = sendPayload == null ? new HashMap() : sendPayload;
       internalSendPayload.put("true");
 
       if (clientSide)
       {
          ThreadPool threadPool = getOnewayThreadPool();
          Runnable onewayRun = new Runnable()
          {
             public void run()
             {
                try
                {
                   invoke(paraminternalSendPayload);
                }
                catch (Throwable e)
                {
                   // throw away exception since can't get it back to original caller
                   .error("Error executing client oneway invocation request: " + parame);
                }
             }
          };
          threadPool.run(onewayRun);
       }
       else
       {
          OnewayInvocation invocation = new OnewayInvocation(param);
          invoke(invocationinternalSendPayload);
       }
    }

   
Returns the callback Connectors with which callbackHandler is registered.
 
    public Set getCallbackConnectors(InvokerCallbackHandler callbackHandler)
    {
       return (Set.get(callbackHandler);
    }

   
Gets the timeout used for network i/o in disconnect() and removeListener().
 
    public int getDisconnectTimeout()
    {
       return ;
    }

   
Sets the timeout used for network i/o in disconnect() and removeListener().
 
    public void setDisconnectTimeout(int disconnectTimeout)
    {
       this. = disconnectTimeout;
    }

   
Sets the maximum queue size to use within client pool for one way invocations on the client side (meaning oneway invocation is handled by thread in this pool and user's call returns immediately). Default value is MAX_NUM_ONEWAY_THREADS.
 
    public void setMaxOnewayThreadPoolQueueSize(int maxOnewayThreadPoolQueueSize)
    {
       this. = maxOnewayThreadPoolQueueSize;
    }

   
Gets the maximum queue size to use within client pool for one way invocations on the client side (meaning oneway invocation is handled by thread in this pool and user's call returns immediately). Default value is MAX_NUM_ONEWAY_THREADS.
 
    public int getMaxOnewayThreadPoolQueueSize()
    {
       return this.;
    }

   
Sets the maximum number of threads to use within client pool for one way invocations on the client side (meaning oneway invocation is handled by thread in this pool and user's call returns immediately). Default value is MAX_NUM_ONEWAY_THREADS.
 
    public void setMaxNumberOfThreads(int numOfThreads)
    {
       this. = numOfThreads;
    }

   
Gets the maximum number of threads to use within client pool for one way invocations on the client side (meaning oneway invocation is handled by thread in this pool and user's call returns immediately). Default value is MAX_NUM_ONEWAY_THREADS.
 
    public int getMaxNumberOfThreads()
    {
       return this.;
    }

   
Gets the thread pool being used for making one way invocations on the client side. If one has not be specifically set via configuration or call to set it, will always return instance of org.jboss.util.threadpool.BasicThreadPool.
 
    public ThreadPool getOnewayThreadPool()
    {
       synchronized ()
       {
          if ( == null)
          {
             BasicThreadPool pool = new BasicThreadPool("JBossRemoting Client Oneway");
             .debug("created new thread pool: " + pool);
             Object param = .get();
             if (param instanceof String)
             {
                try
                {
                    = Integer.parseInt((Stringparam);
                }
                catch (NumberFormatException  e)
                {
                   .error("maxNumberThreads parameter has invalid format: " + param);
                }
             }
             else if (param != null)
             {
                .error("maxNumberThreads parameter must be a string in integer format: " + param);
             }
 
             param = .get();
 
             if (param instanceof String)
             {
                try
                {
                    = Integer.parseInt((Stringparam);
                }
                catch (NumberFormatException  e)
                {
                   .error("maxOnewayThreadPoolQueueSize parameter has invalid format: " + param);
                }
             }
             else if (param != null)
             {
                .error("maxOnewayThreadPoolQueueSize parameter must be a string in integer format: " + param);
             }
 
             pool.setMaximumPoolSize();
 
             if ( > 0)
             {
                pool.setMaximumQueueSize();
             }
             pool.setBlockingMode(BlockingMode.RUN);
              = pool;
          }
       }
       return ;
    }

   
Sets the thread pool to be used for making one way invocations on the client side.
 
    public void setOnewayThreadPool(ThreadPool pool)
    {
       this. = pool;
    }

   
The socket factory can only be set on the Client before the connect() method has been called. Otherwise, a runtime exception will be thrown.
 
    public void setSocketFactory(SocketFactory socketFactory)
    {
       if(isConnected())
       {
          throw new RuntimeException("Cannot set socket factory on Client after " +
                                     "the connect() method has been called.");
       }
 
       if ( != null)
       {
          .setSocketFactory(socketFactory);
       }
       else
       {
          this. = socketFactory;
       }
    }
 
    {
       if ( != null)
       {
          return .getSocketFactory();
       }
       else
       {
          return ;
       }
    }

   
Same as calling invokeOneway(Object param, Map sendPayload, boolean clientSide) with clientSide param being false and a null sendPayload. Therefore, client thread will not return till it has made remote call.
 
    public void invokeOneway(Object paramthrows Throwable
    {
       invokeOneway(paramnull);
    }

   
Same as calling invokeOneway(Object param, Map sendPayload, boolean clientSide) with clientSide param being false. Therefore, client thread will not return till it has made remote call.
 
    public void invokeOneway(Object paramMap sendPayloadthrows Throwable
    {
       invokeOneway(paramsendPayloadfalse);
    }

   
Adds the specified handler as a callback listener for push (async) callbacks. If the transport is uni-directional (e.g. http), remoting will automatically poll for callbacks from the server and deliver them to the callback handler. If the transport is bi-directional (e.g. multiplex), remoting will automatically create a callback server internally and receive and deliver to callback handler the callbacks as they are generated on the server. The metadata map passed will control configuration for how the callbacks are processed, such as the polling frequency.
 
    public void addListener(InvokerCallbackHandler callbackhandlerMap metadatathrows Throwable
    {
       addListener(callbackhandlermetadatanull);
    }

   
Adds the specified handler as a callback listener for push (async) callbacks. If the transport is uni-directional (e.g. http), remoting will automatically poll for callbacks from the server and deliver them to the callback handler. If the transport is bi-directional (e.g. multiplex), remoting will automatically create a callback server internally and receive and deliver to callback handler the callbacks as they are generated on the server. The metadata map passed will control configuration for how the callbacks are processed, such as the polling frequency.

Parameters:
callbackHandlerObject - this object will be included in the Callback object instance passed to the InvokerCallbackHandler specified.
 
    public void addListener(InvokerCallbackHandler callbackhandlerMap metadata,
                            Object callbackHandlerObjectthrows Throwable
    {
       addListener(callbackhandlermetadatacallbackHandlerObjectfalse);
    }

   
Adds the specific handler as a callback listener for async callbacks. If the transport supports bi-directional calls (meaning server can call back to client over same connection that was established by the client) or if the serverToClient flag is set to true, a callback server will be created internally and the target server will actually send callbacks to the client's internal server. Otherwise, the client will simulate push callbacks by internally polling for callbacks on the server and then deliver them to the callback handler.

Parameters:
serverToClient - if true, will allow server to connect to the client directly (which must be allowed by firewall in front of client unless transport is bi-directional, such as the multiplex transport). If false (and not bi-directional transport), server will not create any new connection to the client.
 
    public void addListener(InvokerCallbackHandler callbackhandlerMap metadata,
                            Object callbackHandlerObjectboolean serverToClientthrows Throwable
    {
       InvokerLocator callbackLocator = null;
 
       if (isConnected())
       {
          if (callbackhandler != null)
          {
             boolean isBidirectional =  instanceof BidirectionalClientInvoker;
 
             if (isBidirectional || serverToClient)
             {
                // setup callback server
                String transport = null;
                String host = null;
                int port = -1;
 
                // look for config values
                if (metadata != null)
                {
                   transport = (Stringmetadata.get();
                   host = (Stringmetadata.get();
                   String sPort = (Stringmetadata.get();
                   if (sPort != null)
                   {
                      try
                      {
                         port = Integer.parseInt(sPort);
                      }
                      catch (NumberFormatException e)
                      {
                         .warn("Could not set the internal callback server port as " +
                                  "configuration value (" + sPort + ") is not a number.");
                      }
                   }
                }
                else
                {
                   metadata = new HashMap();
                }
                if (transport == null)
                {
                   transport = .getLocator().getProtocol();
                   metadata.put(transport);
                }
                if (host == null)
                {
                   host = SecurityUtility.getLocalHost().getHostAddress();
                   metadata.put(host);
                }
                if (port == -1)
                {
                   port = PortUtil.findFreePort(host);
                   metadata.put(, String.valueOf(port));
                }
 
                if(isBidirectional)
                {
                   callbackLocator =
                      ((BidirectionalClientInvoker)).getCallbackLocator(metadata);
                }
                else
                {
                   callbackLocator = new InvokerLocator(transporthostportnullmetadata);
                }
                .debug("starting callback Connector: " + callbackLocator);
                Map callbackConfig = new HashMap();
                
                if (.getParameters() != null)
                {
                   callbackConfig.putAll(.getParameters());
                }
                
                configureCallbackServerSocketFactory(callbackConfig);
                Connector callbackServerConnector = new Connector(callbackLocatorcallbackConfig);
                
                synchronized ()
                {
                   Set connectors = (Set.get(callbackhandler);
                   if (connectors == null)
                   {
                      connectors = new HashSet();
                   }
                   connectors.add(callbackServerConnector);
                   .put(callbackhandlerconnectors);
                }
 
                callbackServerConnector.start();
                // have to use the locator from the server as can be modified internally
                callbackLocator = callbackServerConnector.getServerInvoker().getLocator();
                addCallbackListener(callbackhandlermetadatacallbackLocatorcallbackHandlerObject);
             }
             else
             {
                if (.get(callbackhandler) != null)
                {
                   .debug(callbackhandler + " already registered");
                   return;
                }
                
                //need to setup poller to get callbacks from the server
                CallbackPoller poller =
                   new CallbackPoller(thiscallbackhandlermetadatacallbackHandlerObject);
                .put(callbackhandlerpoller);
                addCallbackListener(callbackhandlermetadatacallbackLocatorcallbackHandlerObject);
               poller.start();
            }
         }
         else
         {
            throw new NullPointerException("InvokerCallbackHandler to be added as " +
                                           "a listener can not be null.");
         }
      }
      else
      {
         throw new Exception("Can not add callback listener because " +
                             "remoting client is not connected to server.");
      }
   }

   
Adds the specified handler as a callback listener for pull (sync) callbacks. Using this method will require the programatic getting of callbacks from the server (they will not be pushed to the callback handler automatically).
   public void addListener(InvokerCallbackHandler callbackHandlerthrows Throwable
   {
      addListener(callbackHandler, (InvokerLocatornull);
   }

   
Adds the specified handler as a callback listener for push (async) callbacks. The invoker server will then callback on this handler (via the server invoker specified by the clientLocator) when it gets a callback from the server handler. Note: passing a null clientLocator will cause the client invoker's client locator to be set to null, which basically converts the mode to be pull (sync) where will require call to get callbacks (as will not automatically be pushed to callback handler).
   public void addListener(InvokerCallbackHandler callbackHandler,
                           InvokerLocator clientLocatorthrows Throwable
   {
      addListener(callbackHandlerclientLocatornull);
   }

   
Adds the specified handler as a callback listener for push (async) callbacks. The invoker server will then callback on this handler (via the server invoker specified by the clientLocator) when it gets a callback from the server handler. Note: passing a null clientLocator will cause the client invoker's client locator to be set to null, which basically converts the mode to be pull (sync) where will require call to get callbacks (as will not automatically be pushed to callback handler).

Parameters:
callbackHandlerObject will be included in the callback object passed upon callback.
   public void addListener(InvokerCallbackHandler callbackHandler,
                           InvokerLocator clientLocatorObject callbackHandlerObject)
      throws Throwable
   {
      if (callbackHandler != null)
      {
         if (isConnected())
         {
            addCallbackListener(callbackHandlernullclientLocatorcallbackHandlerObject);
         }
         else
         {
            throw new Exception("Can not add callback listener as " +
                                "remoting client is not connected to server.");
         }
      }
      else
      {
         throw new NullPointerException("InvokerCallbackHandler to be added as " +
                                        "a listener can not be null.");
      }
   }

   
Removes callback handler as a callback listener from the server (and client in the case that it was setup to receive async callbacks). See addListener().
   public void removeListener(InvokerCallbackHandler callbackHandlerthrows Throwable
   {
      if (isConnected())
      {
         if (callbackHandler != null)
         {
            // first need to see if is push or pull callback (i.e. does have locator associated
            // with it)
            String listenerId = (String).get(callbackHandler);
            if(listenerId != null)
            {
               // have a pull callback handler
               // If disconnectTimeout == 0, skip network i/o.
               if ( != 0)
               {
                  Map metadata = new HashMap();
                  metadata.put(listenerId);
                  
                  if ( > 0)
                     metadata.put(., Integer.toString());
                  try
                  {
                     invoke(new InternalInvocation(.null), metadata);
                  }
                  catch (Exception e)
                  {
                     .debug("unable to remove remote callback handler"e);
                  }
               }
               // clean up callback poller if one exists
               CallbackPoller callbackPoller = (CallbackPoller.remove(callbackHandler);
               if (callbackPoller != null)
               {
                  callbackPoller.stop();
               }
               .remove(callbackHandler);
            }
            else
            {
               // have a push callback handler
               List holderList = .getClientLocators(callbackHandler);
               if(holderList != null && holderList.size() > 0)
               {
                  for(int x = 0; x < holderList.size(); x++)
                  {
                     AbstractInvoker.CallbackLocatorHolder holder =
                        (AbstractInvoker.CallbackLocatorHolder)holderList.get(x);
                     listenerId = holder.getListenerId();
                     InvokerLocator locator = holder.getLocator();
                     Map metadata = new HashMap();
                     metadata.put(listenerId);
                     // If disconnectTimeout == 0, skip network i/o.
                     if ( != 0)
                     {
                        if ( > 0)
                           metadata.put(., Integer.toString());
                        try
                        {
                           // now call target server to remove listener
                           InternalInvocation ii =
                              new InternalInvocation(.null);
                           invoke(iimetadata);
                        }
                        catch (Exception e)
                        {
                           .debug("unable to remove remote callback handler"e);
                        }
                     }
                     // call to callback server to remove listener
                     Client client = new Client(locator);
                     client.setSessionId(getSessionId());
                     client.connect();
                     InternalInvocation ii =
                        new InternalInvocation(.,
                              new Object[]{callbackHandler});
                     client.invoke(iimetadata);
                     client.disconnect();
                  }
               }
            }
            // clean up callback server connectors if any exist
            Set connectors = null;
            synchronized ()
            {
               connectors = (Set.remove(callbackHandler);
            }
            if (connectors != null)
            {
               Iterator it = connectors.iterator();
               while (it.hasNext())
               {
                  Connector callbackConnector = (Connectorit.next();
                  callbackConnector.stop();
                  callbackConnector.destroy();
               }
            }
         }
         else
         {
            throw new NullPointerException("Can not remove null InvokerCallbackHandler listener.");
         }
      }
      else
      {
         throw new Exception("Can not remove callback listener as " +
         "remoting client is not connected to server.");
      }
   }

   
Gets the callbacks for specified callback handler. The handler is required because an id is generated for each handler. So if have two callback handlers registered with the same server, no other way to know for which handler to get the callbacks for.
   public List getCallbacks(InvokerCallbackHandler callbackHandlerthrows Throwable
   {
      return getCallbacks(callbackHandlernull);
   }
   
   
Gets the callbacks for specified callback handler. The handler is required because an id is generated for each handler. So if have two callback handlers registered with the same server, no other way to know for which handler to get the callbacks for. The metadata map can be used to set callback blocking mode and blocking timeout value.
   public List getCallbacks(InvokerCallbackHandler callbackHandlerMap metadatathrows Throwable
   {
      if (callbackHandler != null)
      {
         String listenerId = (String).get(callbackHandler);
         if(listenerId != null)
         {
            if (metadata == null)
               metadata = new HashMap();
            
            metadata.put(listenerId);
            InternalInvocation invocation = new InternalInvocation(.null);
            try
            {
               List response = (Listinvoke(invocationmetadata);
               return response;
            }
            catch (MarshalException e)
            {
               if (e.getCause() != null && e.getCause() instanceof SocketTimeoutException)
               {
                  if (.isTraceEnabled()) .trace(this + ": getCallbacks() timed out: returning empty list");
                  return new ArrayList();
               }
               throw e;
            }
            finally
            {
               metadata.remove();
            }
         }
         else
         {
            String errorMessage = "Could not find listener id for InvokerCallbackHandler (" +
                                  callbackHandler +
                                  "), please verify handler has been registered as listener.";
            String errorMode = (Stringmetadata.get();
            boolean throwError = Boolean.valueOf(errorMode).booleanValue();
            
            if (throwError)
            {
               throw new IOException(errorMessage);
            }
            else
            {
               .error(errorMessage);
               return null;
            }
         }
      }
      else
      {
         throw new NullPointerException("Can not remove null InvokerCallbackHandler listener.");
      }
   }
   public int acknowledgeCallback(InvokerCallbackHandler callbackHandlerCallback callback)
      throws Throwable
   {
      return acknowledgeCallback(callbackHandlercallbacknull);
   }
   public int acknowledgeCallback(InvokerCallbackHandler callbackHandlerCallback callback,
                                  Object responsethrows Throwable
   {
      ArrayList callbacks = new ArrayList(1);
      callbacks.add(callback);
      ArrayList responses = null;
      if (response != null)
      {
         responses = new ArrayList(1);
         responses.add(response);
      }
      return acknowledgeCallbacks(callbackHandlercallbacksresponses);
   }
   public int acknowledgeCallbacks(InvokerCallbackHandler callbackHandlerList callbacks)
      throws Throwable
   {
      return acknowledgeCallbacks(callbackHandlercallbacksnull);
   }
   public int acknowledgeCallbacks(InvokerCallbackHandler callbackHandlerList callbacks,
                                   List responsesthrows Throwable
   {
      if (callbackHandler == null)
      {
         throw new Exception("InvokerCallbackHandler parameter must not be null");
      }
      if (callbacks == null)
      {
         throw new Exception("Callback List parameter must not be null");
      }
      if (responses != null && responses.size() != callbacks.size())
      {
         throw new Exception("Callback response list must be (1) null " +
                             "or (2) the same size as callback list");
      }
      if (callbacks.size() == 0)
      {
         return 0;
      }
      if (isConnected())
      {
         ArrayList callbackIds = new ArrayList(callbacks.size());
         Iterator idsIterator = callbacks.iterator();
         ArrayList responseList = null;
         Iterator responseIterator = null;
         if (responses != null)
         {
            responseList = new ArrayList(responses.size());
            responseIterator = responses.iterator();
         }
         Callback callback = null;
         Object response = null;
         String listenerId = null;
         for (int i = 0; i < callbacks.size(); i++)
         {
            callback = (CallbackidsIterator.next();
            if (responseIterator != null)
            {
               response = responseIterator.next();
            }
            Map returnPayload = callback.getReturnPayload();
            if (returnPayload != null)
            {
               Object callbackId = returnPayload.get(.);
               if (callbackId != null)
               {
                  callbackIds.add(callbackId);
                  if (responseIterator != null)
                  {
                     responseList.add(response);
                  }
                  String nextListenerId = (StringreturnPayload.get();
                  if (nextListenerId == null)
                  {
                     throw new Exception("Cannot acknowledge callbacks: " +
                                         "callback " + callbackId + " has null listener id");
                  }
                  if (i == 0)
                  {
                     listenerId = nextListenerId;
                  }
                  else
                  {
                     if (!listenerId.equals(nextListenerId))
                        throw new Exception("Cannot acknowledge callbacks: " +
                                            "all must be from same server side callback handler");
                  }
               }
               else
               {
                  .error("Cannot acknowledge callback: callback id " +
                            "is missing from return payload");
               }
            }
            else
            {
               .error("Cannot acknowledge callback: return payload is null");
            }
         }
         if (callbackIds.size() == 0)
         {
            return 0;
         }
         Map metadata = new HashMap();
         if(listenerId != null)
         {
            metadata.put(listenerId);
         }
         else
         {
            throw new Exception("Could not find listener id for InvokerCallbackHandler (" +
                                callbackHandler + "), please verify handler " +
                                "has been registered as listener.");
         }