Tuesday, April 14, 2009

Customized service object creation with iPOJO

The last week, I attended to the OSGi in Action talk organized by the Java User Group Berlin – Brandenburg. Karl did a very nice talk, but I was definitely more interested by the questions ☺
One of the questions was about the service object creation policy. The person asking for this, was a little worried by the default OSGi policy: publishing the service object itself in the service registry. I can understand his issue: why creating something not necessary needed (lazy creation), and how can I deal with multiple service objects.

So, the answer is definitely the Service Factory. When publishing a service factory instead of the service object, the framework notifies you each time a NEW bundle asks for a service object. So, you can create the service object at the first call or create one service object each time a new bundle asks for the service. In fact, the OSGi framework caches the returned object in order to improve performance.

However, it’s weird to add this “bundle” concept there. How I can create one service object per call or per user, or per thread? Those creation policies make sense in a lot of context. The traditional OSGi answer relies on the “Facade” design pattern. You registers an object that delegate the invocation on the “good” object. You can create the “good” object regarding to your creation policy.

However, I was never really happy to implement this facade pattern in the code. Why? Just because it’s typically something that:
  1. Pollute your code
  2. Can be externalized
Inside iPOJO, I tried to remove this limitation by adding a third creation policy. It is possible to provide a service and to create one service object per asking instance. So, two instances will use two different service object despite they are in the same bundle!

In fact, iPOJO provides a way to specify your own creation strategy. Imagine that you have a specific creation policy. Just implement the desired behavior by creating a class extending CreationStrategy. Moreover, iPOJO brings a new concept called IPojoServiceFactory closed to OSGi Service Factory but based on instance. So, if an iPOJO instance requires a service implementing this interface, the iPOJO container will call a special method to get the service object. This method will be called every time the service is get (so not only once per instance). However the creation strategy may decide to return always the same service object for one instance (per instance strategy).

So, how I can create my own fine-grained creation policy?

Just create a class extending the CreationStrategy class and implements the IPOJOServiceFactory interface.

So, let’s say that your OSGi Service Factory getService method is called. So you return a proxy/facade extending the IPOJO Service Factory interface like in

public Object getService(Bundle arg0, ServiceRegistration arg1) {
Object proxy = Proxy.newProxyInstance(getInstanceManager().getClazz().getClassLoader(),
getSpecificationsWithIPOJOServiceFactory(m_serviceSpecification, m_handler.getInstanceManager().getContext()), this);
return proxy;
}

When another iPOJO instance will asks for your service, it will call the iPOJO Service Factory getService method. Then, you intercept this method and apply your creation strategy. For example, the next snippet shows the per instance creation strategy:

public Object invoke(Object arg0, Method arg1, Object[] arg2) {
if (isGetServiceMethod(arg1)) {
return getService((ComponentInstance) arg2[0]);
}

if (isUngetServiceMethod(arg1)) {
ungetService((ComponentInstance) arg2[0], arg2[1]);
return null;
}

throw new UnsupportedOperationException("This service requires an advanced creation policy. "
+ "Before calling the service, call the getService(ComponentInstance) method to get "
+ "the service object. ");
}


public Object getService(ComponentInstance instance) {
Object obj = m_instances.get(instance);
if (obj == null) {
obj = m_handler.getInstanceManager().createPojoObject();
m_instances.put(instance, obj);
}
return obj;
}

public void ungetService(ComponentInstance instance, Object svcObject) {
Object pojo = m_instances.remove(instance);
m_handler.getInstanceManager().deletePojoObject(pojo);
}


You can easily change this code to implement your own strategy like one per thread... As you get the ComponentInstance object, you can easily look for properties… and so create very sophisticated strategies.

So, thanks to this mechanism, you can creation you own policy and refer to it from your provides metadata:

<component
classname="…FooBarProviderType">
<provides strategy="….MyCreationStrategy">
</component>


That’s it!

The main and major limitation of these strategies is that they rely on iPOJO. So both the provider and the consumer have to be developed with iPOJO to deal correctly with the new service object creation policy. So, just use iPOJO ;-)

1 comment:

Adrian said...

Hello,

thanks for the tutorial, but I really don't get it to work, as it isn't up to date with the current version of iPojo and doesn't contain a full example.

Would be great if you could provide a tutorial with a working example.