Saturday, December 12, 2009

Spring Integration+JMS(JBOSS)+OSGi

I have a POC for spring integration to be used along with JBoss and OSGi in Spring Dm server 2.0M6.

Code Sample
http://docs.google.com/fileview?id=0B-0gqvlsl_VvNzhiMzVmMzgtY2Y4Zi00YjJmLWJmNWQtMTIwMDZjNDViMmJl&hl=en
[Download this pdf - Rename file from pdf to rar and extract]


SwitchBoardBundle – Exposes connection factories as service

Exposes common thread pools as service

[Jboss ip values for connection factories are picked from property files]



Ara Bundle - Start a timertask which puts message into a login channel.

This channel is exposed as a service which is imported by PamClient Channel

Ara bundles defines its own thread pool and receives connectionFactory service from switchboard bundle.



PamClient Bundle - Listens to local events from ara bundle and remote events from Pamserver bundle

Imports login channel service from Ara bundle

Uses common thread pool defined in switchboard bundle

[Property file has values which can point each topic or queue to be hosted on a specific Jboss server]



PamServer Bundle – generates events on regular time intervals which will be put into Jms queue using jms adapters.

Also tested a use case where we could change connection factory without getting down the server

OSGi -Spring - Configuration Admin - Dynamic Property file changes

Normally we have been reading the property files ourselves or used spring property-holder feature or even cm-properties. In all these cases update to the property file are not visible.

You can now use the managed-properties under Configuration Admin and have the values updated in your bean automatically whenever you change the property file. You just drop a property file inside pickup directory and under the bean definition specify the persistent-id as follows:


// Have a property file with name myPropertyFile
<osgix:cm-properties id="config" persistent-id="myPropertyFile"/>

//declare a property place holder config with id of osgi:cm
<context:property-placeholder properties-ref="config"/>

//bean definition using teh property file
<bean id="configTest" class="com.test.ConfigTest">
<osgix:managed-properties persistent-id="myPropertyFile" update-strategy="container-managed" /> <property name="propertyValue" value="${propertyValue}"></property>
</bean>

Now first add the property file to the pick up folder and start the DM server. The setPropertyValue() setter will be called and the value will be initialized when application bundle is dropped.

[There are multiple calls to this setter because of the osgi configuration admin]

Now when the property file in changed in the pickup directory , the setter method will be called and new value will be set into the bean.

Incase you want to manage the updates yourself you can change the update-strategy and provide the update-method in the bean. In this case all the key/values are provided to the method in form of a Map.

<bean id="configTest" class="com.test.ConfigTest">
<osgix:managed-properties persistent-id="myPropertyFile"
update-strategy="bean-managed" update-method="refresh" />
<property name="propertyValue" value="${propertyValue}"></property>
</bean>

The ConfigTest class is as follows

public class ConfigTest {

private int propertyValue;

public void setPropertyValue(int propertyValue) {

System.out.println("setter called for property"+propertyValue);
this.propertyValue = propertyValue;
}


public void refresh(Map <String,String> keyVals)
{
System.out.println("referhs called with value"+keyVals);
}

}

PS:

Do not share the same persistent-id (PID) between multiple bundles or definitions, as only one of them will receive notifications. managed-properties relies on org.osgi.service.cm.ManagedService contract which mandates that each ManagedService instance must be identified with its own unique PID.

Hence the best option in a service model is to have a configuration service reading the property file and giving notifications to required bundles.

Interesting Java Data Structures

Vector & Collections.synchronizedList(new ArrayList()); are similar. They get the lock on the entire object.

So are HashTable and Collections.synchronizedMap(new HashMap());.

Though lock is taken on entire object - during operations like iterations they have to be in a synchronised block.Else parallel access by other thread will lead to a concurrent access exception.

http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html

Solution to these are data structures like CopyOnWrtieArrayList(for list) ConcurrentHashMap(for map).

ConcurrentHashMap doesnt lock the entire object , instead allows parallel reads, when a write operation is on.

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ConcurrentHashMap.html


Similarly with CopyOnWriteArrayList there is no need to lock the entire object during iteration, as the iteration will happen on a copy object.

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

RentrantReadWriteLock - This helps in taking a lock .So that all other access through this point will wait for the lock to be released. This lock is not resticted to a object and hence can be used in the business logic to get fine thread safety and synchronisation over business objects.This also provided read and write locks which will help in granular control for read and write operations.

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html

Synchronizing method against block(object)

When a method is synchronized , the method object is blocked. No other thread can enter into any other synchronized method(non static) on this object.But other threads can enter into a non synchronized block on the same class.

When a block is synchronized - if its synchronised on a object ,two parallel thread can access two synchronized blocks at the same time., since locks are on two different objects.

Class level locks can be obtained by making static methods synchronized.

Saturday, November 21, 2009

AOP - AspectJ,Spring - Compile Time ,Load Time ,Run Time(Proxy)

Spring AOP - Runtime - Using Proxy

Steps

1.Spring Application Context - Bean Declarations

For enabling this proxy approach add
<aop:aspectj-autoproxy />

Note :

Do not be misled by the name of the element: using it will result in the creation of Spring AOP proxies. The @AspectJ style of aspect declaration is just being used here, but the AspectJ runtime is not involved



Aspect Declaration
<bean id="myAspect" class="com.test.aop.MyAspect"></bean>

Method where aspect will be applied
<bean id="test" class="com.test.aop.Test" init-method="init" />

Wrapper calling test
<bean id="testB" class="com.test.aop.Wrapper" init-method="init">
<property name="test" ref="test"></property>
</bean>


2. Classes

  • Aspect Class

@Aspect
public class MyAspect {

@Before("execution(* com.test.aop.Test.*())")
public void myMethod()
{
System.out.println("calling my before aspect");
}

}

  • public class Test {

public void init()
{
System.out.println("init in test method");
}

}


  • public class Wrapper {

private Test test;

public void setTest(Test test) {
this.test = test;
}

public void init() {
test.init();
}

}

3. OutPut(In Spring DM)

System.out I init in test method
System.out I calling my before aspect
System.out I init in test method

Only when the init method is called through testB bean ,the aspect is bound.

Now when init method of test bean is called , the aspect is still not bound.(init methods cannot be proxied).

This is because the way spring life cycle works :

Spring life cycle

Phase 1 - Validate bean definitions
Phase 2 - Bean definition post processor(replacing property values)
Phase 3 - Bean Instantiation
Phase 4 - Bean post initialization(setters and init methods -in order) & Proxy creation

In the above example bean 'test' first cycles through phase 1,2,3 and 4. Hence after the init method is called, the proxy is created.But when testB is created in its init(phase) call to bean test will call teh aspect (as bean test lifecycle is complete)

One more important thing to note is that Cg lib will be used to create proxy here as teh class doesnt implement any interface.(Else jdk dyanmic proxies would have been used)

Aspect-J Load Time Weaving
(This may have issues with Spring DM
http://forum.springsource.org/showthread.php?t=80504
)

Same code as above except some change in the configurations.

1. Replace <aop:aspectj-autoproxy /> with <context:load-time-weaver/>.

2. Add aop.xml in META-INF directory

<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>

<!--works without this -->
<weaver>
<include within="com.test.aop.*" />
</weaver>

<aspects>
<!-- weave in just this aspect -->
<aspect name="com.test.aop.MyAspect" />
</aspects>

</aspectj>


3. Class to test the application in standlone mode

public class StandAloneLoadTimeWeaving {

public static void main(String args[])
{
ApplicationContext ctx = new ClassPathXmlApplicationContext("config.xml",StandAloneLoadTimeWeaving.class);
Test t =(Test)ctx.getBean("test");
t.init();
}

}

Ref: http://www.springbyexample.org/examples/aspectj-ltw.html
http://static.springsource.org/spring/docs/2.5.x/reference/aop.html#aop-aj-ltw


4. Add the following parameter when running

-javaagent:spring-agent.jar


Aspect J Compile Time Weaving(Build Time)

Same as Loadtime weaving needs aop.xml (but no need to add spring agent while running)

Command to compile the code

java org.aspectj.tools.ajc.Main –inpath <src_code_directory> -outjar <output_jarname.jar>

Ex:java -cp aspectjtools.jar;aspectjrt.jar org.aspectj.tools.ajc.Main -inpath . -outjar test.jar

The output jar will have code which is instrumented by the aspect.

You can download aspectj from this site

http://www.eclipse.org/aspectj/downloads.php

Wednesday, November 18, 2009

Writing Custom Namespaces in Spring

1. Application context xmls looks as below

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:test="http://www.test.xyz/schema"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.test.xyz/schema http://www.test.xyz/schema-1.0.xsd">

<test:person name="suji"/>
</beans>

Now the xsd mentioned in the schema location should map to something.

2. You shoudl have a spring.schemas file in the META-INF directory

http\://www.test.xyz/schema-1.0.xsd=com/test/test-1.0.xsd

This maps the schema to teh lcoation of teh xsd

3. Xsd looks like

<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.test.xyz/schema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">

<xsd:element name="person">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Configures all required interactions with the named Control Bus configuration
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Identifies group-name of a Control Bus this configuration defines
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>

</xsd:schema>

We have a single element person with attribute as name which is a string.

4. Now each element in the xsd should map to a resolver.

This can be mentioned in spring.handlers file which is also in the META-INF directory

http\://www.test.xyz/schema=com.test.PersonNamespaceHandler


5. Implementaion of PersonNamespaceHandler

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class PersonNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("person", new PersonParser());
}

}


6. Parser implementation

public class PersonParser extends AbstractBeanDefinitionParser {
private String beanName;

/* This method gets the parameters mentioned in the custom namespace and helps building
custom logic based on it */


@Override
protected AbstractBeanDefinition parseInternal(Element element,
ParserContext parserContext) {
BeanDefinitionBuilder rootBuilder = BeanDefinitionBuilder
.rootBeanDefinition(Person.class.getName());
beanName = element.getAttribute("name");

//Ensuring name is a compulsary attribute

Assert.hasText(beanName, "'name' must be provided");
rootBuilder.addPropertyValue("name", beanName);
return rootBuilder.getBeanDefinition();
}

protected String resolveId(Element element,
AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
return beanName;
}

}


7. Custom classes for Person

public class Person {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


Test case for trying out this

public class PersonParserTest {

public static void main(String[] arg){
ApplicationContext ac = new ClassPathXmlApplicationContext("config.xml", PersonParserTest.class);
Person person = (Person) ac.getBean("suji");
System.out.println("Person: " + person.getName());
}
}

Tuesday, November 17, 2009

TCCL in OSGi(Spring DM)

In order to better understand how TCCL works in OSGi i have done a sample POC.

I created 3 bundles.

Bundle A - calls Bundle B (imports Bundle B)

Bundle B -calls Bundle C (imports Bundle A)

Bundle C - instantiates class in Bundle A (No imports)

In normal cases Bundle C will fail to instantiate class in Bundle A, but this can be achieved using TCCL as follows.

ITest test=(ITest)Thread.currentThread().getContextClassLoader().loadClass("com.bundleA.external.ActionClass").newInstance();

Conclusion: Spring Dm sets TCCL to the bundle classloader where the thread initiated.

Now what if we want to instantiate class of bundle B in Bundle C , but the thread flow doesnt change. ?

This can be easily done by resetting the TCCL in bundle B's method as follows

Thread.currentThread().setContextClassLoader(Bundle2.class.getClassLoader());

BootClassPath and Sytem ClassPath in OSGI(Spring DM)

System Package

java.* can be directly used without any imports. This is neither part of boot delegation nor system packages as they are part of jdk itself.For loading these fundamental types, the OSGi platform uses parent delegation instead of the networking model; that is, it uses the class loader that started the OSGi framework to load classes instead of an OSGi class space.

None of the other public packages available in the JDK such as the javax.net or javax.xml are parent delegated which means they have to be resolved within the class space that is, bundles need to import the packages (which means there needs to be a provider) since they are not implied. The OSGi spec allows the Framework (through its system bundle) to export
any relevant packages from its parent class loader as system packages using the org.osgi.framework.system.packages property.

As repacking the hosting JDK as a bundle isn't a viable option, one can use this setting to have the system bundle (or the bundle with id 0) export these packages itself.

Extension Bundles

Another possible option is to enhance the system bundle through extension bundles. These act as fragments; they are not bundles of their own but rather are attached to a host.
Extension bundles are a special kind of fragments that get attached only to the System bundle in order to deliver optional parts of the Framework

Boot Delegation

This allows the user to create 'implied' packages that will always be loaded by the framework parent class loader, even if the bundles do not provide the proper imports:

This option is mainly created to accommodate various corner cases especially in the JDK classes that expect parent class loading delegation to always occur or that assume that every class loader on the system has full access to the entire boot path.There are cases where boot delegation is quite handy; a good candidate being instrumentation, such as profiling or code coverage.

Ref:http://blog.springsource.com/2009/01/19/exposing-the-boot-classpath-in-osgi/

I have done samples to better understand how classloader comes into picture for loading classes at different levels by printing parent classloaders upto 4 levels.

Class loader for one of the classes of bundle in pick up.

bundle classloader ServerBundleClassLoader: [bundle=ClassPathTest_1.0.0]
bundles parent java.net.URLClassLoader@126e85f
bundles parent sun.misc.Launcher$AppClassLoader@7d772e
bundles parent sun.misc.Launcher$ExtClassLoader@11b86e7


Class loader hierarchy for org.osgi.framework.BundleActivator

**************System bundle 0*******************
bundle classloader java.net.URLClassLoader@126e85f
bundles parent sun.misc.Launcher$AppClassLoader@7d772e
bundles parent sun.misc.Launcher$ExtClassLoader@11b86e7
I bundles parent null


Created a dummy class and added this in the classpath of dm server startup.bin.Also modified to include this java6-server.profile as org.osgi.framework.system.packages = \
(I did import this package in my test bundle)

*************SYSTEM PATH**************
bundle classloader sun.misc.Launcher$AppClassLoader@7d772e
bundles parent sun.misc.Launcher$ExtClassLoader@11b86e7
bundles parent null
I parent null


Created a dummy class and added this in the classpath of dm server startup.bin.Also modified to include this java6-server.profile as org.osgi.framework.bootdelegation = \
(Did not import this package in my test bundle)


*************BOOT PATH**************

bundle classloader sun.misc.Launcher$AppClassLoader@7d772e
bundles parent sun.misc.Launcher$ExtClassLoader@11b86e7
I bundles parent null
I parent null

 
Free Domain Names @ .co.nr!