Package org.jboss.ha.framework.server

Source Code of org.jboss.ha.framework.server.HASingletonImpl$RecordingReplicantListener

/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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.ha.framework.server;

import java.util.EventObject;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import org.jboss.ha.framework.interfaces.ClusterNode;
import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
import org.jboss.ha.framework.interfaces.HASingleton;
import org.jboss.ha.framework.interfaces.HASingletonElectionPolicy;
import org.jboss.ha.framework.interfaces.HASingletonLifecycle;

/**
* Base class for HA-singleton based services.
*
* @author Paul Ferraro
*/
public class HASingletonImpl<E extends EventObject> extends HAServiceImpl<E> implements HASingleton<E>, HASingletonRpcHandler<E>
{
   private final AtomicBoolean master = new AtomicBoolean(false);
   private final HASingletonRpcHandler<E> rpcHandler = new RpcHandler();
   private final HASingletonLifecycle singletonLifecycle;

   AtomicReference<ReplicantView> viewReference = new AtomicReference<ReplicantView>();
  
   private volatile HASingletonElectionPolicy electionPolicy;
   private volatile boolean restartOnMerge = true;
  
   public HASingletonImpl(EventFactory<E> eventFactory, EventFacility<E> eventHandler, HASingletonLifecycle singletonLifecycle)
   {
      super(eventFactory, eventHandler);
     
      this.singletonLifecycle = singletonLifecycle;
   }
  
   public HASingletonImpl(EventFactory<E> eventFactory)
   {
      super(eventFactory);
     
      this.singletonLifecycle = this;
   }
  
   @Override
   public HASingletonElectionPolicy getElectionPolicy()
   {
      return this.electionPolicy;
   }
  
   @Override
   public void setElectionPolicy(HASingletonElectionPolicy electionPolicy)
   {
      this.electionPolicy = electionPolicy;
   }
  
   @Override
   public boolean getRestartOnMerge()
   {
      return this.restartOnMerge;
   }
  
   @Override
   public void setRestartOnMerge(boolean restart)
   {
      this.restartOnMerge = restart;
   }
  
   @Override
   public boolean isMasterNode()
   {
      return this.master.get();
   }
  
   /**
    * @{inheritDoc}
    * Overridden to circumvent deadlock in the unlikely scenario that the view changes between
    * drm listener registration and drm replicant addition.  See JBAS-2647 for details.
    * @see org.jboss.ha.framework.server.HAServiceImpl#registerDRMListener()
    */
   @Override
   protected void registerDRMListener() throws Exception
   {
      if (log.isDebugEnabled())
      {
         log.debug("HASingletonImpl.registerDRMListener for service=" + getHAServiceKey());
      }

      DistributedReplicantManager drm = this.getHAPartition().getDistributedReplicantManager();
     
      // Temporary drm listener
      RecordingReplicantListener listener = new RecordingReplicantListener();
     
      String key = this.getHAServiceKey();

      // record replicant changes, but don't handle them just yet
      drm.registerListener(key, listener);

      // this ensures that the DRM knows that this node has the singleton deployed
      drm.add(key, this.getReplicant());
     
      // Now register the real listener
      drm.registerListener(key, this);
     
      // ...and unregister our temporary one
      drm.unregisterListener(key, listener);
     
      ReplicantView view = this.viewReference.getAndSet(null);
     
      // Process the recorded replicant change
      // Typically this will be the replicant change from drm.add(...)
      if (view != null)
      {
         this.partitionTopologyChanged(view.getReplicants(), view.getId(), view.isMerge());
      }
   }
  
   /**
    * @see org.jboss.ha.framework.interfaces.HASingletonLifecycle#startSingleton()
    */
   @Override
   public void startSingleton()
   {
      this.log.debug("startSingleton() : elected for master singleton node");
   }

   /**
    * @see org.jboss.ha.framework.interfaces.HASingletonLifecycle#stopSingleton()
    */
   @Override
   public void stopSingleton()
   {
      this.log.debug("stopSingleton() : another node in the partition (if any) is elected for master");
   }

   /**
    * When topology changes, a new master is elected based on the result
    * of the isDRMMasterReplica() call.
    *
    * @see org.jboss.ha.framework.server.HAServiceImpl#partitionTopologyChanged(java.util.List, int, boolean)
    * @see org.jboss.ha.framework.interfaces.DistributedReplicantManager#isMasterReplica(String)
    */
   @Override
   protected void partitionTopologyChanged(List<?> newReplicants, int newViewId, boolean merge)
   {
      ReplicantView view = this.viewReference.getAndSet(null);
     
      // Pre-process any recorded replicant changes
      if (view != null)
      {
         this.partitionTopologyChanged(view.getReplicants(), view.getId(), view.isMerge());
      }
     
      boolean isElectedNewMaster = this.elected();
     
      boolean isMaster = this.master.get();

      if( log.isDebugEnabled())
      {

         this.log.debug("partitionTopologyChanged, isElectedNewMaster=" + isElectedNewMaster + ", isMasterNode=" +
            isMaster + ", viewID=" + newViewId + ", partition=" + getHAPartition().getPartitionName()
            );
      }
     
      if (isElectedNewMaster)
      {
         // if this node is already the master, don't bother electing it again
         if (isMaster)
         {
            // JBAS-4229
            if (this.restartOnMerge && merge)
            {
               this.restartMaster();
            }
         }
         // just becoming master
         else
         {
            this.makeThisNodeMaster();
         }
      }
      // transition from master to slave
      else if (isMaster)
      {
         this.stopIfMaster();
      }
   }

   private boolean elected()
   {
      boolean result;
      if (this.electionPolicy == null)
      {
         result = this.isDRMMasterReplica();
      }
      else {
         ClusterNode electedNode = this.election();
         result = (electedNode != null) ? electedNode.equals(this.getHAPartition().getClusterNode()) : false;
      }
      if( log.isDebugEnabled())
      {
         log.debug("election result =" + result + ", electionPolicy=" +
         (electionPolicy != null? electionPolicy.getClass().getName():"DistributedReplicantManager"));
      }
      return result;
   }
  
   private ClusterNode election()
   {
      List<ClusterNode> candidates = this.getElectionCandidates();
     
      if ((candidates == null) || candidates.isEmpty()) return null;
     
      return (candidates.size() == 1) ? candidates.get(0) : this.electionPolicy.elect(candidates);
   }
  
   protected List<ClusterNode> getElectionCandidates()
   {
      return this.getHAPartition().getDistributedReplicantManager().lookupReplicantsNodes(this.getHAServiceKey());
   }
  
   /**
    * @see org.jboss.ha.singleton.HASingleton.RpcHandler#stopOldMaster()
    */
   @Override
   public void stopOldMaster() throws Exception
   {
      // ovidiu 09/02/04 - temporary solution for Case 1843, use an asynchronous
      // distributed call.
      //callMethodOnPartition("_stopOldMaster", new Object[0], new Class[0]);
      this.callAsyncMethodOnPartition("stopOldMaster", new Object[0], new Class[0]);
   }

   protected boolean isDRMMasterReplica()
   {
      DistributedReplicantManager drm = this.getHAPartition().getDistributedReplicantManager();

      return drm.isMasterReplica(this.getHAServiceKey());
   }
  
   protected void makeThisNodeMaster()
   {
      try
      {
         // stop the old master (if there is one) before starting the new one
         this.stopOldMaster();

         this.startNewMaster();
      }
      catch (Exception ex)
      {
         this.log.error("stopOldMaster failed. New master singleton will not start.", ex);

         ex.printStackTrace(System.err);
      }
   }
  
   protected void startNewMaster()
   {
      this.log.debug("startNewMaster, isMasterNode=" + this.master);
     
      this.master.set(true);
     
      // notify starting
      this.sendLocalEvent(HASINGLETON_STARTING_NOTIFICATION);

      // start new master
      this.singletonLifecycle.startSingleton();
     
      // notify started
      this.sendLocalEvent(HASINGLETON_STARTED_NOTIFICATION);
   }
  
   protected void restartMaster()
   {
      this.stopIfMaster();
      this.startNewMaster();
   }

   protected void stopIfMaster()
   {
      this.log.debug("stopIfMaster, isMasterNode=" + this.master.get());
     
      try
      {
         // since this is a cluster call, all nodes will hear it
         // so if the node is not the master, then ignore
         if (this.master.compareAndSet(true, false))
         {
            // notify stopping
            this.sendLocalEvent(HASINGLETON_STOPPING_NOTIFICATION);
           
            // stop the singleton
            this.singletonLifecycle.stopSingleton();
           
            // notify stopped
            this.sendLocalEvent(HASINGLETON_STOPPED_NOTIFICATION);
         }
      }
      catch (Exception ex)
      {
         this.log.error("stopIfMaster failed. Will still try to start new master. " +
            "You need to examine the reason why the old master wouldn't stop and resolve it. " +
            "It is bad that the old singleton may still be running while we are starting a new one, " +
            "so you need to resolve this ASAP.", ex);
      }
   }

   private void sendLocalEvent(String type)
   {
      E event = this.getEventFactory().createEvent(this, type);
     
      try
      {
         this.getEventFacility().notifyListeners(event);
      }
      catch (Exception e)
      {
         this.log.warn("Failed to send local event: " + event, e);
      }
   }
  
   @Override
   protected HAServiceRpcHandler<E> getRpcHandler()
   {
      return this.rpcHandler;
   }
  
   protected class RpcHandler extends HAServiceImpl<E>.RpcHandler implements HASingletonRpcHandler<E>
   {
      /**
       * @see org.jboss.ha.singleton.HASingleton.RpcHandler#stopOldMaster()
       */
      @Override
      public void stopOldMaster()
      {
         HASingletonImpl.this.stopIfMaster();
      }
   }
  
   private static class ReplicantView
   {
      private List<?> replicants;
      private int id;
      private boolean merge;
     
      public ReplicantView(List<?> replicants, int viewId, boolean merge)
      {
         this.replicants = replicants;
         this.id = viewId;
         this.merge = merge;
      }
     
      public List<?> getReplicants()
      {
         return this.replicants;
      }
     
      public int getId()
      {
         return this.id;
      }
     
      public boolean isMerge()
      {
         return this.merge;
      }
   }
  
   class RecordingReplicantListener implements DistributedReplicantManager.ReplicantListener
   {
      @Override
      public void replicantsChanged(String key, List<?> newReplicants, int newReplicantsViewId, boolean merge)
      {
         if (HASingletonImpl.this.getHAServiceKey().equals(key))
         {
            // Record replicant change - overwriting any previously recorded view
            HASingletonImpl.this.viewReference.set(new ReplicantView(newReplicants, newReplicantsViewId, merge));
         }
      }
   }
}
TOP

Related Classes of org.jboss.ha.framework.server.HASingletonImpl$RecordingReplicantListener

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.