UnifiedInvokerHAProxypublic class UnifiedInvokerHAProxy extends UnifiedInvokerProxy
Fields Summary |
---|
static final long | serialVersionUID | private org.jboss.ha.framework.interfaces.LoadBalancePolicy | loadBalancePolicy | private String | proxyFamilyName | private org.jboss.ha.framework.interfaces.FamilyClusterInfo | familyClusterInfo | public static final WeakHashMap | txFailoverAuthorizations |
Constructors Summary |
---|
public UnifiedInvokerHAProxy()
super();
log.debug("UnifiedInvokerHAProxy constructor called with no arguments.");
setSubSystem("invokerha");
| public UnifiedInvokerHAProxy(org.jboss.remoting.InvokerLocator locator, boolean isStrictRMIException, ArrayList targets, org.jboss.ha.framework.interfaces.LoadBalancePolicy policy, String proxyFamilyName, long viewId)
super(locator, isStrictRMIException);
this.familyClusterInfo = ClusteringTargetsRepository.initTarget(proxyFamilyName, targets, viewId);
this.loadBalancePolicy = policy;
this.proxyFamilyName = proxyFamilyName;
setSubSystem("invokerha");
|
Methods Summary |
---|
protected org.jboss.remoting.Client | getClient(org.jboss.invocation.Invocation invocationBasedRouting)Gets the remoting client to call on which is selected by the load balancing policy.
If the target InvokerLocator selected is not for the current remoting client, a new one
will be initialized.
Object target = loadBalancePolicy.chooseTarget(familyClusterInfo, invocationBasedRouting);
InvokerLocator targetLocator = (InvokerLocator) target;
// check if load balancer pick the client invoker we already have
if(!getLocator().equals(targetLocator))
{
init(targetLocator);
}
return getClient();
| public void | invocationHasReachedAServer(org.jboss.invocation.Invocation invocation)
javax.transaction.Transaction tx = invocation.getTransaction();
if(tx != null)
{
synchronized(tx)
{
txFailoverAuthorizations.put(tx, null);
}
}
| public java.lang.Object | invoke(org.jboss.invocation.Invocation invocation)
// 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;
invocation.setValue("FAILOVER_COUNTER", new Integer(failoverCounter), PayloadKey.AS_IS);
Object response = null;
Exception lastException = null;
boolean failoverAuthorized = true;
while(familyClusterInfo.getTargets() != null && familyClusterInfo.getTargets().size() > 0 && failoverAuthorized)
{
boolean definitivlyRemoveNodeOnFailure = true;
try
{
invocation.setValue("CLUSTER_VIEW_ID", new Long(this.familyClusterInfo.getCurrentViewId()));
log.debug("Client cluster view id: " + familyClusterInfo.getCurrentViewId());
log.debug(printPossibleTargets());
Client clientInstance = getClient(invocation);
log.debug("Making invocation on " + clientInstance.getInvoker().getLocator());
response = clientInstance.invoke(invocation, null);
HARMIResponse haResponse = null;
if(response instanceof Exception)
{
log.debug("Invocation returened exception: " + response);
if(response instanceof GenericClusteringException)
{
GenericClusteringException gcex = (GenericClusteringException) response;
lastException = gcex;
// 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(gcex.getCompletionStatus() == GenericClusteringException.COMPLETED_NO)
{
// we don't want to remove the node from the list of failed
// node UNLESS there is a risk to indefinitively loop
//
if(totalNumberOfTargets() >= failoverCounter)
{
if(!gcex.isDefinitive())
{
definitivlyRemoveNodeOnFailure = false;
}
}
removeDeadTarget(getLocator());
if(!definitivlyRemoveNodeOnFailure)
{
resetView();
}
failoverAuthorized = txContextAllowsFailover(invocation);
failoverCounter++;
invocation.setValue("FAILOVER_COUNTER", new Integer(failoverCounter), PayloadKey.AS_IS);
log.debug("Received GenericClusteringException where request was not completed. Will retry.");
continue;
}
else
{
invocationHasReachedAServer(invocation);
throw new ServerException("Clustering error", gcex);
}
}
else
{
throw ((Exception) response);
}
}
if (response instanceof IMarshalledValue)
{
haResponse = (HARMIResponse) ((IMarshalledValue) response).get();
}
else
if(response instanceof MarshalledObject)
{
haResponse = (HARMIResponse) ((MarshalledObject) response).get();
}
else
{
haResponse = (HARMIResponse) response;
}
// check for clustered targets
if(haResponse.newReplicants != null)
{
updateClusterInfo(haResponse.newReplicants, haResponse.currentViewId);
}
response = haResponse.response;
return response;
}
catch(CannotConnectException cncEx)
{
log.debug("Invocation failed: CannotConnectException - " + cncEx, cncEx);
removeDeadTarget(getLocator());
resetView();
failoverAuthorized = txContextAllowsFailover(invocation);
failoverCounter++;
invocation.setValue("FAILOVER_COUNTER", new Integer(failoverCounter), PayloadKey.AS_IS);
}
catch(GenericClusteringException gcex)
{
lastException = gcex;
// 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(gcex.getCompletionStatus() == GenericClusteringException.COMPLETED_NO)
{
// we don't want to remove the node from the list of failed
// node UNLESS there is a risk to indefinitively loop
//
if(totalNumberOfTargets() >= failoverCounter)
{
if(!gcex.isDefinitive())
{
definitivlyRemoveNodeOnFailure = false;
}
}
removeDeadTarget(getLocator());
if(!definitivlyRemoveNodeOnFailure)
{
resetView();
}
failoverAuthorized = txContextAllowsFailover(invocation);
failoverCounter++;
invocation.setValue("FAILOVER_COUNTER", new Integer(failoverCounter), PayloadKey.AS_IS);
log.debug("Received GenericClusteringException where request was not completed. Will retry.");
}
else
{
invocationHasReachedAServer(invocation);
throw new ServerException("Clustering error", gcex);
}
}
catch(RemoteException aex)
{
log.debug("Invocation failed: RemoteException - " + aex, aex);
// per Jira issue JBREM-61
if(isStrictRMIException())
{
throw new ServerException(aex.getMessage(), aex);
}
else
{
throw aex;
}
}
catch(Throwable throwable)
{
log.debug("Invocation failed: " + throwable, throwable);
// this is somewhat of a hack as remoting throws throwable,
// so will let Exception types bubble up, but if Throwable type,
// then have to wrap in new Exception, as this is the signature
// of this invoke method.
if(throwable instanceof Exception)
{
throw (Exception) throwable;
}
throw new Exception(throwable);
}
}
if(failoverAuthorized == false)
{
throw new ServiceUnavailableException("Service unavailable (failover not possible inside a user transaction) for " +
invocation.getObjectName() + " calling method " + invocation.getMethod(),
lastException);
}
else
{
throw new ServiceUnavailableException("Service unavailable for " +
invocation.getObjectName() + " calling method " + invocation.getMethod(),
lastException);
}
| private java.lang.Object | printPossibleTargets()
StringBuffer buffer = new StringBuffer();
if(familyClusterInfo != null)
{
List possibleTargets = familyClusterInfo.getTargets();
if(possibleTargets != null && possibleTargets.size() > 0)
{
for(int x = 0; x < possibleTargets.size(); x++)
{
buffer.append("\nPossible target " + (x + 1) + ": " + possibleTargets.get(x));
}
}
}
return buffer.toString();
| public void | readExternal(java.io.ObjectInput in)Un-externalize this instance.
int version = in.readInt();
// Read in and map the version of the serialized data seen
switch(version)
{
case VERSION_5_0:
setLocator(new InvokerLocator(in.readUTF()));
setStrictRMIException(in.readBoolean());
init(getLocator());
ArrayList targets = (ArrayList) in.readObject();
this.loadBalancePolicy = (LoadBalancePolicy) in.readObject();
this.proxyFamilyName = (String) in.readObject();
long vid = in.readLong();
// keep a reference on our family object
//
this.familyClusterInfo = ClusteringTargetsRepository.initTarget(this.proxyFamilyName, targets, vid);
break;
default:
throw new StreamCorruptedException("Unknown version seen: " + version);
}
| private void | removeDeadTarget(org.jboss.remoting.InvokerLocator locator)
if(locator != null)
{
if(this.familyClusterInfo != null)
{
familyClusterInfo.removeDeadTarget(locator);
log.debug("Removed " + locator + " from target list.");
}
}
| protected void | resetView()
this.familyClusterInfo.resetView();
| protected int | totalNumberOfTargets()
if(this.familyClusterInfo != null)
{
return this.familyClusterInfo.getTargets().size();
}
else
{
return 0;
}
| public boolean | txContextAllowsFailover(org.jboss.invocation.Invocation invocation)
javax.transaction.Transaction tx = invocation.getTransaction();
if(tx != null)
{
synchronized(tx)
{
return ! txFailoverAuthorizations.containsKey(tx);
}
}
else
{
return true;
}
| private void | updateClusterInfo(java.util.ArrayList newReplicants, long currentViewId)
if(familyClusterInfo != null)
{
familyClusterInfo.updateClusterInfo(newReplicants, currentViewId);
log.debug("Updating cluster info. New view id: " + currentViewId);
log.debug("New cluster target list is:");
for(int x = 0; x < newReplicants.size(); x++)
{
log.debug(newReplicants.get(x));
}
}
| public void | writeExternal(java.io.ObjectOutput out)Externalize this instance and handle obtaining the remoteInvoker stub
out.writeInt(CURRENT_VERSION);
out.writeUTF(getLocator().getOriginalURI());
out.writeBoolean(isStrictRMIException());
// JBAS-2071 - sync on FCI to ensure targets and vid are consistent
ArrayList targets = null;
long vid = 0;
synchronized (this.familyClusterInfo)
{
targets = this.familyClusterInfo.getTargets ();
vid = this.familyClusterInfo.getCurrentViewId ();
}
out.writeObject(targets);
out.writeObject(this.loadBalancePolicy);
out.writeObject(this.proxyFamilyName);
out.writeLong(vid);
|
|