31/01/2012

r-OSGi remote OSGi example

In this post we will give a fair example of the workings of the OSGi services remoted through r-OSGi.


In order for the example to work, we must have an OSGi framework with the r-OSGi extension. Also, make sure the 9278 port on your system is free as r-OSGi uses it for its purposes.



Suppose we have a remotable service: HelloService, its interface: IHello and a client who declares a dependency on the service by pointing to its interfaces. It would also like to be able to access it remotely.

When a component declares it provides a service, the OSGi framework stores that information in its internal registry.


Download here the example's source code. You should be able to import everything inside Eclipse as-is. Inside you will find:


Interface - IHello.java:

package it.eng.test.remote.hello;
public interface IHello {   
    public String sayHello(String from);

}

Implementation - HelloService.java:

package it.eng.test.remote.helloservice;
import it.eng.test.remote.hello.IHello;
public class HelloService implements IHello{
    public String sayHello(String from){
        return "Hello from "+from;
    }
   
}



As we can see, the service offers a single, simple method which returns a String.

The service also uses a BundleActivator to register the service as remotable on the framework:

package it.eng.test.remote.helloservice;
import it.eng.test.remote.hello.IHello;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import ch.ethz.iks.r_osgi.RemoteOSGiService;
public class Activator implements BundleActivator {
    private BundleContext context;
    public BundleContext getContext() {
        return context;
    }
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void start(final BundleContext context) throws Exception {
          final Hashtable properties = new Hashtable();
          properties.put(RemoteOSGiService.R_OSGi_REGISTRATION, Boolean.TRUE);
          context.registerService(IHello.class.getName(), new HelloService(), properties);
          System.out.println("Service registered.");
      }   
    public void stop(BundleContext bundleContext) throws Exception {
        context = null;
    }

}


The client is, for simplicity only, composed just by the BundleActivator. When started it connects to the remote framework through its r-OSGi component to browse the available services and connect to the one it is interested in.

package it.eng.test.remote.helloconsumer;
import it.eng.test.remote.hello.IHello;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import ch.ethz.iks.r_osgi.RemoteOSGiService;
import ch.ethz.iks.r_osgi.RemoteServiceReference;
import ch.ethz.iks.r_osgi.URI;

public class Activator implements BundleActivator {
    private BundleContext context;
    public BundleContext getContext() {
        return context;
    }
    public void start(final BundleContext context) throws Exception {
          final ServiceReference serviceRef = context.getServiceReference(RemoteOSGiService.class.getName());
          if (serviceRef == null) {
              System.out.println("R-OSGi service not found!");
          } else {
              final RemoteOSGiService remote = (RemoteOSGiService) context.getService(serviceRef);
              try {
                  remote.connect(new URI("r-osgi://192.168.23.96:9278"));

                  final RemoteServiceReference[] references = remote.getRemoteServiceReferences(
                      new URI("r-osgi://192.168.23.96:9278"), IHello.class.getName(), null);
                  if (references == null) {
                      System.out.println("Service not found!");
                  } else {
                      final IHello hello = (IHello) remote.getRemoteService(references[0]);                      System.out.println(hello.sayHello(System.getProperty("os.name")));
                  }
              } finally {
                  context.ungetService(serviceRef);
              }
          }
      }
   
    public void stop(BundleContext bundleContext) throws Exception {
        context = null;
    }

}

The consumer firstly checks for the r-OSGi component presence, then uses it to connect to another r-OSGi enabled framework located at the address hardcoded in the Activator itself.


After the connection is established, he browses the remote framework's services to find the IHello implementation; if it is there, he attaches to it and prints "Hello from OS\_NAME" on standard output before unbinding from the service.

7 comments:

  1. Hello,I am having problems when running this simple example. Could you hint on how to resolve this? Thanks in advance.
    service side:
    g! Service registered.
    g! lb
    START LEVEL 1
    ID|State |Level|Name
    0|Active | 0|System Bundle (4.0.3)
    1|Active | 1|jslp-osgi (1.0.0.RC2)
    2|Active | 1|Apache Felix Bundle Repository (1.6.6)
    3|Active | 1|Apache Felix Gogo Command (0.12.0)
    4|Active | 1|Apache Felix Gogo Runtime (0.10.0)
    5|Active | 1|Apache Felix Gogo Shell (0.10.0)
    6|Active | 1|osgi.cmpn (4.2.0.200908310645)
    7|Active | 1|R-OSGi Remote Service (1.0.0.RC1)
    8|Active | 1|R-OSGi SLP Service Discovery (1.0.0.RC1)
    9|Active | 1|it.eng.test.remote.hello (0.0.0)
    10|Active | 1|it.eng.test.remote.helloservice (0.0.0)
    g!

    client side:
    C:\develop\felix-framework-4.0.3_client>java -jar bin/felix.jar
    ERROR: Bundle it.eng.test.remote.helloconsumer [10] Error starting file:/C:/deve
    lop/felix-framework-4.0.3_client/bundle/zit.eng.test.remote.helloconsumer.jar (o
    rg.osgi.framework.BundleException: Activator start error in bundle it.eng.test.r
    emote.helloconsumer [10].)
    ch.ethz.iks.r_osgi.RemoteOSGiException: Could not install the generated bundle C
    :\develop\felix-framework-4.0.3_client\.\felix-cache\bundle1\data\IHelloImpl_per
    vasivecloud_jchicc.jar
    at ch.ethz.iks.r_osgi.impl.ChannelEndpointImpl.fetchService(ChannelEndpo
    intImpl.java:697)
    at ch.ethz.iks.r_osgi.impl.RemoteOSGiServiceImpl.fetchService(RemoteOSGi
    ServiceImpl.java:686)
    at ch.ethz.iks.r_osgi.impl.RemoteOSGiServiceImpl.getRemoteService(Remote
    OSGiServiceImpl.java:636)
    at it.eng.test.remote.helloconsumer.Activator.start(Activator.java:43)
    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAct
    ion.java:645)
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:1977)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:1895)
    at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)

    at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStart
    LevelImpl.java:295)
    at java.lang.Thread.run(Thread.java:662)
    Caused by: java.lang.IllegalArgumentException: Unable to parse header: org.osgi.
    framework, ch.ethz.iks.r_osgi, ch.ethz.iks.r_osgi.types, ch.ethz.iks.r_osgi.chan
    nels, it.eng.test.remote.hello; version="[1.0
    at org.apache.felix.framework.util.manifestparser.ManifestParser.parseSt
    andardHeader(ManifestParser.java:1720)
    at org.apache.felix.framework.util.manifestparser.ManifestParser.(
    ManifestParser.java:161)
    at org.apache.felix.framework.BundleRevisionImpl.(BundleRevisionIm
    pl.java:114)
    at org.apache.felix.framework.BundleImpl.createRevision(BundleImpl.java:
    1196)
    at org.apache.felix.framework.BundleImpl.(BundleImpl.java:95)
    at org.apache.felix.framework.Felix.installBundle(Felix.java:2732)
    at org.apache.felix.framework.BundleContextImpl.installBundle(BundleCont
    extImpl.java:165)
    at org.apache.felix.framework.BundleContextImpl.installBundle(BundleCont
    extImpl.java:138)
    at ch.ethz.iks.r_osgi.impl.ChannelEndpointImpl.fetchService(ChannelEndpo
    intImpl.java:685)
    ... 9 more
    ____________________________
    Welcome to Apache Felix Gogo
    g! lb
    START LEVEL 1
    ID|State |Level|Name
    0|Active | 0|System Bundle (4.0.3)
    1|Active | 1|R-OSGi Remote Service (1.0.0.RC1)
    2|Active | 1|jslp-osgi (1.0.0.RC2)
    3|Active | 1|R-OSGi SLP Service Discovery (1.0.0.RC1)
    4|Active | 1|Apache Felix Bundle Repository (1.6.6)
    5|Active | 1|Apache Felix Gogo Command (0.12.0)
    6|Active | 1|Apache Felix Gogo Runtime (0.10.0)
    7|Active | 1|Apache Felix Gogo Shell (0.10.0)
    8|Active | 1|osgi.cmpn (4.2.0.200908310645)
    9|Active | 1|it.eng.test.remote.hello (0.0.0)
    10|Resolved | 1|it.eng.test.remote.helloconsumer (0.0.0)
    g!

    ReplyDelete
    Replies
    1. Cheers,

      this line:

      Caused by: java.lang.IllegalArgumentException: Unable to parse header: org.osgi.
      framework, ch.ethz.iks.r_osgi, ch.ethz.iks.r_osgi.types, ch.ethz.iks.r_osgi.chan
      nels, it.eng.test.remote.hello; version="[1.0

      makes me think there's a problem with your MANIFEST. Could you post it?

      Thank you

      Delete
    2. Thanks to help me, I use bnt-tools to build them, there are the two manifest files :

      Manifest-Version: 1.0
      Bnd-LastModified: 1363058871810
      Bundle-Activator: it.eng.test.remote.helloservice.Activator
      Bundle-ManifestVersion: 2
      Bundle-Name: it.eng.test.remote.helloservice
      Bundle-SymbolicName: it.eng.test.remote.helloservice
      Bundle-Version: 0
      Created-By: 1.6.0_38 (Sun Microsystems Inc.)
      Import-Package: it.eng.test.remote.hello;version="[1.0,2)",org.osgi.fram
      ework;version="[1.5,2)"
      Private-Package: it.eng.test.remote.helloservice
      Tool: Bnd-1.51.0

      Manifest-Version: 1.0
      Bnd-LastModified: 1363053517199
      Bundle-Activator: it.eng.test.remote.helloconsumer.Activator
      Bundle-ManifestVersion: 2
      Bundle-Name: it.eng.test.remote.helloconsumer
      Bundle-SymbolicName: it.eng.test.remote.helloconsumer
      Bundle-Version: 0
      Created-By: 1.6.0_38 (Sun Microsystems Inc.)
      Import-Package: ch.ethz.iks.r_osgi,it.eng.test.remote.hello;version="[1.
      0,2)",org.osgi.framework;version="[1.5,2)"
      Private-Package: it.eng.test.remote.helloconsumer
      Tool: Bnd-1.51.0

      Delete
    3. I did not use that tool to create the MANIFEST; I'm a little puzzled as to why the service bundle started without issues but the consumer didn't even though the MANIFESTs are pretty much the same. Could you try to change your MANIFEST to:

      Manifest-Version: 1.0
      Bundle-ManifestVersion: 2
      Bundle-Name: Helloconsumer
      Bundle-SymbolicName: it.eng.test.remote.helloconsumer
      Bundle-Version: 1.0.0.qualifier
      Bundle-Activator: it.eng.test.remote.helloconsumer.Activator
      Bundle-ActivationPolicy: lazy
      Bundle-RequiredExecutionEnvironment: JavaSE-1.6
      Import-Package: it.eng.test.remote.hello,
      org.osgi.framework;version="1.3.0"
      Require-Bundle: ch.ethz.iks.r_osgi.remote;bundle-version="1.0.0"

      Replacing the "version" attribute with yours, if needed and the "Bundle-SymbolicName", "Bundle-Activator" and "Import-Package" attributes too if you renamed them. Also, how did you compile/export your packages? You should have a look at the first guide in the article (http://www.vogella.com/articles/OSGi/article.html) on how to compile and export OSGi bundles since I based everything on it.

      Once exported, you may run them directly from Eclipse or in a standalone OSGi environment after having installed all dependencies on it; in this case, all r_osgi bundles.

      To start with a basic test, are you able to compile and run the downloadable example as is, without any modifications? You should be able to start the two bundles but get the "Service not found error" if your IP is not 192.168.23.96.

      If you get there, try and change it with your IP in the consumer's Activator class then run the example again, at this point it should work.

      Delete
    4. hi, thanks again for your help. I try it again without using the Bndtools, and i succeed in running them! I think the problems exists in service side that its manifest doesn't import "ch.ethz.iks.r_osgi"(after i configured it, the Bndtools didn't import it automatically), the final manifest of helloservice is as followed:
      Manifest-Version: 1.0
      Bundle-Version: 1.0.0.201303131130
      Bundle-Name: Helloservice
      Bundle-Activator: it.eng.test.remote.helloservice.Activator
      Bundle-ManifestVersion: 2
      Import-Package: ch.ethz.iks.r_osgi,it.eng.test.remote.hello,org.osgi.f
      ramework;version="1.3.0"
      Bundle-SymbolicName: it.eng.test.remote.helloservice
      Bundle-RequiredExecutionEnvironment: JavaSE-1.6
      the helloconsumer’s manifest at client side is pretty similar with it. ^_^

      Delete
    5. Cheers,

      nice to hear, good luck for your future experimentation

      Delete
  2. This comment has been removed by the author.

    ReplyDelete

With great power comes great responsibility.

Da grandi poteri derivano grandi responsabilità.