Package org.jboss.jms.client

Source Code of org.jboss.jms.client.FailoverCommandCenter

/**
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.jms.client;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jboss.jms.client.delegate.ClientConnectionDelegate;
import org.jboss.jms.client.remoting.JMSRemotingConnection;
import org.jboss.jms.client.state.ConnectionState;
import org.jboss.jms.delegate.ConnectionFactoryDelegate;
import org.jboss.jms.server.endpoint.CreateConnectionResult;
import org.jboss.logging.Logger;

/**
* The class in charge with performing the failover.
*
* @author <a href="mailto:ovidiu@jboss.org">Ovidiu Feodorov</a>
* @version <tt>$Revision: 2485 $</tt>
*
* $Id: FailoverCommandCenter.java 2485 2007-02-28 02:30:33Z ovidiu.feodorov@jboss.com $
*/
public class FailoverCommandCenter
{
   // Constants ------------------------------------------------------------------------------------

   private static final Logger log = Logger.getLogger(FailoverCommandCenter.class);

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

   private static boolean trace = log.isTraceEnabled();

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

   private ConnectionState state;

   private FailoverValve2 valve;

   private List failoverListeners;
  
   // Constructors ---------------------------------------------------------------------------------

   public FailoverCommandCenter(ConnectionState state)
   {
      this.state = state;
      failoverListeners = new ArrayList();
     
      valve = new FailoverValve2();
   }

   // Public ---------------------------------------------------------------------------------------
  
   public void setState(ConnectionState state)
   {
      this.state = state;
   }
  
   /**
    * Method called by failure detection components (FailoverValveInterceptors and
    * ConnectionListeners) when they have reasons to believe that a server failure occured.
    */
   public void failureDetected(Throwable reason, FailureDetector source,
                               JMSRemotingConnection remotingConnection)
      throws Exception
   {
      log.debug("failure detected by " + source);

      // generate a FAILURE_DETECTED event
      broadcastFailoverEvent(new FailoverEvent(FailoverEvent.FAILURE_DETECTED, source));

      CreateConnectionResult res = null;
      boolean failoverSuccessful = false;
     
      boolean valveOpened = false;
     
      try
      {
         // block any other invocations ariving to any delegate from the hierarchy while we're
         // doing failover

         valve.close();
        
         synchronized(this)
         {
            // testing for failed connection and setting the failed flag need to be done in one
            // atomic operation, otherwise multiple threads can get to perform the client-side
            // failover concurrently
            if (remotingConnection.isFailed())
            {
               log.debug(this + " ignoring failure detection notification, as failover was " +
                  "already (or is in process of being) performed on this connection");
               return;
            }

            remotingConnection.setFailed();
         }
        
         // Note - failover doesn't occur until _after_ the above check - so the next comment
         // belongs here
         log.debug(this + " starting client-side failover");
        
         // generate a FAILOVER_STARTED event. The event must be broadcasted AFTER valve closure,
         // to insure the client-side stack is in a deterministic state
         broadcastFailoverEvent(new FailoverEvent(FailoverEvent.FAILOVER_STARTED, this));       
        
         int failedNodeID = state.getServerID();
         ConnectionFactoryDelegate clusteredDelegate =
            state.getClusteredConnectionFactoryDelegate();
        
         // re-try creating the connection
         res = clusteredDelegate.
            createConnectionDelegate(state.getUsername(), state.getPassword(), failedNodeID);
        
         if (res == null)
         {
            // No failover attempt was detected on the server side; this might happen if the
            // client side network fails temporarily so the client connection breaks but the
            // server cluster is still up and running - in this case we don't perform failover.
            failoverSuccessful = false;
         }
         else
         {     
            // recursively synchronize state
            ClientConnectionDelegate newDelegate = (ClientConnectionDelegate)res.getDelegate();
           
            state.getDelegate().synchronizeWith(newDelegate);
                          
            valve.open();
            valveOpened = true;
           
            //Now start the connection - note! this can't be done while the valve is closed
            //or it will block itself
           
            // start the connection again on the serverEndpoint if necessary
            if (state.isStarted())
            {
               newDelegate.start();
            }
           
            failoverSuccessful = true;                       
         }
      }
      catch (Exception e)
      {
         log.error("Failover failed", e);
        
         throw e;
      }
      finally
      {
         if (!valveOpened)
         {
            valve.open();
         }

         if (failoverSuccessful)
         {
            log.debug(this + " completed successful failover");
            broadcastFailoverEvent(new FailoverEvent(FailoverEvent.FAILOVER_COMPLETED, this));
         }
         else
         {
            log.debug(this + " aborted failover");
            broadcastFailoverEvent(new FailoverEvent(FailoverEvent.FAILOVER_FAILED, this));
         }
      }
   }

   public void registerFailoverListener(FailoverListener listener)
   {
      synchronized(failoverListeners)
      {
         failoverListeners.add(listener);
      }
   }

   public boolean unregisterFailoverListener(FailoverListener listener)
   {
      synchronized(failoverListeners)
      {
         return failoverListeners.remove(listener);
      }
   }

   public FailoverValve2 getValve()
   {
      return valve;
   }

   public JMSRemotingConnection getRemotingConnection()
   {
      return state.getRemotingConnection();
   }

   public String toString()
   {
      return "FailoverCommandCenter[" + state + "]";
   }

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

   ConnectionState getConnectionState()
   {
      return state;
   }

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

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

   private void broadcastFailoverEvent(FailoverEvent e)
   {
      if (trace) { log.trace(this + " broadcasting " + e); }

      List listenersCopy;

      synchronized(failoverListeners)
      {
         listenersCopy = new ArrayList(failoverListeners);
      }

      for(Iterator i = listenersCopy.iterator(); i.hasNext(); )
      {
         FailoverListener listener = (FailoverListener)i.next();

         try
         {
            listener.failoverEventOccured(e);
         }
         catch(Exception ex)
         {
            log.warn("Failover listener " + listener + " did not accept event", ex);
         }
      }
   }

   // Inner classes --------------------------------------------------------------------------------
}
TOP

Related Classes of org.jboss.jms.client.FailoverCommandCenter

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.