Package org.jboss.ha.framework.server

Source Code of org.jboss.ha.framework.server.HATarget

/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* 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.ha.framework.server;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
import org.jboss.ha.framework.interfaces.DistributedReplicantManager.ReplicantListener;
import org.jboss.ha.framework.interfaces.HAPartition;
import org.jboss.logging.Logger;
import java.io.Serializable;

/**
* Control point representing a clustered service. Works with the
* {@link DistributedReplicantManager} to makes available a
* {@link #getReplicants() list of replicants} (objects used to identify remote
* service endpoints around the cluster) for the service. Guards access to the
* service via the {@link #invocationsAllowed()} and
* {@link #setInvocationsAuthorization(int)} methods.
*
* @author bill@burkecentral.com
* @version $Revision: 74879 $
*
* <p><b>Revisions:</b><br>
* <p><b>2002/01/13: Bill Burke</b>
* <ol>
*   <li>Initial revision
* </ol>
*/
public class HATarget
   implements ReplicantListener
{
   /**
    * Argument to {@link #setInvocationsAuthorization(int)} that indicates
    * {@link #invocationsAllowed()} should return <code>false</code>.
    */
   public static final int DISABLE_INVOCATIONS = 0;
   /**
    * Argument to {@link #setInvocationsAuthorization(int)} that indicates
    * calls to {@link #invocationsAllowed()} should block until a different
    * value is passed to {@link #setInvocationsAuthorization(int)}.
    */
   public static final int MAKE_INVOCATIONS_WAIT = 1;
   /**
    * Argument to {@link #setInvocationsAuthorization(int)} that indicates
    * {@link #invocationsAllowed()} should return <code>true</code>.
    */
   public static final int ENABLE_INVOCATIONS = 2;
  
   protected String replicantName;
   protected ArrayList replicants = new ArrayList();
   protected HAPartition partition = null;
   protected Logger log;
   protected int clusterViewId = 0;
   protected Serializable target;
   protected int allowInvocationsStatus = 0;
   protected CountDownLatch latch = null;
  
   /**
    * Creates a new HATarget.
    *
    * @param partition the {@link HAPartition} for the service's cluster
    * @param replicantName the name of the service
    * @param target        the service's {@link #getReplicants() replicant}
    * @param allowInvocations <code>true</code> if {@link #invocationsAllowed()}
    *                         should return <code>true</code> immediately;
    *                         <code>false</code> if not
    * @throws Exception
    */
   public HATarget(HAPartition partition,
       String replicantName,
       Serializable target,
         int allowInvocations)
      throws Exception
   {
      this.replicantName = replicantName;     
      this.target = target;     
      init ();
      setInvocationsAuthorization (allowInvocations);
      updateHAPartition(partition);
   }

   public String toString()
   {
      StringBuffer buffer = new StringBuffer(super.toString());
      buffer.append('{');
      buffer.append("replicantName="+replicantName);
      buffer.append("partition="+partition.getPartitionName());
      buffer.append("clusterViewId="+clusterViewId);
      buffer.append("allowInvocationsStatus="+allowInvocationsStatus);
      buffer.append("replicants="+replicants);
      buffer.append('}');
      return buffer.toString();
   }

   /**
    * Gets the current
    * {@link DistributedReplicantManager#getReplicantsViewId(String) view id}
    * for the clustered service.
    */
   public long getCurrentViewId()
   {
      return (long)clusterViewId;
   }
  
   /**
    * Removes the local node from the distributed registry of nodes providing
    * the service and causes {@link #invocationsAllowed()} to return
    * <code>false</code>.
    */
   public void destroy()
   {
      try
      {
         this.cleanExistenceInCurrentHAPartition();
        
         // maybe some threads are blocked: we let them go here:
         //
         setInvocationsAuthorization (HATarget.DISABLE_INVOCATIONS);
      }
      catch (Exception e)
      {
         log.error("failed to destroy", e);
      }
   }
   /**
    * Removes the local node from the distributed registry of nodes providing
    * the service. After this call, the HATarget can still be queried for
    * view change, etc. but the local node's instance of the service  is no
    * longer registered with the cluster.
    * <p>
    * <strong>NOTE:</strong> Calling this method does not cause
    * {@link #invocationsAllowed()} to return <code>false</code>. Use
    * {@link #destroy()} unless your application needs to separately control
    * the two aspects of shutting down a clustered service.
    */
   public void disable()
   {
      try
      {
         if (this.partition != null)
         {
            log.debug ("Disabled called on HATarget");
            this.partition.getDistributedReplicantManager().remove (this.replicantName);        
         }     
      }
      catch (Exception e)
      {
         log.error("failed to disable", e);
      }
   }
  
   /**
    * Gets the replicants for the clustered service. A <code>replicant</code>
    * is a service-specific object, typically something that represents a
    * remote service endpoint for the service on a particular cluster node.
    * Examples include an RMI stub, a JBoss Remoting <code>InvokerLocator</code>
    * or an HTTP URL.
    */
   public ArrayList getReplicants()
   {
      return replicants;
   }

   /**
    * Sets the behavior expected from {@link #invocationsAllowed()}.
    *
    * @param status {@link #ENABLE_INVOCATIONS}, {@link #DISABLE_INVOCATIONS}
    *               or {@link #MAKE_INVOCATIONS_WAIT}
    */
   public synchronized void setInvocationsAuthorization (int status)
   {
      if (this.allowInvocationsStatus == status)
      {
         // we don't release and reget a latch if two identical calls are performed
         //
         log.debug ("Invocation authorization called with no-op");
      }
      else
      {
         // CRITICAL CODE! DONT CHANGE ORDER WITHOUT THINKING ABOUT RACE CONDITIONS
         //
         if (status == MAKE_INVOCATIONS_WAIT)
         {
            log.debug ("Invocation authorization called: MAKE_INVOCATIONS_WAIT");
            latch = new CountDownLatch(1);
            this.allowInvocationsStatus = status;
         }
         else
         {
            log.debug ("Invocation authorization called: " +
               ((status==ENABLE_INVOCATIONS)?"ENABLE_INVOCATIONS":"DISABLE_INVOCATIONS") );
            this.allowInvocationsStatus = status;
            releaseCurrentLatch();
         }        
      }
   }
  
   /**
    * Returns whether invocations on the target service are currently allowed
    * on this node.  Will block if {@link #setInvocationsAuthorization(int)} has
    * been set to {@link #MAKE_INVOCATIONS_WAIT}.
    *
    * @return <code>true</code>e if it is valid to make invocations on the
    *         service, <code>false</code> otherwise
    * @throws InterruptedException if the current thread is interrupted while
    *                              blocking waiting for {@link #MAKE_INVOCATIONS_WAIT}
    *                             
    */
   public boolean invocationsAllowed () throws InterruptedException
   {
      if (this.allowInvocationsStatus == ENABLE_INVOCATIONS)
         return true;
      else if (this.allowInvocationsStatus == DISABLE_INVOCATIONS)
         return false;
      else if (this.allowInvocationsStatus == MAKE_INVOCATIONS_WAIT)
      {
         if (log.isTraceEnabled())
            log.trace("Blocking invocation for service " + replicantName);
        
         latch.await();
        
         // if we arrive here, it means that the status has been changed, so
         // we check for the decision:
         //
         if (this.allowInvocationsStatus == ENABLE_INVOCATIONS)
            return true;
         else
            return false;        
      }   
      else
         return false;
   }
  
   public HAPartition getAssociatedPartition ()
   {
       return this.partition;
   }
  
   // DistributedReplicantManager.ReplicantListener implementation ------------
     
   public void replicantsChanged(String key, List newReplicants, int newReplicantsViewId, boolean merge)
   {
      log.debug("replicantsChanged '" + replicantName +
                "' to " + (newReplicants==null? "0 (null)" : Integer.toString (newReplicants.size() ) ) +
                " (intra-view id: " + newReplicantsViewId + ")");
     
      synchronized(replicants)
      {
         // client has reference to replicants so it will automatically get
         // updated
         replicants.clear();
         if (newReplicants != null)
            replicants.addAll(newReplicants);
        
         this.clusterViewId = newReplicantsViewId;
      }
     
   }
  
   /**
    * Allows subclasses to perform initialization work.
    *
    * @throws Exception
    * @deprecated this will be removed in the next major release
    */
   @Deprecated protected void init() throws Exception
   {
      this.log = Logger.getLogger(this.getClass());
   }
  
   /**
    * Associates this target with the given partition, registering
    * with the partition's {@link DistributedReplicantManager}.
    *
    * @param partition the partition
    * @throws Exception
    */
   protected void updateHAPartition(HAPartition partition) throws Exception
   {
      cleanExistenceInCurrentHAPartition();
     
      this.partition = partition;
      DistributedReplicantManager drm = partition.getDistributedReplicantManager();
      drm.registerListener(this.replicantName, this);
      drm.add(this.replicantName, this.target);
   }
  
   /**
    * Unregister's with the partition's {@link DistributedReplicantManager}.
    */
   protected void cleanExistenceInCurrentHAPartition()
   {
      if (this.partition != null)
      {
         try
         {
            DistributedReplicantManager drm = partition.getDistributedReplicantManager();
            drm.unregisterListener(this.replicantName, this);
            drm.remove(this.replicantName);        
         }
         catch (Exception e)
         {
            log.error("failed to clean existence in current ha partition", e);
         }
      }   
   }
  
   /**
    * Releases any latch blocking threads in {@link #invocationsAllowed()}.
    */
   protected void releaseCurrentLatch ()
   {
      if (latch != null)
      {
         latch.countDown();
         latch = null;
      }
   }
}
TOP

Related Classes of org.jboss.ha.framework.server.HATarget

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.