Proposal for TreeCacheMarshaller
ben.wang Aug 12, 2005 7:42 PMScott, Bela, and I have been discussing a solution to provide marshalling in the JBossCache layer about 3 weeks ago. But I was busy working on JBossCacheAop untill 2 days ago.
Now I am tackling this issue working through the design and initial implementation. I want to throw it out here to see if anyone has anything to add. BTW, if all go well, this is planned for release 1.2.4.
The main motive for this, of course, is now it is very common for JbossCache to run under a scoped class loader context. Case in point, in http session replication and SFSB replication, we all have the concept of scoped loader. However, plain JGroups replication will simply use the default system class loader to de-serialize the object. If application layer doesn't use MarshalledValue wrapper, we end up with ClassCastException!
Currently http and sfsb all use MarshalledValue in order to tackle this problem. However, there are issues:
1. JGroups will deserialize MarshalledValue first and the user do another MarshalledValue.get() to retrieve the underlying object.
2. In order to prevent from *un-marshalling* every single user get, we normally maintain a in-memory Pojo copy first. But then we will need an corresponding invlaidation mechanism to flush out the local copy in order to retrieve the updated version from MarshalledValue again. This is tedious to maintain and is not portable.
So here is the proposed solution. We will provide a TreeCacheMarshaller (under package org.jboss.cache.marshall) in JBossCache level. If it is activated, it will use user's specified class loader to de-serialize the key and value objects in the cache store. As a result, it can handle the scoped class loader automatically. In addition, there is also no need to maintain an in-memory copy.
It will implement a callback for RpcDispatcher.Marshaller from JGroups. So if it is registered, JGroups will delegate the de-sersialization to Marshaller. In order for this to work properly, we propose:
1. TreeCache provides registerClassLoader(Fqn fqn, ClassLoader cl) and
unregisterClassLoader(fqn fqn) apis to register the user-specific class loader.
2. User app when needed for marshalling, will register a ClassLoader with TreeCache under a "fqn" region. The concept of region is the same as in eviction. Any nodes fall under this fqn belongs to the same region.
3. During byteBufferFromObject api, we will extract the fqn from the MethodCall obejct, write it into output stream first before the regular one. Then during byteBufferToObject, we will read the fqn first to determine the corresponding class loader before handling the de-serialization.
For example, in http session replication, we would register the "webpath" as a region since it is unique for each web app. And so naturally every session under that will use the same class loader.
But here is one restriction. Since replicated MethodCalls include put, remove, prepare, commit, and rollback, we require all these calls operate under the same "region" for marshalling to work. This is probably ok (e.g., http and sfsb).
There is also a known issue in http session replication. Currently we also externalize the session in order to keep the same session instance. So we will need to come up a way to prevent duplication of serialization.