[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