callAsynchMethodOnCluster ClassLoader Problem
darranl Jun 8, 2003 9:57 AMHi,
I am having a ClassLoader problem that occurs when I use callAsynchMethodOnCluster.
My application consists of a session bean and data transfer object packed in a jar and a service packed in a sar, both of these are then packed in an ear for deployment.
The session bean passes in an instance of 'DataObject' to sendDataObject on my MBean, the two System.out.println calls show that the 'DataObject' is in the same class loader that was used to deploy my application.
setTestData is then automatically called and again both System.out.println calls show that the DataObject is in the same class loader that was used to deploy my application.
I then remove my ear from deploy and after it has been undeployed I deploy it again (The same ear, no recompilation).
When I run my test again the session bean calls sendDataObject, the System.out.println calls show that a new class loader is being used (Correctly).
setTestData as before is called correctly however the first System.out.println call shows that the data object was loaded by the class loader from the previous deployment. The second System.out.println call shows that creating a new DataObject would use the new class loader. As a result I can no longer cast obj to DataObject.
I have been using a profiling tool to find out what is happening and after the first class loader is eventually garbage collected I get the following error displayed on the console.
13:44:57,617 WARN [DefaultPartition] RpcProtocol.Handle(): java.lang.NullPointerException
And setTestData is no longer called.
If setTestData is declared to actually take the type DataObject there are no problems. I can not declare the method to take the specific type as I want to pass round a Hashtable of DataObjects not just a single instance and the Hashtable references them as Object.
Does anyone have any idea as to what I need to do to get the correct class loader to be used when a method on a service is being called across the cluster?
I have pasted in the implementation of the MBean below as I can not get 'Attach Files' to work.
package com.darranl.service;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import org.jboss.ha.framework.interfaces.HAPartition;
import org.jboss.naming.NonSerializableFactory;
import org.jboss.system.ServiceMBeanSupport;
import com.darranl.dto.DataObject;
/**
*
* @author Darran L
* @version 1.1.001
*/
public class ClassLoaderTest
extends ServiceMBeanSupport
implements ClassLoaderTestMBean {
private MBeanServer mBeanServer;
protected ObjectName clusterPartitionName = null;
private HAPartition partition = null;
private static final String SERVICE_NAME = "ClusteredMBean";
private final long createTime = System.currentTimeMillis();
/**
* @see com.darranl.service.ClassLoaderTestMBean#setTestData(com.darranl.dto.DataObject)
*/
public void setTestData(Object obj) {
System.out.println(
"setTestData - "
+ obj.getClass().getClassLoader().toString()
+ " - "
+ createTime);
System.out.println(
"setTestData - "
+ new DataObject().getClass().getClassLoader().toString()
+ " - "
+ createTime);
if (obj instanceof DataObject) {
System.out.println("obj is instanceof DataObject");
} else {
System.out.println("obj is NOT instanceof DataObject");
}
try {
Object other = (DataObject) obj;
System.out.println("No problems casting");
} catch (ClassCastException cce) {
System.out.println("ClassCastException");
}
}
public void sendDataObject(Object obj) {
System.out.println(
"sendDataObject - "
+ obj.getClass().getClassLoader().toString()
+ " - "
+ createTime);
System.out.println(
"sendDataObject - "
+ new DataObject().getClass().getClassLoader().toString()
+ " - "
+ createTime);
try {
partition.callAsynchMethodOnCluster(
SERVICE_NAME,
"setTestData",
new Object[] { obj },
false);
} catch (Exception e) {
System.err.println("sendDataObject error - " + e.getMessage());
}
}
/**
* @see javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer, javax.management.ObjectName)
*/
public ObjectName preRegister(MBeanServer mBeanServer, ObjectName objectName)
throws Exception {
this.mBeanServer = mBeanServer;
return super.preRegister(mBeanServer, objectName);
}
private void rebind() throws NamingException {
Context ctx = new InitialContext();
Name fullName = ctx.getNameParser("").parse("ClassLoaderTest");
NonSerializableFactory.rebind(fullName, this, true);
}
private void unbind() throws NamingException {
System.out.println("++unbind - " + "ClassLoaderTest");
InitialContext ctx = new InitialContext();
Name fullName = ctx.getNameParser("").parse("ClassLoaderTest");
NonSerializableFactory.unbind(fullName);
System.out.println("unbind - finished");
}
/**
* @see org.jboss.system.ServiceMBeanSupport#startService()
*/
protected void startService() throws Exception {
rebind();
clusterPartitionName =
new ObjectName("jboss:service=" + "DefaultPartition");
partition =
(HAPartition) mBeanServer.getAttribute(
clusterPartitionName,
"HAPartition");
partition.registerRPCHandler(SERVICE_NAME, this);
}
/**
* @see org.jboss.system.ServiceMBeanSupport#stopService()
*/
protected void stopService() throws Exception {
partition.unregisterRPCHandler(SERVICE_NAME, this);
unbind();
}
/**
* @see com.darranl.service.ClassLoaderTestMBean#getCreateTime()
*/
public long getCreateTime() {
return createTime;
}
}