--- container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java (revision 1156533) +++ container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java (working copy) @@ -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 ObjectInputStream that loads from the @@ -86,6 +88,43 @@ } } + /** + * ObjectInputStream.resolveProxyClass has some funky way of using + * the incorrect class loader to resolve proxy classes, let's do it our way instead + */ + protected Class resolveProxyClass(String[] interfaces) + throws IOException, ClassNotFoundException { + + ClassLoader latestLoader = classLoader; + 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.findWebappClass(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 findReplicationClass(String name) throws ClassNotFoundException, IOException { return Class.forName(name, false, getClass().getClassLoader()); --- container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java (revision 1156533) +++ container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java (working copy) @@ -22,6 +22,8 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; /** * Custom subclass of ObjectInputStream that loads from the @@ -71,23 +73,68 @@ public Class resolveClass(ObjectStreamClass classDesc) throws ClassNotFoundException, IOException { String name = classDesc.getName(); - boolean tryRepFirst = name.startsWith("org.apache.catalina.tribes"); try { - try - { - if ( tryRepFirst ) return findReplicationClass(name); - else return findExternalClass(name); - } - catch ( Exception x ) - { - if ( tryRepFirst ) return findExternalClass(name); - else return findReplicationClass(name); - } + return resolveClass(name); } catch (ClassNotFoundException e) { return super.resolveClass(classDesc); } } + public Class resolveClass(String name) + throws ClassNotFoundException, IOException { + + boolean tryRepFirst = name.startsWith("org.apache.catalina.tribes"); + 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 + */ + 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 findReplicationClass(String name) throws ClassNotFoundException, IOException { Class clazz = Class.forName(name, false, getClass().getClassLoader());