FileDocCategorySizeDatePackage
HttpInvokerProxyHA.javaAPI DocJBoss 4.2.110180Fri Jul 13 20:52:38 BST 2007org.jboss.invocation.http.interfaces

HttpInvokerProxyHA

public class HttpInvokerProxyHA extends Object implements org.jboss.invocation.InvokerProxyHA, org.jboss.invocation.Invoker, Externalizable
The client side Http invoker proxy that posts an invocation to the InvokerServlet using the HttpURLConnection created from a target url. This proxy handles failover using its associated LoadBalancePolicy and current list of URL strings. The candidate URLs are updated dynamically after an invocation if the cluster partitation view has changed.
author
Scott.Stark@jboss.org
version
$Revision: 57188 $

Fields Summary
private static Logger
log
private static final long
serialVersionUID
Serial Version Identifier.
protected org.jboss.ha.framework.interfaces.LoadBalancePolicy
loadBalancePolicy
protected String
proxyFamilyName
protected org.jboss.ha.framework.interfaces.FamilyClusterInfo
familyClusterInfo
protected transient boolean
trace
Trace level logging flag only set when the proxy is created or read from JNDI
Constructors Summary
public HttpInvokerProxyHA()


   // Constructors --------------------------------------------------
    
   
      // For externalization to work
   
public HttpInvokerProxyHA(ArrayList targets, long viewId, org.jboss.ha.framework.interfaces.LoadBalancePolicy policy, String proxyFamilyName)

param
targets the list of URLs through which clients should contact the InvokerServlet.
param
policy the policy for choosing among targets ClusteringTargetsRepository under which this proxy is to be stored
param
proxyFamilyName the name into the

      this.familyClusterInfo = ClusteringTargetsRepository.initTarget (proxyFamilyName, targets, viewId);
      this.loadBalancePolicy = policy;
      this.proxyFamilyName = proxyFamilyName;
      this.trace = log.isTraceEnabled();
      if( trace )
         log.trace("Init, cluterInfo: "+familyClusterInfo+", policy="+loadBalancePolicy);
   
Methods Summary
public org.jboss.ha.framework.interfaces.FamilyClusterInfogetClusterInfo()

      return familyClusterInfo;
   
public java.lang.ObjectgetRemoteTarget()

      return getRemoteTarget(null);
   
public java.lang.ObjectgetRemoteTarget(org.jboss.invocation.Invocation invocationBasedRouting)

      Object target = loadBalancePolicy.chooseTarget(this.familyClusterInfo, invocationBasedRouting);
      if( trace )
         log.trace("Choose remoteTarget: "+target);
      return target;
   
public java.lang.StringgetServerHostName()

      return null;
   
public java.lang.Objectinvoke(org.jboss.invocation.Invocation invocation)
This method builds a MarshalledInvocation from the invocation passed in and then does a post to the target URL.

      // we give the opportunity, to any server interceptor, to know if this a
      // first invocation to a node or if it is a failovered call
      //
      int failoverCounter = 0;

      // We are going to go through a Remote invocation, switch to a Marshalled Invocation
      MarshalledInvocation mi = new MarshalledInvocation(invocation);         
      mi.setValue("CLUSTER_VIEW_ID", new Long(familyClusterInfo.getCurrentViewId()));
      String target = (String) getRemoteTarget(invocation);
      URL externalURL = Util.resolveURL(target);
      Exception lastException = null;
      while( externalURL != null )
      {
         boolean definitivlyRemoveNodeOnFailure = true;
         invocation.setValue("FAILOVER_COUNTER", new Integer(failoverCounter), PayloadKey.AS_IS);
         try
         {
            if( trace )
               log.trace("Invoking on target="+externalURL);
            Object rtn = Util.invoke(externalURL, mi);
            HARMIResponse rsp = (HARMIResponse) rtn;

            if (rsp.newReplicants != null)
               updateClusterInfo(rsp.newReplicants, rsp.currentViewId);
            return rsp.response;
         }
         catch(GenericClusteringException e)
         {
            // this is a generic clustering exception that contain the
            // completion status: usefull to determine if we are authorized
            // to re-issue a query to another node
            //               
            if( e.getCompletionStatus() != e.COMPLETED_NO )
            {
                  // we don't want to remove the node from the list of targets 
                  // UNLESS there is a risk to loop
                  if (totalNumberOfTargets() >= failoverCounter)
                  {
                     if( e.isDefinitive() == false )
                        definitivlyRemoveNodeOnFailure = false;                     
                  }
            }
            else
            {
               throw new ServerException("Cannot proceed beyond target="+externalURL, e);
            }
         }
         catch(InvocationException e)
         {
            // Handle application declared exceptions
            Throwable cause = e.getTargetException();
            if( cause instanceof Exception )
               throw (Exception) cause;
            else if (cause instanceof Error)
               throw (Error) cause;
            throw new InvocationTargetException(cause);
         }
         catch(IOException e)
         {
            if( trace )
               log.trace("Invoke failed, target="+externalURL, e);
            lastException = e;
         }
         catch(Exception e)
         {
            // Rethrow for the application to handle
            throw e;
         }

         // If we reach here, this means that we must fail-over
         remoteTargetHasFailed(target);
         if( definitivlyRemoveNodeOnFailure )
            resetView();
         target = (String) getRemoteTarget(invocation);
         externalURL = Util.resolveURL(target);
         failoverCounter ++;
      }
      // if we get here this means list was exhausted
      throw new ServerException("Service unavailable last exception:", lastException);
   
public voidreadExternal(java.io.ObjectInput in)
Un-externalize this instance.

      ArrayList targets = (ArrayList) in.readObject();
      long vid = in.readLong ();
      this.loadBalancePolicy = (LoadBalancePolicy) in.readObject();
      this.proxyFamilyName = (String)in.readObject();
      this.trace = log.isTraceEnabled();

      // keep a reference on our family object
      this.familyClusterInfo = ClusteringTargetsRepository.initTarget(this.proxyFamilyName, targets, vid);
      if( trace )
         log.trace("Init, clusterInfo: "+familyClusterInfo+", policy="+loadBalancePolicy);
   
public voidremoteTargetHasFailed(java.lang.Object target)

      removeDeadTarget(target);
   
protected voidremoveDeadTarget(java.lang.Object target)

      if( familyClusterInfo != null )
      {
         ArrayList targets = familyClusterInfo.removeDeadTarget(target);
         if( trace )
         {
            log.trace("removeDeadTarget("+target+"), targets.size="+targets.size());
         }
      }
   
protected voidresetView()

      familyClusterInfo.resetView();
   
protected inttotalNumberOfTargets()

      int size = 0;
      if( familyClusterInfo != null )
         size = familyClusterInfo.getTargets().size();
      return size;
   
public voidupdateClusterInfo(java.util.ArrayList targets, long viewId)

      if (familyClusterInfo != null)
         this.familyClusterInfo.updateClusterInfo (targets, viewId);
   
public voidwriteExternal(java.io.ObjectOutput out)
Externalize this instance.

 
      // JBAS-2071 - sync on FCI to ensure targets and vid are consistent
      ArrayList currentTargets = null;
      long vid = 0;
      synchronized (this.familyClusterInfo)
      {
         currentTargets = this.familyClusterInfo.getTargets ();
         vid = this.familyClusterInfo.getCurrentViewId ();
      }
      out.writeObject(currentTargets);
      out.writeLong(vid);
      out.writeObject(this.loadBalancePolicy);
      out.writeObject(this.proxyFamilyName);