Couple of other ways to get hold of ApplicationContext (rather than doing new ClasspathXmlApplicationContext()).
1. Create a bean which is ApplicationContextAware
MessageChannel msgCh = (MessageChannel)ApplicationContextHolder.getApplicationContext().getBean("eventChannel");
msgCh.send(msg);
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext appContext;
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
System.out.println("*** ApplicationContextHolder::setApplicationContext()...");
ApplicationContextHolder.appContext = ctx;
}
public static ApplicationContext getApplicationContext() {
return appContext;
}
}
This one is in the case of Spring DM
2. Accessing the ApplicationContext from BundleContext (By default every bundle publishes the Application Context as a Service).
public static ApplicationContext getApplicationContext() {
if (appCtx == null) {
try {
ServiceReference[] svcRef = bundleContext.getAllServiceReferences("org.springframework.context.ApplicationContext", "(org.springframework.context.service.name=ContextInClass)"); // Service name is the Bundle Symbolic Name
ServiceReference ref = svcRef[0];
appCtx = (ApplicationContext) bundleContext.getService(ref);
} catch (Exception e) {
e.printStackTrace();
}
}
return appCtx;
}
This is the preferred approach if you wish to use the Application Context from another bundle.
Friday, October 23, 2009
Ways to get Spring ApplicationContext -In Spring DM
Java Monitoring Guidelines
Use the following command which gives the process size.
ps auxwww | grep java
Process size - Max size is 3 Gb on unix and 4 gb on solaris
[process size includes stacks,native code,therads created etc]
user 6451 180 30.2 [1416444-->process_size] 626888 ?
A check on the process size is critical because when there are leaks this gradually increases and finally the server crashes.
Command to get the Memory Details
jmap -dump:live,format=b,file=histo.bin
Command to generate Report Using JHat
jhat -J-mx256m histo.bin [histo.bin can be pscp'ed to windows machine and this command can be executed]
This starts a server gives a port number at the command line. using this url the details can be viewed through a explorer
Consequently the following command can be used to get the current memory picture in the JVM.
jmap -histo:live [process-id] > [filename].txt
The following command is also useful to understand the java heap and the GC behavior
jstat -gcutil 2361 1s
UseFull Vm parametres
-XX:+HeapDumpOnOutOfMemoryError
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-XX:+PrintGCApplicationStoppedTime
-verbose:gc
-XX:ErrorFile=/location/error.log
-XX:HeapDumpPath=/location/heap_dump.hprof
jstack [process_id] or kill -3 [process_id] can be used to get the thread dump of the process.
Saturday, August 8, 2009
Thread Context ClassLoader / Buddy ClassLoading in OSGi.
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)
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 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
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(
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
.jpg)