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