feedburner
Enter your email address:

Delivered by FeedBurner

feedburner count

How to share objects between different classloaders on Terracotta

Labels: , , ,

Object identity in Terracotta is based on a combination of classloader name and object reference. When using Terracotta to share an object between different applications where the object class is loaded by classloaders with different names, exception is thrown. In my case I shared an object between deployed ear application on JBoss (app-ee.ear) and a console application.

Exception in thread "Thread-10" com.tc.exception.TCClassNotFoundException: java.lang.ClassNotFoundException: No registered loader for description: JBoss.UnifiedClassLoader3:deploy/app-ee.ear, trying to load org.terracotta.datagrid.workmanager.routing.RoutableWorkItem
at com.tc.object.bytecode.ManagerUtil.lookupObject(ManagerUtil.java:335)
at java.util.concurrent.LinkedBlockingQueue$Node.getItem(LinkedBlockingQueue.java:65)
at java.util.concurrent.LinkedBlockingQueue.extract(LinkedBlockingQueue.java:139)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:386)
at org.terracotta.datagrid.workmanager.routing.RoutingAwareWorker.start(RoutingAwareWorker.java:46)
at com.shimi.example.StartRoutingWorker$1.run(StartRoutingWorker.java:20)
Caused by: java.lang.ClassNotFoundException: No registered loader for description: JBoss.UnifiedClassLoader3:deploy/app-ee.ear, trying to load org.terracotta.datagrid.workmanager.routing.RoutableWorkItem
at com.tc.object.loaders.StandardClassProvider.getClassFor(StandardClassProvider.java:43)
at com.tc.object.ClientObjectManagerImpl.lookup(ClientObjectManagerImpl.java:522)
at com.tc.object.ClientObjectManagerImpl.lookupObject(ClientObjectManagerImpl.java:423)
at com.tc.object.ClientObjectManagerImpl.lookupObject(ClientObjectManagerImpl.java:412)
at com.tc.object.bytecode.ManagerImpl.lookupObject(ManagerImpl.java:651)
at com.tc.object.bytecode.ManagerUtil.lookupObject(ManagerUtil.java:333)
... 5 more


In order to solve the problem, all the VMs which are synchronized by Terracotta needs to load the shared class with the same classloader name. Since the name of the classloader which loaded the class on JBoss was JBoss.UnifiedClassLoader3:deploy/app-ee.ear, I needed to load the class on the console application using a classloader with the same name. I used a wrapper main class around the application main class. The wrapper class rename the system classloader using Terracotta NamedClassLoader and start the application.



import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import com."com/caucho/loader/EnvironmentClassLoader"tc.object.bytecode.hook.impl.ClassProcessorHelper;
import com.tc.object.loaders.NamedClassLoader;

public class CustomLoader {

// usage: java CustomLoader com.example.MyRealMainClass [arg1] [arg2]

public static void main(String[] args) throws Exception {
URL[] systemURLs = ((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs();

ClassLoader loader = new URLClassLoader(systemURLs, ClassLoader
.getSystemClassLoader().getParent());

// here is the custom classloader name
((NamedClassLoader) loader).__tc_setClassLoaderName("JBoss.UnifiedClassLoader3:deploy/app-ee.ear");
ClassProcessorHelper.registerGlobalLoader((NamedClassLoader) loader);

Thread.currentThread().setContextClassLoader(loader);
Class mainClass = loader.loadClass(args[0]);

Method main = mainClass.getMethod("main", new Class[] { args.getClass() });

String[] nextArgs = new String[args.length - 1];
System.arraycopy(args, 0, nextArgs, 0, nextArgs.length);
main.invoke(null, new Object[] { nextArgs });
}
}

1 comments:
gravatar
Chathurika Sandarenu said...
December 11, 2008 at 8:00 AM  

Hi,
There is much easier way of doing this which I found in Terracotta site. Just give vm argument -Dcom.tc.loader.system.name=JBoss.UnifiedClassLoader3:deploy/app-ee.ear when you are running the app.

Post a Comment