Package org.jboss.test.messaging.jms.clustering.base

Source Code of org.jboss.test.messaging.jms.clustering.base.ClusteringTestBase$SimpleFailoverListener

/*
   * 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.messaging.jms.clustering.base;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.InitialContext;

import org.jboss.jms.client.FailoverEvent;
import org.jboss.jms.client.FailoverListener;
import org.jboss.jms.client.JBossConnection;
import org.jboss.jms.client.delegate.DelegateSupport;
import org.jboss.jms.client.state.ConnectionState;
import org.jboss.test.messaging.MessagingTestCase;
import org.jboss.test.messaging.tools.ServerManagement;

import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;

/**
* @author <a href="mailto:tim.fox@jboss.org">Tim Fox</a>
* @author <a href="mailto:clebert.suconic@jboss.org">Clebert Suconic</a>
* @author <a href="mailto:ovidiu@jboss.org">Ovidiu Feodorov</a>
* @version <tt>$Revision: 2450 $</tt>
* $Id: ClusteringTestBase.java 2450 2007-02-26 23:06:40Z clebert.suconic@jboss.com $
*/
public class ClusteringTestBase extends MessagingTestCase
{
   // Constants ------------------------------------------------------------------------------------

   // Static ---------------------------------------------------------------------------------------

   // Attributes -----------------------------------------------------------------------------------

   protected int nodeCount;
   protected String config = "all";

   protected Context[] ic;
   protected Queue queue[];
   protected Topic topic[];

   // No need to have multiple conncetion factories since a clustered connection factory will create
   // connections in a round robin fashion on different servers.

   protected ConnectionFactory cf;

   // Constructors ---------------------------------------------------------------------------------

   public ClusteringTestBase(String name)
   {
      super(name);
   }

   // Public ---------------------------------------------------------------------------------------

   // Package protected ----------------------------------------------------------------------------

   // Protected ------------------------------------------------------------------------------------

   protected void setUp() throws Exception
   {
      super.setUp();

      if (nodeCount < 1)
      {
         throw new Exception("Node count not defined! Initalize nodeCount in the test's setUp()");
      }

      ic = new Context[nodeCount];
      queue = new Queue[nodeCount];
      topic = new Topic[nodeCount];

      for (int i = 0; i < nodeCount; i++)
      {
         // make sure all servers are created and started; make sure that database is zapped
         // ONLY for the first server, the others rely on values they expect to find in shared
         // tables; don't clear the database for those.
         ServerManagement.start(i, config, i == 0);

         ServerManagement.deployQueue("testDistributedQueue", i);
         ServerManagement.deployTopic("testDistributedTopic", i);

         ic[i] = new InitialContext(ServerManagement.getJNDIEnvironment(i));
         queue[i] = (Queue)ic[i].lookup("queue/testDistributedQueue");
         topic[i] = (Topic)ic[i].lookup("topic/testDistributedTopic");
      }

      // We only need to lookup one connection factory since it will be clustered so we will
      // actually create connections on different servers (round robin).
      cf = (ConnectionFactory)ic[0].lookup("/ConnectionFactory");

      drainQueues();
   }

   protected void tearDown() throws Exception
   {

      for(int i = 0; i < nodeCount; i++)
      {
         if (ServerManagement.isStarted(i))
         {
            ServerManagement.log(ServerManagement.INFO, "Undeploying Server " + i, i);
            ServerManagement.undeployQueue("testDistributedQueue", i);
            ServerManagement.undeployTopic("testDistributedTopic", i);
            ServerManagement.stop(i);
         }

         ic[i].close();
      }

      super.tearDown();
   }

   protected String getLocatorURL(Connection conn)
   {
      return getConnectionState(conn).getRemotingConnection().
         getRemotingClient().getInvoker().getLocator().getLocatorURI();
   }

   protected int getServerId(Connection conn)
   {
      return getConnectionState(conn).getServerID();
   }

   protected int getObjectId(Connection conn)
   {
      return ((DelegateSupport) ((JBossConnection) conn).
         getDelegate()).getID();
   }

   protected ConnectionState getConnectionState(Connection conn)
   {
      return (ConnectionState) (((DelegateSupport) ((JBossConnection) conn).
         getDelegate()).getState());
   }

   protected Connection createConnectionOnServer(ConnectionFactory factory, int serverId)
      throws Exception
   {
      int count=0;

      while (true)
      {
         if (count++>10)
            return null;

         Connection connection = factory.createConnection();

         if (getServerId(connection) == serverId)
         {
            return connection;
         }
         else
         {
            connection.close();
         }
      }
   }


   protected void waitForFailoverComplete(int serverID, Connection conn1)
      throws Exception
   {

      assertEquals(serverID, ((JBossConnection)conn1).getServerID());

      // register a failover listener
      SimpleFailoverListener failoverListener = new SimpleFailoverListener();
      ((JBossConnection)conn1).registerFailoverListener(failoverListener);

      log.debug("killing node " + serverID + " ....");

      ServerManagement.kill(serverID);

      log.info("########");
      log.info("######## KILLED NODE " + serverID);
      log.info("########");

      // wait for the client-side failover to complete

      while(true)
         {
            FailoverEvent event = failoverListener.getEvent(120000);
         if (event != null && FailoverEvent.FAILOVER_COMPLETED == event.getType())
         {
            break;
         }
         if (event == null)
         {
            fail("Did not get expected FAILOVER_COMPLETED event");
         }
      }

      // failover complete
      log.info("failover completed");
   }



   /**
    * Lookup for the connection with the right serverID. I'm using this method to find the proper
    * serverId so I won't relay on loadBalancing policies on testcases.
    */
   protected Connection getConnection(Connection[] conn, int serverId) throws Exception
   {
      for(int i = 0; i < conn.length; i++)
      {
         ConnectionState state = (ConnectionState)(((DelegateSupport)((JBossConnection)conn[i]).
            getDelegate()).getState());

         if (state.getServerID() == serverId)
         {
            return conn[i];
         }
      }

      return null;
   }

   protected void checkConnectionsDifferentServers(Connection[] conn) throws Exception
   {
      int[] serverID = new int[conn.length];
      for(int i = 0; i < conn.length; i++)
      {
         ConnectionState state = (ConnectionState)(((DelegateSupport)((JBossConnection)conn[i]).
            getDelegate()).getState());
         serverID[i] = state.getServerID();
      }

      for(int i = 0; i < nodeCount; i++)
      {
         for(int j = 0; j < nodeCount; j++)
         {
            if (i == j)
            {
               continue;
            }

            if (serverID[i] == serverID[j])
            {
               fail("Connections " + i + " and " + j +
                  " are pointing to the same physical node (" + serverID[i] + ")");
            }
         }
      }
   }

   // Private --------------------------------------------------------------------------------------

   private void drainQueues() throws Exception
   {
      Connection[] conn = new Connection[nodeCount];

      try
      {
         // TODO This is a dangerous hack, relying on an arbitrary distribution algorithm
         // (round-robin in this case). If we want a connection to a specific node, we should be
         // able to look up something like "/ConnectionFactory0"
        
         for(int i = 0; i < nodeCount; i++)
         {
            conn[i] = cf.createConnection();
         }

         // Safety check, making sure we get connections to distinct nodes

         checkConnectionsDifferentServers(conn);

         for(int i = 0; i < nodeCount; i++)
         {
            Session s = conn[i].createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageConsumer c = s.createConsumer(queue[i]);
            conn[i].start();

            Message msg = null;
            do
            {
               msg = c.receive(1000);
               if (msg != null)
               {
                  log.info("Drained message " + msg + " on node " + i);
               }
            }
            while (msg != null);
         }
      }
      finally
      {
         for(int i = 0; i < nodeCount; i++)
         {
            if (conn[i] != null)
            {
               conn[i].close();
            }
         }
      }
   }

   // Inner classes --------------------------------------------------------------------------------
  
   protected class SimpleFailoverListener implements FailoverListener
   {
      private LinkedQueue buffer;

      public SimpleFailoverListener()
      {
         buffer = new LinkedQueue();
      }

      public void failoverEventOccured(FailoverEvent event)
      {
         try
         {
            buffer.put(event);
         }
         catch(InterruptedException e)
         {
            throw new RuntimeException("Putting thread interrupted while trying to add event " +
               "to buffer", e);
         }
      }

      /**
       * Blocks until a FailoverEvent is available or timeout occurs, in which case returns null.
       */
      public FailoverEvent getEvent(long timeout) throws InterruptedException
      {
         return (FailoverEvent)buffer.poll(timeout);
      }
   }

}
TOP

Related Classes of org.jboss.test.messaging.jms.clustering.base.ClusteringTestBase$SimpleFailoverListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.