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 ;-)

Wednesday, April 1, 2009

iPOJO and File Install : configuring iPOJO instances with 'cfg' files

FileInstall is a great bundle to provision your system. It watches a directory and installs every bundles contained inside the directory. Moreover, it’s fully support the configuration admin. So, it reads .cfg files contained in the folder and pushes the read configuration into the configuration admin.

iPOJO also supports the configuration admin. iPOJO instances can be created, deleted and reconfigured from the configuration admin.

So, why not creating, reconfiguring and deleting iPOJO instances from the cfg files.

File Install philosophy


File install is great and simple. It just has one general idea to understand:

The content of the watched folder is your system configuration

So, if you create cfg files inside this folder, those files will be analyzed and the configuration pushed in the configuration admin. To remove the configuration, just remove the file from the folder!

Note: Don’t forget to install the configuration admin

Using File install to create instances


When you declare an iPOJO component, this will expose a ManagedServiceFactory service. [Except if you voluntary set the component type to private]. This service can be used to create / reconfigure/ delete instances of this component type.

So, let’s say that we have the following bar.Foo class:

@Component
public class Foo {
@Property
private String name;


}

This declare an iPOJO component type (named bar.Foo (i.e. the classname) as no name is specified). This component type also declares a property (name).

So, once deployed, iPOJO will exposed a ManagedServiceFactory service with the ‘bar.Foo’ service pid. The configuration admin will push all matching configuration to this ManagedServiceFactory.

Now, let’s say that File install watches the ‘load’ folder. If you create a file named bar.Foo-1.cfg containing the following content:
name = the name
Once saved, File Install will find it, analyzes it and pushes the configuration to the configuration admin. The configuration admin will pushes this configuration to our ManagedServiceFactory, and so we just create an instance of our type!

So, cfg files completely replaces the tag of iPOJO metadata files. You no more need them (if you use annotations).

Let’s create a second file named bar.Foo-2.cfg containing the following content:
name = the second name
This will create another instance.

Reconfiguring an instance


To reconfigure an instance, just edit the cfg file. For example, edit the bar.Foo-2.cfg and change the name property to ‘a third name’. The instance will be automatically reconfigured.

Deleting an instance


To delete an instance, just remove the cfg file (containing the instance configuration) from the file install folder. That’s it! The watched folder is your system configuration.

The ManagedService case


So, let’s imagine that you don’t want to create instances from cfg file but just reconfiguring them. It’s also possible. File install also supports Managed Service, and so, will pushed a Managed Service configuration inside the configuration admin.

If you use this way, you have to create the instance yourself (from the metadata.xml file for example).
First, let’s modify our component type:

@Component(managedservice="MyPID")
public class Foo {
@Property
private String name;


}

and create the metadata.xml file declaring an instance of this type:

<ipojo>
<instance component="bar.Foo"/>
</ipojo>

The “managedservice” attribute of the @Component annotation allows setting the service pid of the Managed Service. So, iPOJO will expose a ManagedService allowing reconfiguring your instance with the “MyPID” pid. [You can also set the managedservice pid from the instance configuration].
So, to reconfigure the instance, create a cfg file named MyPID.cfg containing the configuration such as:
name = a name

When you save the file in the watched folder, File install will pushes the configuration to the configuration admin. Then, the configuration admin will look for the matching ManagedService (the one with the MyPID service.pid) and pushed the configuration. So, your instance will receives the configuration!

To edit the configuration, just edit the cfg file. To remove it, just remove the file from the folder.

Conclusion


File install is definitely a great tool to provision your system. The configuration admin supports can be useful to create iPOJO applications “on the fly” and will allows you reconfiguring your system dynamically!