/*
 * JBoss, Home of Professional Open Source
 * Copyright 2006, 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.lang.reflect.Field;
import java.util.LinkedList;
import java.util.Map;

import javax.management.MBeanServer;

import org.jboss.logging.Logger;
import org.jboss.remoting.Client;
import org.jboss.remoting.InvocationRequest;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.ServerInvocationHandler;
import org.jboss.remoting.ServerInvoker;
import org.jboss.remoting.callback.InvokerCallbackHandler;
import org.jboss.remoting.transport.Connector;
import org.jboss.remoting.transport.PortUtil;
import org.jboss.remoting.transport.multiplex.MultiplexServerInvoker;
import org.jboss.remoting.transport.socket.LRUPool;
import org.jboss.remoting.transport.socket.SocketServerInvoker;
import org.jboss.test.remoting.transport.multiplex.utility.SuccessCountingTestCase;

public class SharedThreadpoolTestCaseOld extends SuccessCountingTestCase
{
   private static final Logger log = Logger.getLogger(SharedThreadpoolTestCaseOld.class);
   static int connectPort;
   static String serverLocatorURI;
   static InvokerLocator serverLocator;;
   static Connector connector;

   
   public void setUp() throws Exception
   {
      super.setUp();
      
      if (connector == null)
      {
         try
         {
            connectPort = PortUtil.findFreePort("localhost");
            serverLocator = new InvokerLocator("multiplex://localhost:" + connectPort);
            serverLocatorURI = "multiplex://localhost:" + connectPort;
            connector = new Connector(serverLocator.getLocatorURI());
            connector.create();
            connector.addInvocationHandler("test", new InvocationHandler());
            connector.start();
         }
         catch (Exception e)
         {
            log.error(e);
            e.printStackTrace();
         }
      }
      else
      {
         Thread.sleep(500);
      }
   }
   
   
   public void testSharedThreads()
   {
      log.info("ENTERING " + getName());
      
      try
      {
         // Create two Client, each with different bind ports, so that we get
         // two virtual MultiplexServerInvokers.
         String locatorURI = serverLocatorURI + "/?multiplexBindHost=localhost&multiplexBindPort=";
         int port1 = PortUtil.findFreePort("localhost");
         int port2 = PortUtil.findFreePort("localhost");
         InvokerLocator clientLocator1 = new InvokerLocator(locatorURI + port1);
         InvokerLocator clientLocator2 = new InvokerLocator(locatorURI + port2);
         System.out.println(clientLocator1);
         System.out.println(clientLocator2);
         Client client1 = new Client(clientLocator1);
         Client client2 = new Client(clientLocator2);
         client1.connect();
         client2.connect();
         
         // Verify that two virtual MultiplexServerInvokers exists.
         Field field = MultiplexServerInvoker.class.getDeclaredField("virtualServerInvokers");
         field.setAccessible(true);
         Map virtualServerInvokers = (Map) field.get(connector.getServerInvoker());
         for (int i = 0; i < 5; i++)
         {
            if (virtualServerInvokers.size() == 2)
               break;
            Thread.sleep(1000);
         }
         if (virtualServerInvokers.size() != 2)
            fail();
         
         // Make an invocation on each Client, each of which will lead to the creation
         // of a ServerThread.
         class ClientThread extends Thread
         {
            Client client;
            ClientThread(Client client) {this.client = client;}
            public void run()
            {
               try
               {
                  client.invoke("abc");
               }
               catch (Throwable t)
               {
                  log.error(t);
                  t.printStackTrace();
               }
            }
         }
         new ClientThread(client1).start();
         new ClientThread(client2).start();
         
         // Wait for there to be two ServerThreads in the master
         // MultiplexServerInvoker's clientpool.
         field = SocketServerInvoker.class.getDeclaredField("clientpool");
         field.setAccessible(true);
         LRUPool clientpool = (LRUPool) field.get(connector.getServerInvoker());
         for (int i = 0; i < 5; i++)
         {
            if (clientpool.size() == 2)
               break;
            Thread.sleep(1000);
         }
         if (clientpool.size() != 2)
            fail();

         // Wait for the two virtual MultiplexServerInvokers to shut down.
         client1.disconnect();
         client2.disconnect();
         for (int i = 0; i < 5; i++)
         {
            if (virtualServerInvokers.size() == 0)
               break;
            Thread.sleep(1000);
         }
         assertTrue(virtualServerInvokers.size() == 0);

         // Verify that the master MultiplexServerInvoker still has two ServerThreads.
         field = SocketServerInvoker.class.getDeclaredField("threadpool");
         field.setAccessible(true);
         LinkedList threadpool = (LinkedList) field.get(connector.getServerInvoker());
         assertTrue(clientpool.size() + threadpool.size() == 2);
         
         log.info(getName() + " PASSES");
         OKCounter++;
      }
      catch (Throwable t)
      {
         log.error(getName() + " FAILS");
         log.error(t);
         t.printStackTrace();
         fail();
      }
   }
   
   
   public static class InvocationHandler implements ServerInvocationHandler
   {
      public Object invoke(InvocationRequest invocation) throws Throwable
      {
         Thread.sleep(4000);
         return invocation.getParameter();
      }

      public void addListener(InvokerCallbackHandler callbackHandler)
      {
      }

      public void removeListener(InvokerCallbackHandler callbackHandler)
      {
      }

      public void setMBeanServer(MBeanServer server)
      {
      }

      public void setInvoker(ServerInvoker invoker)
      {
      }
   }
}
