[jboss-cvs] JBossAS SVN: r71091 - in branches/JBPAPP_4_2_0_GA_CP: cluster/src/main/org/jboss/ha/jndi and 1 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Mar 20 14:52:19 EDT 2008
Author: bstansberry at jboss.com
Date: 2008-03-20 14:52:19 -0400 (Thu, 20 Mar 2008)
New Revision: 71091
Modified:
branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/framework/interfaces/HARMIClient.java
branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/jndi/HANamingService.java
branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/interfaces/NamingContext.java
Log:
[JBPAPP-653] RMI Client Doesn't Always Immediately Recover After Complete Cluster Shutdown
Modified: branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/framework/interfaces/HARMIClient.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/framework/interfaces/HARMIClient.java 2008-03-20 17:57:59 UTC (rev 71090)
+++ branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/framework/interfaces/HARMIClient.java 2008-03-20 18:52:19 UTC (rev 71091)
@@ -26,6 +26,10 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
+import java.rmi.ConnectException;
+import java.rmi.ConnectIOException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.UnknownHostException;
import java.util.ArrayList;
import org.jboss.invocation.MarshalledInvocation;
@@ -154,13 +158,56 @@
}
+ /**
+ * Invoke the given method against a remote server. If the call results
+ * in certain {@link RemoteException} subtypes, catch the exception and
+ * attempt to fail over to another server.
+ * <p>
+ * Failover will only be attempted if the remote call throws an exception
+ * whose type indicates the call never reached the server:
+ * <ul>
+ * <li>{@link java.rmi.ConnectException}</li>
+ * <li>{@link java.rmi.ConnectIOException}</li>
+ * <li>{@link java.rmi.NoSuchObjectException}</li>
+ * <li>{@link java.rmi.UnknownHostException}</li>
+ * </ul>
+ * </p>
+ * <p>
+ * All other exception types will not be caught.
+ * </p>
+ * <p>
+ * If one of the above exception types is caught when invoking against the
+ * last known server, then a {@link RemoteException} will be thrown. This
+ * exception will include as its {@link Throwable#getCause() cause} either
+ * <ol>
+ * <li>any {@link java.rmi.NoSuchObjectException} that was caught</li>
+ * <li>or, if no {@link java.rmi.NoSuchObjectException} that was caught,
+ * the exception thrown on the last failover attempt</li>
+ * </ol>
+ * Preference is given to including <code>NoSuchObjectException</code> as
+ * the cause, as that exception indicates that a server was listening on
+ * the expected address and port but that this client has an RMI stub that
+ * is out of sync with the server. This would typically happen due to
+ * a server restart or service redeploy. Knowledge of this failure condition
+ * could potentially be useful to the caller.
+ * </p>
+ *
+ * @param proxy the proxy object that's being invoked
+ * @param method the method to invoke
+ * @param args arguments to the method
+ * @return any return value from the invocation, or <code>null</code>
+ *
+ * @throws Throwable Throwable thrown when making remote call, or the
+ * <code>RemoteException</code> discussed above.
+ */
public Object invokeRemote(Object proxy, Method method, Object[] args) throws Throwable
{
boolean trace = log.isTraceEnabled();
HARMIServer target = (HARMIServer)getRemoteTarget();
+ NoSuchObjectException nsoe = null;
+ Exception lastException = null;
while (target != null)
{
- Exception lastException = null;
try
{
if( trace )
@@ -183,26 +230,24 @@
return rsp.response;
}
- catch (java.rmi.ConnectException e)
+ catch (ConnectException e)
{
lastException = e;
}
- catch (java.rmi.ConnectIOException e)
+ catch (ConnectIOException e)
{
lastException = e;
}
- catch (java.rmi.NoSuchObjectException e)
+ catch (NoSuchObjectException e)
{
+ // JBAS-4740 preserve this exception
+ nsoe = e;
lastException = e;
}
- catch (java.rmi.UnmarshalException e)
+ catch (UnknownHostException e)
{
lastException = e;
}
- catch (java.rmi.UnknownHostException e)
- {
- lastException = e;
- }
if( trace )
log.trace("Invoke failed, target="+target, lastException);
// If we reach here, this means that we must fail-over
@@ -210,7 +255,10 @@
target = (HARMIServer)getRemoteTarget();
}
// if we get here this means list was exhausted
- throw new java.rmi.RemoteException("Service unavailable.");
+ // JBAS-4740 wrap any NSOE in preference to 'lastException' since
+ // an NSOE indicates a server was running
+ Exception toWrap = (nsoe == null) ? lastException : nsoe;
+ throw new java.rmi.RemoteException("Service unavailable.", toWrap);
}
@@ -223,6 +271,12 @@
// InvocationHandler implementation ----------------------------------------------
+ /**
+ * Invoke the given method, locally if possible; if not then
+ * {@link #invokeRemote(Object, Method, Object[]) invoke against a remote server}.
+ *
+ * @see #invokeRemote(Object, Method, Object[])
+ */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
// The isLocal call is handled by the proxy
Modified: branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/jndi/HANamingService.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/jndi/HANamingService.java 2008-03-20 17:57:59 UTC (rev 71090)
+++ branches/JBPAPP_4_2_0_GA_CP/cluster/src/main/org/jboss/ha/jndi/HANamingService.java 2008-03-20 18:52:19 UTC (rev 71091)
@@ -58,6 +58,7 @@
/** The RMI port on which the Naming implementation will be exported. The
default is 0 which means use any available port. */
protected int rmiPort = 0;
+ protected String replicantName = "HAJNDI";
HARMIServerImpl rmiserver;
// Public --------------------------------------------------------
@@ -124,7 +125,7 @@
Class clazz;
LoadBalancePolicy policy;
- rmiserver = new HARMIServerImpl(partition, "HAJNDI", Naming.class,
+ rmiserver = new HARMIServerImpl(partition, replicantName, Naming.class,
theServer, rmiPort, clientSocketFactory, serverSocketFactory, bindAddress);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Modified: branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/interfaces/NamingContext.java
===================================================================
--- branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/interfaces/NamingContext.java 2008-03-20 17:57:59 UTC (rev 71090)
+++ branches/JBPAPP_4_2_0_GA_CP/naming/src/main/org/jnp/interfaces/NamingContext.java 2008-03-20 18:52:19 UTC (rev 71091)
@@ -34,6 +34,8 @@
import java.net.InetSocketAddress;
import java.rmi.ConnectException;
import java.rmi.MarshalledObject;
+import java.rmi.NoSuchObjectException;
+import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -216,6 +218,9 @@
server = (Naming) ref.get();
if (server != null)
{
+ // JBAS-4622. Ensure the env for the request has the
+ // hostKey so we can remove the cache entry if there is a failure
+ serverEnv.put("hostKey", hostKey);
return server;
}
}
@@ -362,19 +367,17 @@
{
}
}
- Object hostKey = serverEnv.remove("hostKey");
- if (hostKey != null)
+ }
+
+ // JBAS-4622. Always do this.
+ Object hostKey = serverEnv.remove("hostKey");
+ if (hostKey != null)
+ {
+ synchronized (NamingContext.class)
{
- synchronized (NamingContext.class)
- {
- cachedServers.remove(hostKey);
- }
+ cachedServers.remove(hostKey);
}
}
- else
- {
- // Don't do anything for local server
- }
}
/**
@@ -508,7 +511,24 @@
{
className = ((Reference) obj).getClassName();
}
- naming.rebind(getAbsoluteName(name), obj, className);
+ try
+ {
+ naming.rebind(getAbsoluteName(name), obj, className);
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ if (handleStaleNamingStub(re, refEnv))
+ {
+ // try again with new naming stub
+ naming.rebind(getAbsoluteName(name), obj, className);
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
}
catch (CannotProceedException cpe)
{
@@ -565,7 +585,25 @@
className = ((Reference) obj).getClassName();
}
name = getAbsoluteName(name);
- naming.bind(name, obj, className);
+
+ try
+ {
+ naming.bind(name, obj, className);
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ if (handleStaleNamingStub(re, refEnv))
+ {
+ // try again with new naming stub
+ naming.bind(name, obj, className);
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
}
catch (CannotProceedException cpe)
{
@@ -624,7 +662,25 @@
{
try
{
- res = naming.lookup(n);
+ try
+ {
+ res = naming.lookup(n);
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ if (handleStaleNamingStub(re, refEnv))
+ {
+ // try again with new naming stub
+ res = naming.lookup(n);
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
+ // If we got here, we succeeded, so break the loop
break;
}
catch (ConnectException ce)
@@ -751,7 +807,24 @@
try
{
- naming.unbind(getAbsoluteName(name));
+ try
+ {
+ naming.unbind(getAbsoluteName(name));
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ if (handleStaleNamingStub(re, refEnv))
+ {
+ // try again with new naming stub
+ naming.unbind(getAbsoluteName(name));
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
}
catch (CannotProceedException cpe)
{
@@ -799,7 +872,26 @@
try
{
- return new NamingEnumerationImpl(naming.list(getAbsoluteName(name)));
+ Collection c = null;
+ try
+ {
+ c = naming.list(getAbsoluteName(name));
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ if (handleStaleNamingStub(re, refEnv))
+ {
+ // try again with new naming stub
+ c = naming.list(getAbsoluteName(name));
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
+ return new NamingEnumerationImpl(c);
}
catch (CannotProceedException cpe)
{
@@ -835,7 +927,26 @@
try
{
// Get list
- Collection bindings = naming.listBindings(getAbsoluteName(name));
+ Collection bindings = null;
+ try
+ {
+ // Get list
+ bindings = naming.listBindings(getAbsoluteName(name));
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ if (handleStaleNamingStub(re, refEnv))
+ {
+ // try again with new naming stub
+ bindings = naming.listBindings(getAbsoluteName(name));
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
Collection realBindings = new ArrayList(bindings.size());
// Convert marshalled objects
@@ -941,7 +1052,24 @@
try
{
name = getAbsoluteName(name);
- return naming.createSubcontext(name);
+ try
+ {
+ return naming.createSubcontext(name);
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ if (handleStaleNamingStub(re, refEnv))
+ {
+ // try again with new naming stub
+ return naming.createSubcontext(name);
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
}
catch (CannotProceedException cpe)
{
@@ -1026,7 +1154,25 @@
try
{
Name n = getAbsoluteName(name);
- link = naming.lookup(n);
+ try
+ {
+ link = naming.lookup(n);
+ }
+ catch (RemoteException re)
+ {
+ // Check for JBAS-4615.
+ // TODO if we resolve JBAS-4616, need to use refEnv
+ if (handleStaleNamingStub(re, env))
+ {
+ // try again with new naming stub
+ link = naming.lookup(n);
+ }
+ else
+ {
+ // Not JBAS-4615. Throw exception and let outer logic handle it.
+ throw re;
+ }
+ }
if (!(link instanceof LinkRef) && link instanceof Reference)
link = getObjectInstance(link, name, null);
;
@@ -1480,6 +1626,50 @@
}
return nameEnv;
}
+
+ /**
+ * JBAS-4615. Check if the given exception is because the server has
+ * been restarted while the cached naming stub hasn't been dgc-ed yet.
+ * If yes, we will flush out the naming stub from our cache and
+ * acquire a new stub. BW.
+ *
+ * @param e the exception that may be due to a stale stub
+ * @param refEnv the naming environment associated with the failed call
+ *
+ * @return <code>true</code> if <code>e</code> indicates a stale
+ * naming stub and we were able to succesfully flush the
+ * cache and acquire a new stub; <code>false</code> otherwise.
+ */
+ private boolean handleStaleNamingStub(RemoteException e, Hashtable refEnv)
+ {
+ if (e instanceof NoSuchObjectException
+ || e.getCause() instanceof NoSuchObjectException)
+ {
+ try
+ {
+ if( log.isTraceEnabled() )
+ {
+ log.trace("Call failed with recoverable RMI failure, " +
+ "flushing server cache and reaquiring Naming ref", e);
+ }
+ naming = null;
+ removeServer(refEnv);
+
+ checkRef(refEnv);
+
+ return true;
+ }
+ catch (Exception e1)
+ {
+ // Just log and return false; let caller continue processing
+ // the original exception passed in to this method
+ log.error("Caught exception flushing server cache and " +
+ "re-establish naming after exception " +
+ e.getLocalizedMessage(), e1);
+ }
+ }
+ return false;
+ }
// Inner classes -------------------------------------------------
}
More information about the jboss-cvs-commits
mailing list