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: [email protected]
For additional commands, e-mail: [email protected]