Sunday, May 9, 2010

Thread Context Classloader in Deserialization - ObjectInputStream

We had uses cases, especially with OSGI where we had to use TCCL in deserialization of Object InputStream.

Sample method

public static Object getObject(byte[] bArr){
try{
ByteArrayInputStream bais = new ByteArrayInputStream(bArr);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}catch(Exception err){
err.printStackTrace();
}
return null;
}


return ois.readObject() - fails because ObjectInputStream doesnt take into consideration TCCL when deserializing.

In OSGi we need to deserialize this using TCCL because objects being deserialized are in another bundle and framework bundle canot see these classes.

Java has provided a way to solve this . We need to extend ObjectInputStream and overide the
public Class resolveClass(ObjectStreamClass desc) method.

[Since resolveClass class is protected method in ObjectInputStream ]

Code


public class MyObjectInputStream extends ObjectInputStream {

@Override
public Class resolveClass(ObjectStreamClass desc) throws IOException,
ClassNotFoundException {
ClassLoader currentTccl = null;
try {
currentTccl = Thread.currentThread().getContextClassLoader();
return currentTccl.loadClass(desc.getName());
} catch (Exception e) {
}

}
return super.resolveClass(desc);
}

public MyObjectInputStream(InputStream in) throws IOException {
super(in);
}

}

Now we can use MyObjectInputStream which ensures that TCCL will have visibility to deserialize the class.

MyObjectInputStream ois = new MyObjectInputStream(bais);
return ois.readObject();

Using Bundlor for automated generation of Osgi manifest files

One of the most useful utilities which helps in automated creation of manifest files. This gives all the hooks required for customization.

A sample template file used for generation

Bundle-Name: ${bundle.name}
Bundle-Description: ${bundle.description}
Bundle-ManifestVersion: 2
Bundle-SymbolicName: ${bundle.symbolic.name}
Bundle-Vendor: ${bundle.vendor}
Import-Template: org.apache.log4j.*;bundle-symbolic-name="com.springsource.org.apache.log4j", *
Excluded-Imports: com.sun.*,javax.xml.*,org.apache.xerces.jaxp.*,org.w3c.*,org.xml.*,sun.*,com.tc.*


Here the Import template functionality gives complete flexibility to control my imports> This ensures that all subpackages of org.apache.lo4j if imported by bundle will have bundle symbolic names attached to it.

If there is any private package , based on some naming convention we can exclude this from being exported. Also boot delegated packages should be excluded for exporting.

Boot delegated package exports can be avoided by passing osgi profile file to bundlor.
At this moment - Bundlor 1.0.0 had a Bug with this feature which is fixed in the daily snapshot version.
Ref : http://forum.springsource.org/showthread.php?t=87312

Hence bundlor automates a lot of these things and there is no need for static commit of manifest files.

This can be easily integrated with any build for the project as follows

<target name="bundlor.init">
<taskdef resource="com/springsource/bundlor/ant/antlib.xml"
uri="antlib:com.springsource.bundlor.ant">
<classpath id="bundlor.classpath">
<fileset dir="${bundlor.home}/dist"/>
<fileset dir="${bundlor.home}/lib"/>
</classpath>
</taskdef>
</target>


<bundlor:bundlor
inputPath="${basedir}/xxx_jar.jar"
outputPath="${basedir}/xxx_bundle.jar"
manifestTemplatePath="${basedir}/${bundlor.config.dir}/xxx.mf"
propertiesPath="${basedir}/${bundlor.config.dir}/xxx.properties"
osgiProfilePath="${basedir}/${bundlor.home}/profile/java6-server.profile"/>

Ref: http://www.springsource.org/bundlor

Integration of Terracotta with Spring Dm server

At this moment I am using the following version of the softwares

Spring DM server(or DM Kernel) - 2.0.1 version
Terracotta- version 3.2.1

Steps

In Dm server

1. Modify springsource-dm-kernel-2.0.1.RELEASE\bin\dmk.sh to start with terracotta cleint.

Change $JAVA_HOME/bin/java to $TERRACOTTA_CLIENT_PATH/bin/dso-java.sh

2. Change springsource-dm-kernel-2.0.1/lib/java6-server.profile to include terracotta classes in boot delegation path

Add under org.osgi.framework.bootdelegation = \
com.tc.*,\
com.tcclient,\
com.tcclient.*

Changes in Terracotta

1. change tc-config.xml to have the following tims

<modules>
<module name="tim-equinox-3.5.1" version="1.1.1"/>
<module name="tim-ehcache-2.0" version="1.5.2"/>
<module name="tim-distributed-cache" version="1.3.2"/>
<module name="tim-concurrent-collections" version="1.3.2"/>
</modules>

2. Add the following app group element in tc-config.xml

<app-group name="osgiAppGroup">
<named-classloader>Standard.system</named-classloader>
<named-classloader>dso-shared.0.0.0</named-classloader>
</app-group>


Thw app group element in only required if you want to share dso classes between standalone JVM and Spring Dm server(where dso classes are laoded by bundle classlaoder).

Also important thing to be noted is that inside a JVM all shared classes(dso's) have to be laoded by a single classloader.[Inside spring Dm server all dso classes should be a single bundle]

 
Free Domain Names @ .co.nr!