/*
* 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.test.remoting.transport.multiplex;


import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.MarshalException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import junit.framework.TestCase;

import org.apache.log4j.Category;
import org.apache.log4j.FileAppender;
import org.apache.log4j.PatternLayout;
import org.jboss.logging.Logger;
import org.jboss.remoting.Client;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.InvokerRegistry;
import org.jboss.remoting.ServerInvoker;
import org.jboss.remoting.callback.Callback;
import org.jboss.remoting.callback.HandleCallbackException;
import org.jboss.remoting.callback.InvokerCallbackHandler;
import org.jboss.remoting.transport.ClientInvoker;
import org.jboss.remoting.transport.Connector;
import org.jboss.remoting.transport.multiplex.MasterServerSocket;
import org.jboss.remoting.transport.multiplex.MultiplexClientInvoker;
import org.jboss.remoting.transport.multiplex.MultiplexServerInvoker;
import org.jboss.remoting.transport.multiplex.MultiplexingManager;
import org.jboss.remoting.transport.multiplex.VirtualServerSocket;

/**
 * 
 */
public class MultiplexInvokerTestClient extends TestCase
{
   private static final Logger log = Logger.getLogger(MultiplexInvokerTestClient.class);

   // Default locator values
   private static String transport = "multiplex";
   private static String serverHost = "localhost";
   private static int serverPort = 7070;
   private static String callbackHost = "localhost";
   private static int callbackPort = 6060;
   private static boolean firstTime = true;
   private static Connector virtualServerSocketTestConnector;
   private static String virtualServerSocketTestBindHost = "localhost";
   private static int virtualServerSocketTestBindPort = 9090;
   private static boolean testsOver = false;

   OneServerInvokerTester tester;

   public void setUp()
   {
      if(firstTime)
      {
         firstTime = false;

         String pattern = "%5p [%t] (%F:%L) <%d{ABSOLUTE}> - %m%n";
         PatternLayout layout = new PatternLayout(pattern);

         try
         {
            File logFile = new File("test_logs");
            logFile.mkdir();
            FileAppender fileAppender = new FileAppender(layout, "test_logs" + File.separator + "invoker.client.log");
            fileAppender.setAppend(false);
            //fileAppender.setThreshold(Level.toLevel(testLogLevel));
            Category.getRoot().addAppender(fileAppender);
         }
         catch(IOException e)
         {
            log.error(e);
            e.printStackTrace();
            logStackTrace(e);
         }

         try
         {
            // Give server a chance to start.
            Thread.sleep(5000);
         }
         catch(InterruptedException ignored)
         {
         }
      }
      else
      {
         serverPort++;
         callbackPort++;

//         try
//         {
//            Thread.sleep(1000);
//         }
//         catch (InterruptedException ignored)
//         {
//         }
      }

      tester = new OneServerInvokerTester();
   }

   public void tearDown()
   {
      tester.close();

      if(testsOver)
      {
         virtualServerSocketTestConnector.stop();
      }
   }

   public void zztestMasterServerInvoker()
   {
      try
      {
         OneServerInvokerTester tester = new OneServerInvokerTester();
         tester.createRemotingClient(transport + "://" + serverHost + ":" + serverPort);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort;
         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));

         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getServerSocket() instanceof MasterServerSocket);
         assertTrue(tester.runPushCallbackTest(callbackLocator));
      }
      catch(Throwable e)
      {
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }

   public void testMultiplexInvokerTimeout()
   {
      log.info("entering testMultiplexInvokerTimeout()");
      System.out.println("entering testMultiplexInvokerTimeout()");

      try
      {
         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&multiplexBindHost=" + callbackHost +
                                                           "&multiplexBindPort=" + callbackPort +
                                                           "&timeout=5000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 5000);

         // test socket timeout
         try
         {
            tester.makeInvocation();
            fail();
         }
         catch(Exception e)
         {
            if(! (e instanceof MarshalException))
            {
               log.error(e);
               fail();
            }
         }

         assertTrue(tester.makeInvocation().equals(new Integer(0)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));
      }
      catch(Throwable e)
      {
         log.error(e);
         logStackTrace(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }

      log.info("testMultiplexInvokerTimeout() PASSES");
   }

 
   public void testRule1ClientFirst()
   {
      log.info("entering testRule1ClientFirst()");
      System.out.println("entering testRule1ClientFirst()");

      try
      {
         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&multiplexBindHost=" + callbackHost +
                                                           "&multiplexBindPort=" + callbackPort +
                                                           "&timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?serverMultiplexId=testMultiplexId" +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));

         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof VirtualServerSocket);
         VirtualServerSocket vss = (VirtualServerSocket) serverSocket;
         assertTrue(vss.getRemotePort() == serverPort);
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule1ClientFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }


   public void testRule1ServerFirst()
   {
      log.info("entering testRule1ServerFirst()");
      System.out.println("entering testRule1ServerFirst()");


      try
      {
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?serverMultiplexId=testMultiplexId" +
                              "&multiplexConnectHost=" + serverHost +
                              "&multiplexConnectPort=" + serverPort +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));
         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof VirtualServerSocket);
         VirtualServerSocket vss = (VirtualServerSocket) serverSocket;
         assertTrue(vss.getRemotePort() == serverPort);

         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);

         // test push callbacks
         assertTrue(tester.runPushCallbackTest(callbackLocator));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test invocations
         assertTrue(tester.makeInvocation().equals(new Integer(0)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));
         
         log.info("testRule1ServerFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }


   public void testRule2ClientFirst()
   {
      log.info("entering testRule2ClientFirst()");
      System.out.println("entering testRule2ClientFirst()");

      try
      {
         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?multiplexBindHost=" + callbackHost +
                                                           "&multiplexBindPort=" + callbackPort +
                                                           "&timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?multiplexConnectHost=" + serverHost +
                              "&multiplexConnectPort=" + serverPort +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));

         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof VirtualServerSocket);
         VirtualServerSocket vss = (VirtualServerSocket) serverSocket;
         assertTrue(vss.getRemotePort() == serverPort);
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule2ClientFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }

   public void testRule2ServerFirst()
   {
      log.info("entering testRule2ServerFirst()");
      System.out.println("entering testRule2ServerFirst()");

      try
      {
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?multiplexConnectHost=" + serverHost +
                              "&multiplexConnectPort=" + serverPort +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));
         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof VirtualServerSocket);
         VirtualServerSocket vss = (VirtualServerSocket) serverSocket;
         assertTrue(vss.getRemotePort() == serverPort);

         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?multiplexBindHost=" + callbackHost +
                                                           "&multiplexBindPort=" + callbackPort +
                                                           "&timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule2ServerFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }


   public void testRule3ClientFirst()
   {
      log.info("entering testRule3ClientFirst()");
      System.out.println("entering testRule3ClientFirst()");

      try
      {
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?serverMultiplexId=testMultiplexId" +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);

         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         tester.setupServer(callbackLocator);
         callbackLocator = tester.getCallbackServerLocator();

         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));
         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof VirtualServerSocket);
         VirtualServerSocket vss = (VirtualServerSocket) serverSocket;
         assertTrue(vss.getRemotePort() == serverPort);
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule3ClientFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }


   public void testRule3ServerFirst()
   {
      log.info("entering testRule3ServerFirst()");
      System.out.println("entering testRule3ServerFirst()");

      try
      {
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?serverMultiplexId=testMultiplexId" +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);

         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&timeout=60000");

         tester.setupServer(callbackLocator);
         tester.createRemotingClient(serverLocator.getLocatorURI());

         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));
         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof VirtualServerSocket);
         VirtualServerSocket vss = (VirtualServerSocket) serverSocket;
         assertTrue(vss.getRemotePort() == serverPort);
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule3ServerFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }


   public void testRule4ClientFirst()
   {
      log.info("entering testRule4ClientFirst()");
      System.out.println("entering testRule4ClientFirst()");

      try
      {
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);

         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         tester.setupServer(callbackLocator);

         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));
         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof MasterServerSocket);
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule4ClientFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }

   public void testRule4ServerFirst()
   {
      log.info("entering testRule4ServerFirst()");
      System.out.println("entering testRule4ServerFirst()");

      try
      {
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));
         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof MasterServerSocket);

         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule4ServerFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }


   public void testInconsistentClientParameters()
   {
      log.info("entering testInconsistentClientParameters()");
      System.out.println("entering testInconsistentClientParameters()");


      try
      {
         String callbackURI = transport + "://" + callbackHost + ":" + callbackPort +
                              "/?serverMultiplexId=testMultiplexId" +
                              "&multiplexConnectHost=" + serverHost +
                              "&multiplexConnectPort=" + serverPort +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);

         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + 3333 +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&timeout=60000");

         try
         {
            tester.createRemotingClient(serverLocator.getLocatorURI());
            fail();
         }
         catch (Throwable t)
         {
            if (!t.getMessage().startsWith("socket group connect port") )
               fail();
         }
         
         log.info("testInconsistentClientParameters() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }

   
   public void testInconsistentServerParameters()
   {
      log.info("entering testInconsistentServerParameters()");
      System.out.println("entering testInconsistentServerParameters()");

      try
      {
         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&multiplexBindHost=" + callbackHost +
                                                           "&multiplexBindPort=" + callbackPort +
                                                           "&timeout=60000");

         tester.createRemotingClient(serverLocator.getLocatorURI());

         // test push callbacks
         String callbackURI = transport + "://" + callbackHost + ":" + 3333 +
                              "/?serverMultiplexId=testMultiplexId" +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         
         try
         {
            tester.setupServer(callbackLocator);
            fail();
         }
         catch (Throwable t)
         {
//            t = t.getCause();
            if (!t.getCause().getMessage().startsWith("socket group bind port") )
               fail();
         }

         log.info("testInconsistentServerParameters() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }
   
   
   public void ytestAnonymousPort()
   {
      log.info("entering testAnonymousPort()");
      System.out.println("entering testAnonymousPort()");


      try
      {
         InvokerLocator serverLocator = new InvokerLocator(transport +
                                                           "://" + serverHost + ":" + serverPort +
                                                           "/?clientMultiplexId=testMultiplexId" +
                                                           "&multiplexBindHost=" + callbackHost +
                                                           "&multiplexBindPort=" + callbackPort +
                                                           "&timeout=600000");

         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 600000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         String callbackURI = transport + "://" + callbackHost + 
                              "/?serverMultiplexId=testMultiplexId" +
                              "&backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);
         tester.setupServer(callbackLocator);
         callbackLocator = tester.getCallbackServerLocator();
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));

         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getLocator().getPort() == callbackPort);
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof VirtualServerSocket);
         VirtualServerSocket vss = (VirtualServerSocket) serverSocket;
         assertTrue(vss.getRemotePort() == serverPort);
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testRule1ClientFirst() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }
   
   
   public void testMultiplexInvokerVirtualServerSocket()
   {
      log.info("entering testMultiplexInvokerVirtualServerSocket()");
      System.out.println("entering testMultiplexInvokerVirtualServerSocket()");

      try
      {
         String callbackURI = transport + "://" + virtualServerSocketTestBindHost + ":" + virtualServerSocketTestBindPort +
                              "/?backlog=2" +
                              "&numAcceptThreads=5" +
                              "&timeout=300000";

         InvokerLocator callbackLocator = new InvokerLocator(callbackURI);

         // synchronize with server
         Socket s = new Socket(virtualServerSocketTestBindHost, virtualServerSocketTestBindPort + 1);
         s.close();

         tester.setupServer(callbackLocator);
         assertTrue(InvokerRegistry.isServerInvokerRegistered(callbackLocator));
         ServerInvoker[] serverInvokers = InvokerRegistry.getServerInvokers();
         MultiplexServerInvoker multiplexServerInvoker = null;

         for(int i = 0; i < serverInvokers.length; i++)
         {
            if(serverInvokers[i].getLocator().equals(callbackLocator))
            {
               if(serverInvokers[i] instanceof MultiplexServerInvoker)
               {
                  multiplexServerInvoker = (MultiplexServerInvoker) serverInvokers[i];
               }
            }
         }

         assertTrue(multiplexServerInvoker != null);
         assertTrue(multiplexServerInvoker.getLocator().equals(callbackLocator));
         assertTrue(multiplexServerInvoker.getBacklog() == 2);
         assertTrue(multiplexServerInvoker.getNumAcceptThreads() == 5);
         assertTrue(multiplexServerInvoker.getTimeout() == 300000);
         ServerSocket serverSocket = multiplexServerInvoker.getServerSocket();
         assertTrue(serverSocket instanceof MasterServerSocket);

         InvokerLocator serverLocator = new InvokerLocator(transport + "://" + serverHost +
                                                           ":" + serverPort +
                                                           "/?timeout=60000");


         InetSocketAddress connectAddress = new InetSocketAddress(serverHost, serverPort);

         for(int i = 0; i < 5; i++)
         {
            if(MultiplexingManager.checkForShareableManager(connectAddress))
            {
               break;
            }

            try
            {
               Thread.sleep(2000);
            }
            catch(InterruptedException ignored)
            {
            }
         }


         Thread.sleep(10000);
         tester.createRemotingClient(serverLocator.getLocatorURI());
         assertTrue(InvokerRegistry.isClientInvokerRegistered(serverLocator));
         ClientInvoker[] clientInvokers = InvokerRegistry.getClientInvokers();
         MultiplexClientInvoker multiplexClientInvoker = null;

         for(int i = 0; i < clientInvokers.length; i++)
         {
            if(clientInvokers[i].getLocator().equals(serverLocator))
            {
               if(clientInvokers[i] instanceof MultiplexClientInvoker)
               {
                  multiplexClientInvoker = (MultiplexClientInvoker) clientInvokers[i];
               }
            }
         }

         assertTrue(multiplexClientInvoker != null);
         assertTrue(multiplexClientInvoker.getLocator().equals(serverLocator));
         assertTrue(multiplexClientInvoker.getTimeout() == 60000);
         assertTrue(tester.makeInvocation().equals(new Integer(1)));
         assertTrue(tester.makeInvocation().equals(new Integer(0)));

         // Check on virtual MultiplexServerInvoker before it's destroyed by runPushCallbackTest().
         InetSocketAddress address = new InetSocketAddress(serverHost, serverPort);
         MultiplexServerInvoker virtualServerInvoker = multiplexServerInvoker.getServerInvoker(address);
         assertTrue(virtualServerInvoker.getServerSocket() instanceof VirtualServerSocket);

         // test pull callbacks
         assertTrue(tester.runPullCallbackTest());

         // test push callbacks
         assertTrue(tester.runPushCallbackTest(callbackLocator));
         log.info("testMultiplexInvokerVirtualServerSocket() PASSES");
      }
      catch(Throwable e)
      {
         log.error(e);
         e.printStackTrace();
         logStackTrace(e);
         fail();
      }
   }


   private void logStackTrace(Throwable e)
   {
      StackTraceElement[] stackTraceElements = e.getStackTrace();
      StringBuffer sb = new StringBuffer();
      
      for (int i = 0; i < stackTraceElements.length; i++)
      {
         StackTraceElement ste = stackTraceElements[i];
         sb.append("[" + ste.getFileName() + ": " + ste.getLineNumber() + "]: " + ste.getMethodName());
//         log.error("[" + ste.getFileName() + ": " + ste.getLineNumber() + "]: " + ste.getMethodName());
      }
      
      log.error(sb.toString());
   }


   static class OneServerInvokerTester
   {
      private Client remotingClient;
      private Client remotingClient2;

      // callback server, which receives push callbacks.
      private Connector callbackServerConnector;

      /**
       * Create the remoting client to use to make calls on the remoting server.
       *
       * @param locatorURI
       * @throws Exception
       */
      public void createRemotingClient(String locatorURI) throws Exception
      {
         InvokerLocator locator = new InvokerLocator(locatorURI);
         System.out.println("Calling remoting server with locator uri of: " + locatorURI);
         remotingClient = new Client(locator);
         remotingClient.connect();

         remotingClient2 = new Client(locator);
         remotingClient2.connect();
      }

      /**
       * Makes a call on the remoting server.
       *
       * @throws Throwable
       */
      public Object makeInvocation() throws Throwable
      {
         log.info("entering makeInvocation()");
         return remotingClient.invoke(new Integer(0), null);
      }

      /**
       * Shows how to register for pull callbacks and then get any callbacks
       * that are waiting on the server.
       *
       * @throws Throwable
       */
      public boolean runPullCallbackTest() throws Throwable
      {
         boolean success = true;

         // our impplementation of the InvokerCallbackHandler interface, which
         // is defined as an inner class below.
         CallbackHandler callbackHandler = new CallbackHandler();

         // by passing only the callback handler, will indicate pull callbacks
         log.info("pull callbacks: adding listener");
         remotingClient.addListener(callbackHandler);

         Thread.sleep(500);

         // go get our callbacks residing on the server
         System.out.println("getting callbacks: " + remotingClient.getInvoker().getLocator());
         List callbacks = remotingClient.getCallbacks(callbackHandler);
         log.info("pull callbacks: got callbacks");
         Iterator itr = callbacks.iterator();
         int counter = 0;

         while(itr.hasNext())
         {
            counter++;
            Callback callbackObject = (Callback) itr.next();
            success &= callbackObject.getCallbackObject().equals(new Integer(counter));
         }

         success &= counter == 2;

         // remove callback handler from server
         remotingClient.removeListener(callbackHandler);
         log.info("pull callbacks: removed listener");

         return success;
      }

      /**
       * Shows how to register for push callbacks where the server will
       * callback on our callback handler when it generates a callback.
       *
       * @param callbackLocator TODO
       * @throws Throwable
       */
      public boolean runPushCallbackTest(InvokerLocator callbackLocator) throws Throwable
      {
         System.out.println("entering runPushCallbackTest()");
         CallbackHandler callbackHandler = new CallbackHandler();
         CallbackHandler callbackHandler2 = new CallbackHandler();

         // Callback handle object will be passed back as part of the callback object
         // This can be used at the time the callback is received to identify context
         String callbackHandleObject = "myCallbackHandleObject";
         String callbackHandleObject2 = "myCallbackHandleObject2";

         // by passing the callback handler and callback locator, will indicate push callbacks
         // could also have not included callbackHandleObject as last parameter if did not care
         // callback handle (i.e. addListener(callbackHandler, callbackLocator); )
         log.info("push callbacks: adding listener");
         remotingClient.addListener(callbackHandler, callbackLocator, callbackHandleObject);
         remotingClient2.addListener(callbackHandler2, callbackLocator, callbackHandleObject2);

//         // need to wait for brief moment so server can callback
//         Thread.sleep(500);

         // remove callback handler from server
         remotingClient.removeListener(callbackHandler);
         remotingClient2.removeListener(callbackHandler2);
         log.info("push callbacks: removed listener");

         // shut down callback server
         callbackServerConnector.stop();
         callbackServerConnector.destroy();
         callbackServerConnector = null;
         System.out.println("stopped callback Connector");
         
         List callbacks = callbackHandler.getCallbacks();
         Iterator itr = callbacks.iterator();
         int counter = 0;
         boolean success = true;

         while(itr.hasNext())
         {
            counter++;
            Callback callbackObject = (Callback) itr.next();
            success &= callbackObject.getCallbackObject().equals(new Integer(counter));
            success &= callbackObject.getCallbackHandleObject().equals(callbackHandleObject);
            System.out.println("callback: " + callbackObject.getCallbackObject());
         }
         System.out.println("printed first set of callbacks");

         callbacks = callbackHandler2.getCallbacks();
         itr = callbacks.iterator();
         int counter2 = 0;

         while(itr.hasNext())
         {
            counter2++;
            Callback callbackObject = (Callback) itr.next();
            success &= callbackObject.getCallbackObject().equals(new Integer(counter2));
            success &= callbackObject.getCallbackHandleObject().equals(callbackHandleObject2);
            System.out.println("callback: " + callbackObject.getCallbackObject());
         }
         System.out.println("printed second set of callbacks");
         
         success &= (counter + counter2) == 4;
         return success;
      }

      /**
       * Sets up the callback server that the target remoting server can call on
       * with the callbacks that it generates.
       *
       * @param locator
       * @throws Exception
       */
      public void setupServer(InvokerLocator locator) throws Exception
      {
         System.out.println("Starting remoting server with locator uri of: " + locator);
         callbackServerConnector = new Connector();
         callbackServerConnector.setInvokerLocator(locator.getLocatorURI());
         callbackServerConnector.start();
         System.out.println("Started remoting server with original locator uri of: " + locator);
         System.out.println("Started remoting server with updated  locator uri of: " + callbackServerConnector.getInvokerLocator());

         // are using the same invocation handler as the one on the sample callback server
         MultiplexInvokerTestServer.SampleInvocationHandler invocationHandler
               = new MultiplexInvokerTestServer.SampleInvocationHandler(false);
         // first parameter is sub-system name.  can be any String value.
         callbackServerConnector.addInvocationHandler("sample", invocationHandler);
      }

      public void close()
      {
         if(remotingClient != null)
         {
            remotingClient.disconnect();
         }
         
         if(remotingClient2 != null)
         {
            remotingClient2.disconnect();
         }
         
         if (callbackServerConnector != null)
         {
            callbackServerConnector.stop();
            callbackServerConnector.destroy();
         }
      }
      
      public InvokerLocator getClientLocator()
      {
         return remotingClient.getInvoker().getLocator();
      }
      
      public InvokerLocator getCallbackServerLocator()
      {
         return callbackServerConnector.getLocator();
      }
   }


   /**
    * Our implementation of the InvokerCallbackHandler.  Simply
    * prints out the callback object's message upon receiving it.
    */
   public static class CallbackHandler implements InvokerCallbackHandler
   {
      private ArrayList callbacks = new ArrayList();

      public ArrayList getCallbacks()
      {
         return callbacks;
      }

      /**
       * Will take the callback and print out its values.
       *
       * @param callback
       * @throws org.jboss.remoting.callback.HandleCallbackException
       *
       */
      public void handleCallback(Callback callback) throws HandleCallbackException
      {
         log.info("Received push callback.");
         log.info("Received callback value of: " + callback.getCallbackObject());
         log.info("Received callback server invoker of: " + callback.getServerLocator());
         System.out.println("Received push callback: " + callback.getCallbackObject());
         callbacks.add(callback);
      }
   }
}

