Author: rjung
Date: Tue Jun 30 18:31:20 2009
New Revision: 789867

URL: http://svn.apache.org/viewvc?rev=789867&view=rev
Log:
Fix BZ 42662: Classloader issue for replicated sessions and dynamic proxies.
Backport of r656701 from Tomcat 6.0.

Modified:
    tomcat/sandbox/tomcat-oacc/trunk/docs/changelog.xml
    
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/DeltaManager.java
    
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
    
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java
    
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java

Modified: tomcat/sandbox/tomcat-oacc/trunk/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-oacc/trunk/docs/changelog.xml?rev=789867&r1=789866&r2=789867&view=diff
==============================================================================
--- tomcat/sandbox/tomcat-oacc/trunk/docs/changelog.xml (original)
+++ tomcat/sandbox/tomcat-oacc/trunk/docs/changelog.xml Tue Jun 30 18:31:20 2009
@@ -33,6 +33,10 @@
   <subsection name="Cluster">
       <changelog>
       <fix>
+        <bug>42662</bug>: Classloader issue for replicated sessions and 
dynamic proxies.
+        Backport from Tomcat 6.0. (rjung)
+      </fix>
+      <fix>
         <bug>45279</bug>: Fix socket when closing multicast.
         Backport from Tomcat 6.0. (rjung)
       </fix>

Modified: 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/DeltaManager.java
URL: 
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/DeltaManager.java?rev=789867&r1=789866&r2=789867&view=diff
==============================================================================
--- 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/DeltaManager.java
 (original)
+++ 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/DeltaManager.java
 Tue Jun 30 18:31:20 2009
@@ -723,7 +723,7 @@
         ReplicationStream ois = null;
         Loader loader = null;
         fis = new ByteArrayInputStream(data);
-        ois = new ReplicationStream(fis, getClassLoaders(this.container)[0]);
+        ois = new ReplicationStream(fis, getClassLoaders(this.container));
         session.getDeltaRequest().readExternal(ois);
         ois.close();
         return session.getDeltaRequest();

Modified: 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
URL: 
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/ReplicationStream.java?rev=789867&r1=789866&r2=789867&view=diff
==============================================================================
--- 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
 (original)
+++ 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
 Tue Jun 30 18:31:20 2009
@@ -22,6 +22,8 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectStreamClass;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
 
 /**
  * Custom subclass of <code>ObjectInputStream</code> that loads from the
@@ -39,7 +41,7 @@
     /**
      * The class loader we will use to resolve classes.
      */
-    private ClassLoader classLoader = null;
+    private ClassLoader[] classLoaders = null;
 
     /**
      * Construct a new instance of CustomObjectInputStream
@@ -50,11 +52,11 @@
      * @exception IOException if an input/output error occurs
      */
     public ReplicationStream(InputStream stream,
-                             ClassLoader classLoader)
+                             ClassLoader[] classLoaders)
         throws IOException {
 
         super(stream);
-        this.classLoader = classLoader;
+        this.classLoaders = classLoaders;
     }
 
     /**
@@ -69,31 +71,92 @@
     public Class resolveClass(ObjectStreamClass classDesc)
         throws ClassNotFoundException, IOException {
         String name = classDesc.getName();
-        boolean tryRepFirst = name.startsWith("org.apache.catalina.cluster");
         try {
-            try
-            {
-                if ( tryRepFirst ) return findReplicationClass(name);
-                else return findWebappClass(name);
-            }
-            catch ( Exception x )
-            {
-                if ( tryRepFirst ) return findWebappClass(name);
-                else return findReplicationClass(name);
-            }
+            return resolveClass(name);
         } catch (ClassNotFoundException e) {
             return super.resolveClass(classDesc);
         }
     }
     
-    public Class findReplicationClass(String name)
+    public Class resolveClass(String name)
         throws ClassNotFoundException, IOException {
-        return Class.forName(name, false, getClass().getClassLoader());
+
+        boolean tryRepFirst = name.startsWith("org.apache.catalina.cluster");
+            try {
+            if (tryRepFirst)
+                return findReplicationClass(name);
+            else
+                return findExternalClass(name);
+        } catch (Exception x) {
+            if (tryRepFirst)
+                return findExternalClass(name);
+            else
+                return findReplicationClass(name);
+        }
+    }
+    
+    /**
+     * ObjectInputStream.resolveProxyClass has some funky way of using 
+     * the incorrect class loader to resolve proxy classes, let's do it our 
way instead
+     */
+    @Override
+    protected Class<?> resolveProxyClass(String[] interfaces)
+            throws IOException, ClassNotFoundException {
+        
+        ClassLoader latestLoader = (classLoaders!=null && 
classLoaders.length==0)?null:classLoaders[0];
+        ClassLoader nonPublicLoader = null;
+        boolean hasNonPublicInterface = false;
+
+        // define proxy in class loader of non-public interface(s), if any
+        Class[] classObjs = new Class[interfaces.length];
+        for (int i = 0; i < interfaces.length; i++) {
+            Class cl = this.resolveClass(interfaces[i]);
+            if (latestLoader==null) latestLoader = cl.getClassLoader();
+            if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
+                if (hasNonPublicInterface) {
+                    if (nonPublicLoader != cl.getClassLoader()) {
+                        throw new IllegalAccessError(
+                                "conflicting non-public interface class 
loaders");
+                    }
+                } else {
+                    nonPublicLoader = cl.getClassLoader();
+                    hasNonPublicInterface = true;
+                }
+            }
+            classObjs[i] = cl;
+        }
+        try {
+            return Proxy.getProxyClass(hasNonPublicInterface ? nonPublicLoader
+                    : latestLoader, classObjs);
+        } catch (IllegalArgumentException e) {
+            throw new ClassNotFoundException(null, e);
+        }
     }
 
-    public Class findWebappClass(String name)
+    
+    public Class findReplicationClass(String name)
         throws ClassNotFoundException, IOException {
-        return Class.forName(name, false, classLoader);
+        Class clazz = Class.forName(name, false, getClass().getClassLoader());
+        return clazz;
+    }
+
+    public Class findExternalClass(String name) throws ClassNotFoundException  
{
+        ClassNotFoundException cnfe = null;
+        for (int i=0; i<classLoaders.length; i++ ) {
+            try {
+                Class clazz = Class.forName(name, false, classLoaders[i]);
+                return clazz;
+            } catch ( ClassNotFoundException x ) {
+                cnfe = x;
+            } 
+        }
+        if ( cnfe != null ) throw cnfe;
+        else throw new ClassNotFoundException(name);
+    }
+
+    public void close() throws IOException  {
+        this.classLoaders = null;
+        super.close();
     }
 
 

Modified: 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java
URL: 
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java?rev=789867&r1=789866&r2=789867&view=diff
==============================================================================
--- 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java
 (original)
+++ 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java
 Tue Jun 30 18:31:20 2009
@@ -18,7 +18,9 @@
 
 import java.io.IOException;
 
+import org.apache.catalina.Container;
 import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Loader;
 import org.apache.catalina.Session;
 import org.apache.catalina.cluster.CatalinaCluster;
 import org.apache.catalina.cluster.ClusterManager;
@@ -362,6 +364,19 @@
         return null;
     }
 
+    public static ClassLoader[] getClassLoaders(Container container) {
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        if (container != null) loader = container.getLoader();
+        if (loader != null) classLoader = loader.getClassLoader();
+        else classLoader = Thread.currentThread().getContextClassLoader();
+        if ( classLoader == Thread.currentThread().getContextClassLoader() ) {
+            return new ClassLoader[] {classLoader};
+        } else {
+            return new ClassLoader[] 
{classLoader,Thread.currentThread().getContextClassLoader()};
+        }
+    }
+
     /**
      * Reinstantiates a serialized session from the data passed in.
      * This will first call createSession() so that we get a fresh instance 
with all
@@ -376,7 +391,7 @@
         try
         {
             java.io.ByteArrayInputStream session_data = new 
java.io.ByteArrayInputStream(data);
-            ReplicationStream session_in = new 
ReplicationStream(session_data,container.getLoader().getClassLoader());
+            ReplicationStream session_in = new ReplicationStream(session_data, 
getClassLoaders(container));
 
             Session session = sessionId!=null?this.findSession(sessionId):null;
             boolean isNew = (session==null);

Modified: 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java
URL: 
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java?rev=789867&r1=789866&r2=789867&view=diff
==============================================================================
--- 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java
 (original)
+++ 
tomcat/sandbox/tomcat-oacc/trunk/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java
 Tue Jun 30 18:31:20 2009
@@ -27,6 +27,7 @@
 import javax.management.ObjectName;
 
 import org.apache.catalina.Container;
+import org.apache.catalina.Loader;
 import org.apache.catalina.cluster.CatalinaCluster;
 import org.apache.catalina.cluster.ClusterMessage;
 import org.apache.catalina.cluster.ClusterReceiver;
@@ -609,6 +610,19 @@
         }
     }
 
+    public static ClassLoader[] getClassLoaders(Container container) {
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        if (container != null) loader = container.getLoader();
+        if (loader != null) classLoader = loader.getClassLoader();
+        else classLoader = Thread.currentThread().getContextClassLoader();
+        if ( classLoader == Thread.currentThread().getContextClassLoader() ) {
+            return new ClassLoader[] {classLoader};
+        } else {
+            return new ClassLoader[] 
{classLoader,Thread.currentThread().getContextClassLoader()};
+        }
+    }
+
     /**
      * deserialize the receieve cluster message
      * @param data uncompress data
@@ -627,8 +641,8 @@
             } else {
                 instream = new ByteArrayInputStream(data.getMessage());
             }
-            ReplicationStream stream = new ReplicationStream(instream,
-                    getClass().getClassLoader());
+            Container container = cluster.getContainer();
+            ReplicationStream stream = new ReplicationStream(instream, 
getClassLoaders(container));
             message = stream.readObject();
             // calc stats really received bytes
             totalReceivedBytes += data.getMessage().length;



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to