McM
mcm@noway.es
Contact me: noway.es
Contact me

OSGI Remote Services: Distributed OSGI

Here I present a simple example of distribution of OSGI services across virtual machines. This is really easy to implement using the OSGI standard for distributed services.
This came up recently in this year (2009). In the specification you will find the properties you must set on your OSGi Service to declare that it should be remoted.

What we need

  • Service interface and data object to be exchanged preferably in an isolated bundle.
  • Server side implementation and configuration
  • Client Side implementation and configuration
  • Apache CXF service

Service

It is recommended to have a exclusive bundle for the services and the object you want to exchange remotely.

In this example the bundle com.as.remote.osgi.service_1.0.0.200909171749.jar will have the interface of the remote OSGI service and the data Object.

  • DeviceExample.java
  • ServiceExample.java
    public interface ServiceExample {

        int addNewDevice(int id, String name, String location);
        void delenteDevice(int id);
        Collection <DeviceExample> getItems();
        DeviceExample getItem (int id);

    }

We can see how a data object is returned in the las method.

Important note!

  • Besides the standard hashCode(), equals() and toString(), etc, only JavaBean
    style setter and getter methods are supported
    . This means that you probably
    have to design your datatypes specifically to suit the remote invocation
    scenario

Server Side

In the server side we will have a dummy implementation of the the service ( interface ServiceExample) but the most important thing is when you register the service to the OSGI framework, in this case with a simple activator:

        Dictionary props = new Hashtable();
        props.put("osgi.remote.interfaces", "*");
        props.put("osgi.remote.configuration.type", "pojo");
        props.put("osgi.remote.configuration.pojo.httpservice.context", "/remoteService");
      

This properties are compulsory in order to register the bundle to be accessed remotely.
In this properties you register in which interfaces your services can be accessed:

props.put("osgi.remote.interfaces", "*");

This means that I declare all the interfaces passed to bundleContext.registerService() are suitable for remoting. Change * for any IP you want in your machine.

These are the only properties you will need to declare the bundle
I have called this bundle: com.as.remote.osgi.serviceImpl_1.0.0.200909171749.jar.

Now you will be able to run the server. To run an OSGI distributed service we will use the Distributed OSGi DSW Reference Implementation which is based on Apache CXF that you can find here: http://cxf.apache.org/dosgi-releases.html.

We use the standalone OSGI version cxf-dosgi-ri-singlebundle-distribution-1.0.jar

Just download it and install it in your framework.
Here is my target platform:

osgi> ss

Framework is launched.

id State       Bundle
0 ACTIVE      org.eclipse.osgi_3.5.0.v20090520
1 ACTIVE      org.eclipse.osgi.services_3.2.0.v20090520-1800
7 ACTIVE      cxf-dosgi-ri-singlebundle-distribution_1.0.0
11 ACTIVE      com.as.remote.osgi.serviceImpl_1.0.0.qualifier
12 ACTIVE      com.as.remote.osgi.service_1.0.0.qualifier

In the log, you will see how our service is ready to be remoted:

INFO: publication properties: {osgi.remote.endpoint.location=http://McM:55284/remoteService, osgi.remote.discovery.publication.service.properties={osgi.remote.configuration.type=pojo, osgi.remote.configuration.pojo.httpservice.context=/remoteService, osgi.remote.interfaces=*, osgi.remote.endpoint.location=http://McM:55284/remoteService}, osgi.remote.service.interfaces=[com.as.remote.osgi.service.ServiceExample], osgi.remote.endpoint.id=e3106fae-f195-4526-b6f5-26fcd9eee539}

by default it will run on 8080 port but if it is busy, another random port will be used:

osgi> Port 8080 is not available. Setting HttpService port to: 45643

If you want to change the port, just use the OSGI property of the HTTP service, for example to port 9000:

org.osgi.service.http.port - specifies the port number to use for the http serving. The default value for this property is 80 (which requires root permission), as per the OSGi specification.

In this case, you will see at the console:

osgi> HttpService using port: 9000

Now the service will be accesibled by port 9000. The service ServiceExmple is now remoted using Web Services.

The most amazing is that the service is available via SOAP over HTTP. Apache CXF generate automatically a WSDL file. In this example you can access using your browser: http://127.0.0.1:8080/remoteService?wsdl

because you configured it in the properties of the OSGI bundle (the servlet context):

props.put("osgi.remote.configuration.pojo.httpservice.context", "/remoteService");

remote osgi service

Client Side

This bundle is a normal OSGI bundle. In this example, com.as.remote.osgi.client_1.0.0.200909171749.jar is the client. I will use a simple service tracker to track the ServiceExample service. The only different file you will need is in the OSGI-INF folder, within remote-service folder:

<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
<service-description>
  <provide interface="com.as.remote.osgi.service.ServiceExample"/>
  <property name="osgi.remote.interfaces">192.168.1.112</property>
  <property name="osgi.remote.configuration.type">pojo</property>
  <property name="osgi.remote.configuration.pojo.address">
   http://192.168.1.112:8080/remoteService/
  </property>
</service-description>
</service-descriptions>

You can see that the property osgi.remote.interfaces is set to an IP because I ran the example in a different computer.

You will need to run the example with the Apache CXF single bundle distribution and copy of the bundle with the remote data object and service. Here is the target platform:

osgi> ss

Framework is launched.

id State       Bundle
0 ACTIVE      org.eclipse.osgi_3.5.0.v20090520
3 ACTIVE      org.eclipse.osgi.services_3.2.0.v20090520-1800
4 ACTIVE      cxf-dosgi-ri-singlebundle-distribution_1.0.0
5 ACTIVE      com.as.remote.osgi.client_1.0.0.qualifier
8 ACTIVE      com.as.remote.osgi.service_1.0.0.qualifier

In the console you will see how the remote service is discovered and retrieved:

INFO: Creating Service {http://service.osgi.remote.as.com/}ServiceExample from class com.as.remote.osgi.service.ServiceExample

After that, you will see the log:
" Remote client: ServiceReference retrieved
Remote client: interacting with server"

Running the simple example

You can download the sever side here
and the client side here

Uncompress the server and the client.

start the server:

mcm@McM:~/Desktop/server$ sh start.sh

start the client:

mafalda:/tmp/client# sh start.sh

In the client side you will see the following log:

Remote client: ServiceReference retrieved
Remote client: interacting with server
remote Device retrieved. Location: toledo
remote client: deleting device 1 ...
*******************************
id:  1
name: miki
location: madrid
*******************************
id:  3
name: pp
location: toledo

meanwhile, in the server:

Server: Elemento Añadido 1
Server: Elemento Añadido 2
Server: Elemento Añadido 3
Server: Elemento borrado1
server: returning list

You will find the source code inside the bundles.

Share it!

Twitter Gmail Delicious Google Bookmarks Hotmail Yahoo Mail Share/Bookmark