Friday

The OSGi and the Services issue

Few months ago, i had introduce the Open Service Gateway initiative in a post, as trying to make a solid ground for the association of posts concerning the ServiceMix related posts, for introducing a simplistic usage of open source tools on S.O.A. related projects. From that time and on, we were introduced to a wide adoption of OSGi methodology and approach by developers and vendors (both legacy and open source). This fact gives the option and possibility to consider OSGi technology as technology that will transform Java development. Specially on the enterprise side.

To establish a point of useful OSGi, i am giving a quick example on how to build a simple service and consume it. This is quite useful in the S.O.A. development, considering it as a step in the development tasks of the reference architecture that one should follow in a S.O.A. enabled solution and approach. Specially when in a small team the object is cheap (cost and time) development considering services.

You may start and work with Equinox and Eclipse IDE. You may also use other OSGi runtime like Apache Felix or Knopflerfish. Knopflerfish even gives you are good GUI to work with. I will not be explaining fundamentals of OSGi technology.The goal here is to be a little bit more simplistic and independent, in order to be able to work with any other IDE, approach or tools you might prefer. So here we are concerned with a simple application (bundle).  Lets start with.

What's OSGi service?

In very general terms, conforming with S.O.A. re-use, a service is a … repeatable task. When it comes to business, any repeatable task in your business process is a service. Similarly in a application, you can have generic tasks (even specific tasks) that are repeatedly used and therefore, can be represented as service. Representing and using these tasks as services is what SOA is all about! But that' at an enterprise level. When it comes to OSGi services, it is the same concept but applied at JVM level.
In OSGi, a service is a plain java object which is published to a registry. A consumer can consume the registered service through lookup. A service a be registered and unregistered at any point of time. Service is built using interface-based programming model. To implement or build a service you basically provide implementation to a interface. To consume, you only need the interface for the lookup and there is no need to know about the implementation. The service registry is the "middle man" who help producers and consumers to get in touch with each other.

Building STARTUPOSGISRVservice

The first step would be to create our interface or "front end" of the service. For our service, we will have a simple interface named IStartupOSGISRV:

package org.my.service.startupservice;

public interface IStartupOSGISRV {
public String sayHi();
}


And here is our service implementation.



package org.my.service.startupservice;

public class StartupOSGISRV implements IStartupOSGISRV {
public String sayHi() {
return "Hi There!";
}
}


That's it! Our service is ready for use. But, we need to inform consumers that the service is ready to serve. For this, we will have to register our service with the OSGi service registry.

OSGi framework provides us with standard APIs to register and unregister service with the registry. We will use the registerService method to register as shown below:



serviceRegistration = context.registerService(IStartupOSGISRV.class.getName(),startupservice,null);


I am sure for beginners this is not enough. Let's explain the stuff little further.To register our new service, we will build a simple bundle that will call registerService method.



package org.my.service.startupservice;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

public class Activator implements BundleActivator {

private ServiceRegistration serviceRegistration;
private IStartupOSGISRV startupservice;

public void start(BundleContext context) throws Exception {
System.out.println("Starting StartupServiceBundle..");
startupservice= new StartupService();
serviceRegistration = context.registerService(IStartupOSGISRV .class.getName(),startupservice,null);

}

public void stop(BundleContext context) throws Exception {
serviceRegistration.unregister();
}

}


Our Activator class implements BundleActivator. Basically, its a simple OSGi bundle with start and stop methods. We will register our service with the bundle starts up and unregister when the bundle is uninstalled from the framework.

Now lets have a closer look at start method. We create a instance of our service and then use registerService method. The first argument is service name which is obtained using InterfaceName.class.getName(). Its a best practice to use this method instead of specifying the name as string (org.my.service.startupservice.IStartupOSGISRV). The second argument is the instance of the service itself. And the final argument is Map wherein developers can pass additional properties to the service.


To unregister the service, you simple call unregister method when we stop the bundle. So now we have a running service on our OSGi runtime.  Now we must consume it.



 



Consuming a service



To consume a service, we first create serviceReference object form the BundleContext. This can be achieved by calling getServiceReference method. The method takes the class name as a argument. Once you have the serviceReference object, we will use getService method to finally get the service. We will have to typecast the object returned by getService method before using it.



startupserviceRef = context.getServiceReference(IHelloService.class.getName());
IStartupOSGISRV serviceObjectStartupService = (IStartupOSGISRV)context.getService(startupserviceRef);
System.out.println("Service says: " + serviceObjectStartupService.sayHi());


Implementing the service and consumer is the same package is easy. Because, the interface is available. When you have your service and consumer bundle separate, there are some important points to note. OSGi provides the capability of specifying the packages they can be exported or imported. With this facility you can expose your service interface and hide its implementation from the public. The configuration details are specified in the MANIFEST file. Have a look at our StartupService's MANIFEST file:



Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: StartupService Plug-in
Bundle-SymbolicName: StartupService
Bundle-Version: 1.0.0
Bundle-Activator: org.my.service.startupservice.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: org.osgi.framework;version="1.3.0"
Export-Package: org.my.service.startupservice;uses:="org.osgi.framework"


Notice that we have exported org.my.service.startupservice package. Similarly, we import this package in our consuming bundle.

And to add some notes; The code used for consuming the service is not the best way. You should make the code very simple and easy to understand without involving Exceptions handling,Null pointer checks and ServiceListeners.

No comments: