Author: markt
Date: Tue Aug 16 13:03:26 2011
New Revision: 1158254
URL: http://svn.apache.org/viewvc?rev=1158254&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51647
Session replication fails with ClassNotFoundException when session attribute is
Java dynamic proxy
Modified:
tomcat/tc5.5.x/trunk/STATUS.txt
tomcat/tc5.5.x/trunk/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
tomcat/tc5.5.x/trunk/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java
tomcat/tc5.5.x/trunk/container/webapps/docs/changelog.xml
Modified: tomcat/tc5.5.x/trunk/STATUS.txt
URL:
http://svn.apache.org/viewvc/tomcat/tc5.5.x/trunk/STATUS.txt?rev=1158254&r1=1158253&r2=1158254&view=diff
==============================================================================
--- tomcat/tc5.5.x/trunk/STATUS.txt (original)
+++ tomcat/tc5.5.x/trunk/STATUS.txt Tue Aug 16 13:03:26 2011
@@ -93,10 +93,3 @@ PATCHES PROPOSED TO BACKPORT:
as well as menu names etc.)
I think there is not much demand for this feature in 5.5 to justify
this.
The rest of changes and fixes are OK to backport (e.g. allow to specify
port numbers).
-
-* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51647
- Session replication fails with ClassNotFoundException when session attribute
- is Java dynamic proxy
- https://issues.apache.org/bugzilla/attachment.cgi?id=27375
- +1: markt, kfujino, kkolinko
- -1:
Modified:
tomcat/tc5.5.x/trunk/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
URL:
http://svn.apache.org/viewvc/tomcat/tc5.5.x/trunk/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java?rev=1158254&r1=1158253&r2=1158254&view=diff
==============================================================================
---
tomcat/tc5.5.x/trunk/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
(original)
+++
tomcat/tc5.5.x/trunk/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
Tue Aug 16 13:03:26 2011
@@ -22,6 +22,8 @@ import java.io.InputStream;
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
@@ -86,6 +88,43 @@ public final class ReplicationStream ext
}
}
+ /**
+ * 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());
Modified:
tomcat/tc5.5.x/trunk/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java
URL:
http://svn.apache.org/viewvc/tomcat/tc5.5.x/trunk/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java?rev=1158254&r1=1158253&r2=1158254&view=diff
==============================================================================
---
tomcat/tc5.5.x/trunk/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java
(original)
+++
tomcat/tc5.5.x/trunk/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java
Tue Aug 16 13:03:26 2011
@@ -22,6 +22,8 @@ import java.io.IOException;
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 <code>ObjectInputStream</code> that loads from the
@@ -71,23 +73,68 @@ public final class ReplicationStream ext
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());
Modified: tomcat/tc5.5.x/trunk/container/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc5.5.x/trunk/container/webapps/docs/changelog.xml?rev=1158254&r1=1158253&r2=1158254&view=diff
==============================================================================
--- tomcat/tc5.5.x/trunk/container/webapps/docs/changelog.xml (original)
+++ tomcat/tc5.5.x/trunk/container/webapps/docs/changelog.xml Tue Aug 16
13:03:26 2011
@@ -111,6 +111,10 @@
name of the authentication scheme if request has already been
authenticated. (kfujino)
</fix>
+ <fix>
+ <bug>51647</bug>: Fix session replication when a session attribute is a
+ Java dynamic proxy. Based on a patch by Tomasz Skutnik. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Webapps">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]