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.qualifierIn 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: 45643If 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: 9000Now 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");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.qualifierIn 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.ServiceExampleAfter 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: toledomeanwhile, in the server:
Server: Elemento Añadido 1
Server: Elemento Añadido 2
Server: Elemento Añadido 3
Server: Elemento borrado1
server: returning listYou will find the source code inside the bundles.


