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.
Hello,I am having problems when running this simple example. Could you hint on how to resolve this? Thanks in advance.
ReplyDeleteservice 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!
Cheers,
Deletethis 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
Thanks to help me, I use bnt-tools to build them, there are the two manifest files :
DeleteManifest-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
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:
DeleteManifest-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.
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:
DeleteManifest-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. ^_^
Cheers,
Deletenice to hear, good luck for your future experimentation
This comment has been removed by the author.
ReplyDelete