Saturday, August 8, 2009

Thread Context ClassLoader / Buddy ClassLoading in OSGi.

Bundles like Struts,hibernate,Spring need to instantiate classes in custom application bundle.In normal cases this can be directly done because there is a single class space(single class loader).

Consider a case where there are more than one class loaders .Lets take a simple case in which the struts/spring jar is kept under tomcat common lib and your application classes are under the web-inf lib. These two are jars now are loaded by two different classloaders.
Tomcat common lib class loader being the parent of tomcat web-inf/lib class loader.Also classloader of struts jar cannot see application classes in web-inf lib.

Now how can struts/spring see application classes ?

To solve such problems java Java came up with a solution called Thread Context Class Loader(TCCL). Thread context class loader was introduced in Java 2 to enable frameworks running in application servers to access the "right" application class loader for loading application classes.

This is accessed using Thread.getCurentThread.getContextClassloader().Its as simple as, It is the classloader associated with each thread.There are setter methods which can be called to set this TCCL.

By the definition in tomcat the TCCL is set to the context class loader from where the thread begins.So TCCL has the classloader visibity of web-inf lib,solving our problem.

Now since the thread started from that application ,these third party jars can use TCCL to instantiate application classes. The control starts from our application bundle and then flow moves to some third party bundle like struts or hibernate,which internally in their
source code use TCCL to instantiate our classes.

TCCL becomes slightly more complicated in the case of OSGI.

I have a small POC for the Reflection based Class loading using TCCL.

Source Code : http://www.4shared.com/file/123739699/3b6dd30e/TCCLosgi.html

Bundle 3(Core bundle) – has reflection code to instantiate application classes. Uses TCCL to instantiate classes.

Bundle 2 (Service) –Using the core bundle to instantiate its classes (imports bundle 3 classes directly)

Bundle 1 (Application) – uses the OSGi service provided by bundle 2.


Control Flow:

Bundle 1 makes a OSGi service call to bundle 2.

Bundle 2 now uses core to instantiate its(bundle 2) classes.

Result: ClassNotFoundException

Reason:

Bundle 2 is able to instantiate classes only in Bundle 3 and not in Bundle.

This is because TCCL has visibility only to class loader from where the thread started.

Solution:

1. PAR(Spring DM solution)

Spring Dm comes with a concept of PAR,which is grouping of bundles.All bundles inside the PAR will contribute together to form a synthetic context.And hence bundles inside it have visibility to all others exisiting inside it.

http://blog.springsource.com/2008/05/02/running-spring-applications-on-osgi-with-the-springsource-application-platform/

2.Buddy Class Loading (this is equinox specific solution and not part of OSGi spec)

http://wiki.eclipse.org/index.php/Context_Class_Loader_Enhancements#Buddy_Class_Loading


Now bundle 3, that is the core bundle can be a buddy to bundle 2 (service bundle).

Syntax

In bundle 3 manifest we need to mention Buddy-Policy :registered

In bundle 2 manifest we mention Eclipse-RegisterBuddy : bundle symbolic name


Now at run time we can add new slots(Bundle 4) which registers itself as a buddy to bundle 2(core) ,without affecting any other bundles.

3. We can set the TCCL in bundle 2 to bundle class loader when the deligation goes through it.I guess TCCL may not be the right approach(not good to tamper the class loader prior to making calls across bundles).

We can choose a solution based on the requirement.






Cyclic Dependency in OSGi & Dynamic Imports

Since in OSGi we have multiple class loaders as compared to single Class Loader case ,there may be occur the problem of cyclic dependency.

This cyclic dependency may not be compile type instead most of the cases its runtime. Some piece of code may try to instantiate classes in another bundle using reflection.

Consider such a example

Bundle A requires Bundle B at runtime and vice versa.

Bundle A has to mention import in its manifest for bundle B classes and Bundle B has to do the same for Bundle A classes.

Now in such case when Bundle A is deployed it says class not found for Bundle B classes,hence to solve this we need to write

Import Package : package-from-BundleB;resolution=optional

Now Bundle A doesn't give error . Follow with deployment of Bundle B. Later when bundle A tries to access classes in Bundle B it says ClassNotFoundException.

This is because when we mentioned resolution=optional , it doesn't try to link again when class is requested. And the linking happens only initial time.

To solve this we need to use Dynamic imports in such cases.

This cyclic dependency in most of the cases can be solved using Thread Context Class Loader or Eclipse Buddy Class Loading(refer next blog for details),and there will rarely occur a case to use dynamic imports.

Sunday, August 2, 2009

Example:Spring Integration + Spring DM OSGi + Spring JMS(JBoss MQ)

I have come up with a sample for spring jms with spring integration.It shows how easy is it to configure adaptors for jms using spring integration.

Source Code Download:http://www.4shared.com/dir/18401908/5d14c8a6/springintosgijms.html

I basically have three bundles

Jms Exchange - where jms input/output channels and apapters are declared

Jms-Sender - bundle publishing message into the queue

Jms-Receiver - bundle receiving message from the queue

Jms Exchange
------------------

Publishing channel will put the message into this channel
<!-- channel for jms In message -->
<integration:channel id="jmsInChannel" />


Wrapping the channel using gateway , so that bundle publishing into teh channel is unaware of spring integration apis.

<!-- gateway which puts message into channel -->
<integration:gateway id="jmsSendProxy"
default-request-channel="jmsInChannel" service-interface="com.jms.exchange.IJmsEvent" />


Publishing the gateway as OSGi service for sender to put messages into the cahnnel.

<osgi:service id="jmsSendService" interface="com.jms.exchange.IJmsEvent" ref="jmsSendProxy"></osgi:service>



Jms outbound adaptor which picks the message from channel and puts it into the defined jms queue.

<!-- adapter which puts message from channel to jms queue -->
<jms:outbound-channel-adapter id="jmsin"
destination="sendDestination" channel="jmsInChannel" />


JNDI template required for jms communication on JBoss MQ

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory
</prop>
<prop key="java.naming.provider.url">jnp://10.1.64.232</prop>
<prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming
</prop>
</props>
</property>
</bean>


Connection Factory definition

<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>java:ConnectionFactory</value>
</property>

</bean>


Queue details for sending message

<bean id="sendDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>queue/RequestQueue</value>
</property>
</bean>



JMS message driven channel adaptor which picks the message as soon as it on the JMS queue and puts it into
the given channel.

<!-- adapter which pulls message from queue into channel -->
<jms:message-driven-channel-adapter
id="jmsout" destination="sendDestination" channel="jmsOutChannel" />


Channel defined for putting the message from queue to channel.

<!-- channel for jms Out message -->
<integration:channel id="jmsOutChannel" />


Publishing the channel as OSGi service for receiver to pick the mssage from channel.

<osgi:service id="jmsListenChannel" ref="jmsOutChannel"
interface="org.springframework.integration.channel.SubscribableChannel" />


Jms Sender
--------------


Osgi referece in to teh gateway for publishing the message into the channel.

<osgi:reference id="jmsSendProxy" interface="com.jms.exchange.IJmsEvent" ></osgi:reference>


JMS Sender using the gateway to put messages into the channel.

<!-- POJO calling gateway -->
<bean id="sender" class="com.jms.sender.Sender">
<property name="jmsSendProxy" ref="jmsSendProxy"></property>
</bean>


public class Sender extends TimerTask{

private IJmsEvent jmsSendProxy;

public void setJmsSendProxy(IJmsEvent jmsSendProxy) {
System.out.println("SETTER CALLED");
this.jmsSendProxy = jmsSendProxy;
}

@Override
public void run() {
System.out.println("TIMER TASK");
jmsSendProxy.send("TEST MESSAGE");

}
}


Spring Time Task which puts the message into the channel periodically.


<bean id="senderTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="period" value="10000" />
<property name="timerTask" ref="sender" />
</bean>

<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="senderTask" />
</list>
</property>
</bean>






Jms receiver
-----------------

OSGi reference into the channel for listening the messages in the channel.

<osgi:reference id="jmsListenChannel"
interface="org.springframework.integration.channel.SubscribableChannel" />


Service Activator which has a calls a dummy method when a jms message is received.

<!-- service activator for listening to jms messages on channel -->
<integration:service-activator
input-channel="jmsListenChannel" ref="jmsreceiver" method="receive" />

<bean id="jmsreceiver" class="com.jms.receiver.Receiver">



public class Receiver {

public void receive(String arg)
{
System.out.println("Jms response recevived"+arg);
}

}

Example: Spring Integration + Spring DM OSGi + Spring Remoting

I have just come up with a example for Spring integration along with OSgi.

I basically have 4 bundles

1. Exchange bundle which has definitions of channels

This bundle is spring integration aware, and hence has channel definitions in it.

Channel definition.

<publish-subscribe-channel id="login"/>

This channl is wrapped around a gateway and exposed as a OSGi service.This is to ensure that the event generating bundle is unaware of spring integration apis

Wrapping channel around gateway

<gateway id="loginProxy" default-request-channel="login"
service-interface="com.pg.exchange.event.IEvent" />

Exposing gateway as OSGi service

<osgi:service id="loginChannel" ref="loginProxy"
interface="com.pg.exchange.event.IEvent" />


Also the channel is directly published as a OSGi service for listener listening to it.

<osgi:service id="loginAnnouncementsChannel" ref="login"
interface="org.springframework.integration.channel.SubscribableChannel" />



2. Login bundle - bundle which generate login event and publishes it using gateway.

Accepting the Gateway from the exchange bundle as a OSgi service

<osgi:reference id="eventPublisher"
interface="com.pg.exchange.event.IEvent"/>

This bundle generates periodic events using a spring timer task as shown below

<bean id="logineventGenerator" class="com.pg.ara.LoginEventGenerator">
<property name="eventPublisher" ref="eventPublisher"></property>
</bean>

<bean id="loginTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="period" value="10000" />
<property name="timerTask" ref="logineventGenerator" />
</bean>


<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="loginTask" />
</list>
</property>
</bean>

Timer Task class generating events

public class LoginEventGenerator extends TimerTask {

IEvent eventPublisher;

public void setEventPublisher(IEvent eventPublisher) {
this.eventPublisher = eventPublisher;
}

@Override
public void run() {
System.out.println("login event published");
eventPublisher.login("Logged In");
}

}


3. Pam-proxy bundle is a bundle which listens to the event using OSGi refered pub-sub-channel

When the message is obtained it makes a spring remoting call uisng remoting adaptors

Consumed OSGi service

<osgi:reference id="loginAnnouncementsChannel"
interface="org.springframework.integration.channel.SubscribableChannel"/>


Activator which makes a remoting call when message is put on a channel

<si:service-activator input-channel="loginAnnouncementsChannel"
ref="exampleService"
method="testRemoting"
output-channel="responseChannel"/>


Channel which gets the spring remoting response
<si:channel id="responseChannel" />


Activator listening on the response
<si:service-activator input-channel="responseChannel"
ref="responseHandler"
method="handleResponse" />

ProxyFactory bean for making spring remoting call
<bean id="exampleService"
class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" >
< property name="serviceUrl" value="http://localhost:8088/test/pamService" />
< property name="serviceInterface" value="com.pam.external.IExampleService" />
</bean>


Response handler for the spring remoting call
<bean id="responseHandler" class="com.pam.proxy.sample.ResponseHandler" />


All the above bean can be avoided and instead we can use http-invoker inbound and outbound adaptors as explained in spring integration reference guide.

But i did not want the spring remoting hosting side to be unaware of spring integration.

Also i did not want to put any java code in the pam-proxy bundle.


4. Pam web bundle publishing a spring remoting service

<bean id="exampleProxy" class="com.pam.ExampleService" />

<bean name="/pamService"
class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="exampleProxy" />
<property name="serviceInterface" value="com.pam.external.IExampleService" />
</bean>



Source Code Location :http://www.4shared.com/dir/18401573/8c9d7e8d/springintosgiremoting.html

Saturday, August 1, 2009

Spring Integration & OSGi

This is the latest addition to the spring portfolio ,and again they have made it look so simple. This is mainly meant for asynchronous messaging between modules.Here when i say modules it could be within the same JVm or outside. Spring Integration does not provide any framework for inter JVM communication instead it provides adapters for all existing frameworks like JMS,Spring Remoting,HTTP calls ,Web Services etc.

Spring Integration mainly deals with channels , which is a pipe where messages can be put , and there can be any number of subscibers listening to it.We can keep our business logic independent of the frameworks used.Here channels can be of different types direct channels,pub-sub-channel,polling channels etc .Also there are provisions to make the channel synchronous.

It also provides number of adapters like jms adapters,rmi adaptors,web service adpaters such that we always deal in terms of channels i .e we talk to channels and it publishes to the required framework.Since we keep our code independent of any framework it will be easy flip any of these using configuratiosn without affecting teh business logic.

Certain examples i came across which are very descriptive

1.Spring Integration Documentaion Examples(http://static.springsource.org/spring-integration/reference/htmlsingle/spring-integration-reference.html#samples)

2.Spring Integration Example(dist/org.springframework.integration.samples-1.0.2.SR1.jar)

3.Blog by Oleg(http://blog.springsource.com/2009/02/27/spring-integration-on-dm-server/)

Certain points to note.

1.Channels can be published as OSGi service and other bundles can import it and publish on the channel or listen to it.

Note :

When more than one pub sub channel is defined and needs to be published, filter attributes have to be used to distinguish one from teh other.

Ref : http://forum.springsource.org/showthread.php?t=75316

Two models for hiding spring integration apis from bundles

1. Have a seperate bundle(call it exchange bundle) with spring integration configurations.

2. Wrap the channel using gateway() and expose this as a service , which will be used from the publishing bundle.This makes it independent of spring integration APIs and the publishing channel needs to know only about the interface.

3a. Let all teh bundles interested in listening to teh event register with the exchange bundle using a interface.

Implement a service activator in the exchange bundle.The service activator will collect all the OSgi services interested in listening to the service and call teh method one after the other for all registered services.

3b. The service activator will have a register /unregister method ,and teh service activator will be exposed a OSgi service.The interested bundles will import this service and call the register method. On calling thr register method it will add to the list in teh activator, which will call the method when teh event is published on teh channel. (oleg's blog uses teh same model)

http://forum.springsource.org/showthread.php?t=75315

 
Free Domain Names @ .co.nr!