There were quite a number of questions on the webinar and I didn't get to answer all of them, so I'm providing some answers here. For those of you who missed the webinar, you can still view the recorded version of the Distributed OSGi webinar here.
The source code of the GreeterDemo that I used during the demo session can be found in the Apache CXF demos SVN here: http://svn.apache.org/repos/asf/cxf/dosgi/trunk/samples/greeter for details on how to run the demo see the demo walkthrough page on the CXF Distributed OSGi website.
Below are the questions asked during the webinar, and an attempt to answer them. Feel free to send comments if I missed anything…
Q: Does it use RMI?
A: The wire-protocol and data-binding used are not specified by Distributed OSGi. They are up to the implementation. The Apache CXF implementation used in the demo uses SOAP/HTTP but other implementations could be written to use other wire protocols, such as RMI.
Q: Why don't you use JaxWS?
A: It's all about choice for the developer. JaxWS is a specific programming model for Web Services in Java. Distributed OSGi is for those who like the OSGi Services programming model, and would like to stay within that programming model to distribute OSGi services. It's not incompatible with other programming models, such as JaxWS, JaxRS, CORBA etc and can be used alongside them.
Q: Can I used Distributed OSGi services from Visual Basic?
A: Yes you can! Visual Basic programs can invoke on Web Services that are defined by WSDL. If you use the Apache CXF Distributed OSGi implementation it will generate a WSDL for your OSGi service which you can use from your Visual Basic client.
Q: Is there an implementation of Distributed OSGi available in Open Source?
A: Yes, the Apache CXF implementation, Eclipse ECF implementation and Apache Tuscany implementation are all open source and freely available to everyone.
Q: Can I use Distributed OSGi services from an Ajax browser client?
A: Yes, this is possible. I wrote an example of this on this blog a little while ago, see here: http://coderthoughts.blogspot.com/2009/02/distributed-osgi-powered-ajax-webapp.html.
Q: Can i use cxf with equinox, specifically pre 3.5?
A: The short answer is no, but you can use the current betas of Equinox 3.5 (builds since December). Any implementation of Distributed OSGi will need the Service Registry Hooks. Since this is a new API, it is only available in Equinox 3.5 and Apache Felix 1.4.1 or newer.
Q: Why is it based on webservices?
A: The design of Distributed OSGi is not based on Web Services and you may find implementations that don't use web services at all. The Apache CXF implementation is based on Web Services. Web services provide a standards-based approach for distributing software and allow integration with other (non-OSGi) systems. Although not required per se by an implementation of RFC 119, ‘Legacy integration' is one of the use cases that drove the design of Distributed OSGi, and by using Web Services this use-case can be addressed.
Q: You are using CXF for cross-jvm/osgi communication and mentioned that the rfc does not define the communication protocol. Does that mean that it is possible to implement a custom communication protocol?
A: Absolutely!
Q: How can I specify which protocol(s) to be used for some remote service?
A: Use intents mechanism for that. The intents mechanism allows you to declaratively specify constraints on the remote service. In short, you can put a property on the service that you want to remote that declares using what binding/protocol you the service should be exposed. So you could do something like: osgi.remote.requires.intents=JMS which means that the service should only be exposed over JMS. If the Distribution Software (DSW) can't satisfy the intent, it will not be able to expose the service. Although some values (for SOAP and JMS) have been defined in the RFC for this property, the actual possible values depend on the Distribution Software implementation used.
Q: How do I set the discovery service dynamically without the remote-services.xml?
A: Use an RFC 119 compliant Discovery implementation, these don't use the remote-services.xml files. We're currently working on one in the Apache CXF codebase that is based on Apache Zookeeper, but other implementations, such as the one based on SLP at Eclipse ECF are also available.
Q: Can I specify more than one protocol for one service? For example Web Services, CORBA, RMI, etc.
A: If you specify the protocol to use using the osgi.remote.requires.intents mechanism as described above, you can only specify one. E.g. specifying that the service has to satisfy both the RMI and CORBA intent at the same time is a contradiction, however you can register the same POJO twice with the OSGi Service registry, once for each protocol.
Q: Is Discovery service a separate OSGi container?
The RFC 119 Discovery architecture typically uses a centralized Discovery Server (potentially a replicated one, like we have with the CXF/Zookeeper implementation). The Discovery Service in the OSGi container provides a standardized interface to such a Discovery Server. The Distribution Software (DSW) interacts with the Discovery Service in the local OSGi service registry, which then communicates with the centralized Discovery Server.
Q: Service Registry hooks- limiting visibility of service-This is similar to access control the service- what are your views on this? Thanks
A: I forwarded this question to BJ Hargrave from IBM, the main author of the Service Registry Hooks RFC, he provided the following answer: "It is more about controlling visibility to services (but I guess some people may call that access [see http://blog.bjhargrave.com/2009/03/i-am-visible-but-am-i-accessible.html]). But the primary purpose is not to secure the system since without a Security Manager installed, there is no actual security. Its primary purpose is to control service visibility to influence the services a bundle sees so that it selects a desired service rather than another service. For example, the proxy for X rather than X. "
Q: so if they [OSGi Services] don't implement any signature, how are they identified within the registry?
A: OSGi Services don't need to implement a particular OSGi signature or interface, but they would typically implement an interface that relates to their purpose. In the presentation I mentioned a Purchase Service, which implements a foo.bar.PurchaseService interface. Normally services are looked up via their interface, but you can also look up services in the OSGi Service Registry purely on other properties that they might have.
Q: When you say 'Dynamically come and go', can you elaborate on that what does that really mean?
A: Example: A running OSGi system. A consumer in that system might be using a service that satisfies its lookup criteria. While the system is running another service that also satisfies these criteria could arrive (either because a new bundle that creates this service is installed or because an existing bundle registers a new service). Depending on the consumer's requirements, it could now potentially be using both services, the old and the new one. At a later time one of the services might go away at which point the consumer will only be using the one that's left. All (properly developed) OSGi service consumers are capable of dealing with dynamics like this.
Q: is the WSDL, automatically generated by some tool?
A: Yes, the Apache CXF DOSGi implementation does this dynamically at runtime, based to the Java interface of the service. You don't have to run a tool for this with CXF, although other implementations might require the running of a tool to achieve something like this.
Q: What does pojo mean?
A: Plain Old Java Object.
Q: I suppose that the parameters of the service exposed are of type 'primitive' like int, string, double, DateTime but cannot be of type by example SessionFactory ?
A: It depends on the DOSGi implementation used. If you want your code to be suitable for a number of DOSGi implementations it's best to restrict the use of data types to primitives, collections and arrays. The CXF DOSGi implementation also supports classes and interfaces as part of the signature as long as they in turn are defined in terms of the data types mentioned.
Q: Can you highlight the security capabilities that are provided by distributed OSGi?
and Q: Can we secure the communication between remote OSGI servers (and authenticate, authorise access to the services)?
A: Security is a Quality of Service that DOSGi implementations could provide. The intents mechanism can be used to only select remote services that are secure, e.g. by requesting the ‘confidentiality' intent, or by requesting a custom intent (such as AcmeSecurity) that your deployer defines with the appropriate security configuration. For more information see chapter 5.5.3 of RFC 119 (in http://www.osgi.org/download/osgi-4.2-early-draft3.pdf).
Q: How do local discovery services know about other discovery services?
A: The Discovery Service registered in the OSGi container communicates with a centralized Discovery Server. This Discovery Service needs to be configured with the connection details of the central discovery server.
Q: what implementations of distributed OSGi will be available in Equinox 3.5? Anything faster than webservices?
A: Equinox 3.5 does not have any Distributed OSGi implementations, but Eclipse 3.5 provides the ECF implementation. I guess I'm wondering what really the performance difference is that you are looking for. Have you measured the performance of CXF webservices versus something else? Could you provide us with some target figures? I know that CXF performs pretty well…
Q: Can you specify multiple instance endpoints for the same service?
A: On the server side one remote service typically maps to one remote endpoint (although exceptions are possible, especially in case the service implements multiple interfaces some implementations will give you one endpoint per interface). If you want more endpoints you can always register more OSGi services for the same POJO (although I'm not sure what the use-case for that would be).
On the consumer side, the consumer can be informed of multiple remote endpoints satisfying the OSGi Service Lookup criteria, in which case the consumer could get multiple client-side proxies to the remote services.
Q: Can you talk more about discovery with ZooKeeper and how that would work?
A: In the CXF project I started implementing the RFC 119 Discovery implementation using Apache ZooKeeper as the underlying Discovery mechanism. ZooKeeper is based on a replicated central server that holds a virtual file system. Consumers connecting to the ZooKeeper server will all view the same filesystem which holds the discovery information. The way this works in practice is that you have your cluster (1 or more) of zookeeper servers running. The CXF Discovery implementation bundle is installed in your OSGi containers. It will communicate with the ZooKeeper server for the discovery information. The net effect is that the remote service consumers will see the remote services without needing any extra configuration.
Q: Question : Is there other org.osgi.remote.type foreseen (e.g. POJO) ? What is the particularity of the type 'POJO' except its name ?
A: The POJO configuration type is specific to CXF. There is one configuration type specified in RFC 119: SCA, which is optional. Using SCA as a way to configure Distributed OSGi will give you portability on the configuration level. CXF does not implement the SCA configuration type yet…
Q: Question : Will it be possible using 'blueprint or spring DM' to integrate remote OSGI with Spring XML file ?
A: Yes - there is a demo that comes with the CXF DOSGi implementation that uses Spring-DM to create a remote OSGi service and on the consumer side it uses Spring-DM to create the consumer. Distributed OSGi is orthogonal to any OSGi component model and should therefore work fine with any of them. See here for the demo code: http://svn.apache.org/repos/asf/cxf/dosgi/trunk/samples/spring_dm
Q: is it possible to load balance across distributed OSGi bundles?
A: Yes – if multiple remote instances exist the consumer could be informed about all of them: the consumer will get a service proxy for each remote instance. The consumer can use these to implement some load-balancing algorithm.
Q: Why does a copy of the interface and class have to live on the client?
A: Only the interface needs to be available to the service consumer. The implementation class does not. I think this is a very natural thing to do. If I write a consumer to a service, like a PurchaseService, I need to know the interface to that PurchaseService, how am I otherwise going to use this in a meaningful way? The interface is the contract between the consumer and the service provider. This is also the case for local OSGi Services. They can't use an OSGi service if they don't have access to the interface.
Q: It seems like you are cheating if you get a copy of the interface and class in your client code prior to starting the demo.
A: No I'm not cheating, only the interface is present in the consumer. When I run the consumer I can see that the value I'm entering in the consumer running in Felix is echoed in the Equinox server window. The implementation resides in Equinox.
Q: Does distributed OSGi support multiple instance of the same service and thus software based failover rof services across remote services?
A: Yes, see above.
Q: for properties is there a namespace type construct to prevent collisions? or is it inherent based on the scope of a service?
A: No there isn't really a namespace (although the Distributed OSGi properties use the osgi. prefix), but it is good practice to qualify your own properties with your own organization just like a Java package, e.g. com.acme.myproperty to avoid clashes.
Q: Are there standard properties of services, like names, that every OSGI service should define?
A: No. Its absolutely fine to register a service with no properties. OSGi will typically add a few properties, like service.id and objectClass but as a service provider you don't need to worry about these.
Q: How does a Discovery service, choose if the service is deployed both locally and remotely?
A: If a good match is available locally, DOSGi will not look for remote services. If you want to influence your match, forcing either a local or a remote match you can refine your lookup by adding extra criteria in the LDAP filter.
Q: Can the contract by dynamically found and transmitted remotely?
A: You could write a system to do this, as bundles can be installed at any time in a running OSGi system, but the Distributed OSGi standard doesn't define this.
Q: With multiple instances of the same service, would they have the same endpoint, or could they have different endpoints? How would a discovery pick which one?
A: The will have different endpoints. Everything being equal Discovery will simply inform you about all of them. If your consumer only needs to use one of them, which one the consumer will get is undefined. If the consumer has a preference for a particular one it needs to refine its filter to only match that one. You can also have the consumer receive proxies to all remote instances.
Q: Can you turn existing code (POJOs) into distributed OSGI services just using configuration (i.e. no java re-coding)?
A: Yes, OSGi Blueprint/Spring-DM provide a lot of support here. You configure them with an XML file that will instantiate your POJO and register it as an OSGi service.
Q: Are you familiar with the Paremus fabric, distributed OSGi runtime that uses SCA as the "wire-up" model? If so, does it use SCA in the way you described?
A: I'm not really familiar with this product, but I have seen demos of it. The SCA part of RFC 119 is really about defining qualities of service for the distributed services. It's not used for wiring services, the OSGi Service registry is used for that.
Q: Will both local and remote services be returned from a search?
A: There is no difference in the API to use to obtain local services or remote services. However, if appropriate local matches are available, the system won't look for remote services. If you want all local and remote matches you can do lookups with and without the osgi.remote property. The osgi.remote property is only set on proxies for remote services.
Q: Are there any drawbacks, using OSGI distributed services that you may know of?
A: None :) Seriously, yes remote computing is not the same as local computing. There are additional failure scenarios, additional latency, additional security impacts and so on. So if your system works perfect with all your services locally, keep it that way. However, if you want to distribute your OSGi services, then RFC 119 is a good way to do it!
Friday, May 8, 2009
Tuesday, April 21, 2009
Webinar and demo of Distributed OSGi (RFC 119) on Tue April 28
Just to let y'all know... I'll be doing a webinar and demo of Distributed Services OSGi on Tuesday April 28.
Distributed OSGi is a major new feature in the OSGi 4.2 specification. For more info, see http://fusesource.com/resources/video-archived-webinars
The demo will be done using the Apache CXF Reference Implementation.
Registration and attendance is free :)
Distributed OSGi is a major new feature in the OSGi 4.2 specification. For more info, see http://fusesource.com/resources/video-archived-webinars
The demo will be done using the Apache CXF Reference Implementation.
Registration and attendance is free :)
Monday, February 9, 2009
A Distributed OSGi Powered AJAX WebApp
A pretty cool new way of using Distributed OSGi services is from a non-OSGi environment. In the previous post I used an OSGi AuctionService from an OSGi AuctionConsumer in a different VM.
This posting is about using that OSGi service from a non-OSGi consumer. From an AJAX-powered web application that's running in the browser!
I'm writing the webapp using the Google Web Toolkit (GWT). Both the webapp as well as my OSGi service are hosted in the same OSGi container. With AJAX you can create a rich client application running inside the browser. So no Servlet/JSP style server-side execution. The webapp runs on the client machine. GWT makes creating the AJAX app easy: you write them in plain old Java. No need to sidestep into Javascript as GWT turns the Java into a Javascript AJAX app and all (well, almost) of the browser specific madness is taken care of by GWT too.
As with any website, the end-users users simply open it in their browser. No client install, no browser plugins. Any modern browser supports this stuff natively. Remote communication, such as obtaining a list of available items, listing a new item, placing a bid, is done via SOAP/HTTP calls directly on my OSGi AuctionService (the one from the previous posting) which has been remoted using the Apache CXF-based Distributed OSGi Reference Implementation.
To do all this I'm adding a component called Pax Web Extender to my OSGi container, on top of the Distributed OSGi bundles. Pax Web Extender turns the OSGi container into a web container which means that I can deploy a .WAR file into it. It internally leverages the OSGi HTTP Service. (Spring DM Server can do this too BTW).
My OSGi container is configured like this:

Besides the CXF Distributed OSGi and Pax-Web-Extender Bundles I have my AuctionService and AuctionInterface bundles deployed (see previous posting for the details), plus the .WAR file that holds my AJAX webapp.
The reason I can invoke my OSGi Service is because it was made available remotely over a standards-based mechanism. Distributed OSGi itself doesn't prescribe how you do your remoting, it only says that you can use standards-based wire protocols and bindings if you wish and that this can make OSGi Services available to non-OSGi consumers.
The CXF implementation of Distributed OSGi turns an OSGi Service into a Web Service that is accessible via SOAP/HTTP. GWT can already natively make remote HTTP invocations. I didn't actually even care looking for a SOAP library for GWT. SOAP is just XML and GWT has some pretty good XML parsing functionality.
The last thing that I need to worry about (besides security, but that's a separate topic) is the browser's single-origin policy. But hey: I've deployed my webapp in the same runtime as my OSGi Service so as long as I make them available over the same port there's no problem! I achieved this by sharing the same OSGi HTTP Service by both the Distributed OSGi runtime and the Pax Web Extender. Thanks to the OSGi Services architecture!
So I'm taking the AuctionService of the previous posting, but first of all I want to expose it on a slightly simpler URL. The default URL of http://localhost:9000/org/coderthoughts/auction/AuctionService is just a bit too long, let's use /auction as the context instead. I also want to make it use the OSGi HTTP Service (which CXF doesn't do by default). I can do both in one shot by setting the osgi.remote.configuration.pojo.httpservice.context service property to the value /auction. The HTTP Service that comes with CXF runs by default on port 8080 (you can change this by setting the org.osgi.service.http.port system property) so my Web Service now runs on http://localhost:8080/auction. Change the activator that registers the service to the following:
public class Activator implements BundleActivator {
private ServiceRegistration sr;
public void start(BundleContext context) throws Exception {
Dictionary props = new Hashtable();
props.put("osgi.remote.interfaces", "*");
props.put("osgi.remote.configuration.type", "pojo");
props.put("osgi.remote.configuration.pojo.httpservice.context",
"/auction");
sr = context.registerService(AuctionService.class.getName(),
new AuctionServiceImpl(), props);
}
public void stop(BundleContext context) throws Exception {
sr.unregister();
}
}
To double check that the service is operational on the new address, simply open http://localhost:8080/auction?wsdl and see if the WSDL appears again (just like in the previous posting).
I won't go into all the detail of writing the GWT app here. Look at the code in the SVN project for all of that.
I constructed my GWT application the usual way by creating a starting point with the projectCreator and applicationCreator scripts that come with GWT. This creates a nice Eclipse project skeleton for GWT from which I can start hacking my AJAX site in Plain Old Java :)
All you need to do in the GWT app to invoke on the Distributed OSGi service is:
All of this happens in the AuctionSite class which is the webapp's main class. There are a few more classes such as data classes and a few dialogs. Check out the project from SVN to see them all...
To prepare my webapp (.WAR file) for running with the Pax Web Extender I'm turning it into an OSGi bundle by adding the following META-INF/MANIFEST.MF file:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: AuctionSite
Bundle-Version: 1.0.0
Webapp-Context: auctionsite
The Webapp-Context is important as this tells the Pax Web Extender where to register the webapp.
I also have to add a WEB-INF/web.xml file to the .WAR as this is the signature file that the Pax-Web Extender needs in order to spot a bundle as a webapp. However, I don't really need to put anything in it. My webapp consists only of static files (no servlets etc.) as far as the webserver is concerned, so my web.xml is simply:
<web-app>
<display-name>AuctionSite</display-name>
</web-app>
GWT comes with scrips that you run to turn your Java into AJAX.
I wrote a tiny little ant script that calls the GWT script and then creates a .WAR file from my GWT project in Eclipse.
Now lets boot is all up! I'm using Equinox 3.5M5 with the Multi Bundle Distribution of CXF-DOSGi.
To install the Multi Bundle Distribution of CXF-DOSGi, download it from here. Then unzip it in your Felix/Equinox installation dir.
Take the contents of the felix.config.properties.append or equinox.config.ini.append and append it to the configuration file of your OSGi container.
This will automatically load all the DOSGi bundles when starting up the OSGi container.
You should now have the following bundles running in Equinox:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20090127-1630
1 ACTIVE org.eclipse.osgi.services_3.2.0.v20081205-1800
2 ACTIVE org.apache.geronimo.specs.geronimo-annotation_1.0_spec_1.1.1
3 ACTIVE org.apache.geronimo.specs.geronimo-activation_1.1_spec_1.0.2
4 ACTIVE org.apache.geronimo.specs.geronimo-javamail_1.4_spec_1.2.0
5 ACTIVE org.apache.geronimo.specs.geronimo-ws-metadata_2.0_spec_1.1.2
6 ACTIVE com.springsource.org.apache.commons.logging_1.1.1
7 ACTIVE com.springsource.org.jdom_1.0.0
8 ACTIVE org.springframework.bundle.spring.core_2.5.5
9 ACTIVE org.springframework.bundle.spring.beans_2.5.5
10 ACTIVE org.springframework.bundle.spring.context_2.5.5
11 ACTIVE com.springsource.org.aopalliance_1.0.0
12 ACTIVE org.springframework.bundle.spring.aop_2.5.5
13 ACTIVE org.springframework.bundle.osgi.io_1.1.2
14 ACTIVE org.springframework.bundle.osgi.core_1.1.2
15 ACTIVE org.springframework.bundle.osgi.extender_1.1.2
16 ACTIVE org.ops4j.pax.web.service_0.5.1
17 ACTIVE org.apache.servicemix.specs.locator-1.1.1
18 ACTIVE org.apache.servicemix.bundles.jaxb-impl_2.1.6.1
19 ACTIVE org.apache.servicemix.bundles.wsdl4j_1.6.1.1
20 ACTIVE org.apache.servicemix.bundles.xmlsec_1.3.0.1
21 ACTIVE org.apache.servicemix.bundles.wss4j_1.5.4.1
22 ACTIVE org.apache.servicemix.bundles.xmlschema_1.4.2.1
23 ACTIVE org.apache.servicemix.bundles.asm_2.2.3.1
24 ACTIVE org.apache.servicemix.bundles.xmlresolver_1.2.0.1
25 ACTIVE org.apache.servicemix.bundles.neethi_2.0.4.1
26 ACTIVE org.apache.servicemix.bundles.woodstox_3.2.7.1
27 ACTIVE org.apache.cxf.cxf-bundle-minimal_2.2.0.SNAPSHOT
28 ACTIVE org.apache.servicemix.specs.saaj-api-1.3_1.1.1
29 ACTIVE org.apache.servicemix.specs.stax-api-1.0_1.1.1
30 ACTIVE org.apache.servicemix.specs.jaxb-api-2.1_1.1.1
31 ACTIVE org.apache.servicemix.specs.jaxws-api-2.1_1.1.1
32 ACTIVE cxf-dosgi-ri-discovery-local_1.0.0.SNAPSHOT
33 ACTIVE cxf-dosgi-ri-dsw-cxf_1.0.0.SNAPSHOT
34 ACTIVE org.ops4j.pax.web.extender.war_0.4.0
35 ACTIVE AuctionIntf_1.0.0
36 ACTIVE AuctionImpl_1.0.0
37 ACTIVE AuctionSite_1.0.0
Open the webapp at http://localhost:8080/auctionsite/AuctionSite.html. This kicks off the AJAX app in your browser. When you hit the reload button it makes a SOAP/HTTP invocation on the server to list all the items and get their details. The SOAP messages it sends map to the AuctionService.getItemIDs() and AuctionService.getItems() APIs. (At the bottom of the screen you see the SOAP message as it comes back form the server)

Let's list a new item...

After filling in the Javascript popup, hit OK.
It now sends the following SOAP message from the browser to the server:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:listNewItem xmlns:ns1="http://auction.coderthoughts.org/">
<ns1:arg0>Joke</ns1:arg0>
<ns1:arg1>1000</ns1:arg1>
<ns1:arg2>2009-02-09T15:48:22-00:00</ns1:arg2>
</ns1:listNewItem>
</soap:Body>
</soap:Envelope>
Once the remote invocation has completed, the list of items is updated again, which is the same as hitting the reload button.

I can still access the web service from my remote OSGi client that I developed in the previous post. The same remote OSGi service can obviously be shared among many consumers. When I run the AuctionClient bundle I'm also seeing my newly listed item.
Before I can do that I need to update the remote-services.xml file in the consumer bundle with the new location of the Web Service (when using Discovery this is not needed BTW):
<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
<service-description>
<provide interface="org.coderthoughts.auction.AuctionService"/>
<property name="osgi.remote.interfaces">*</property>
<property name="osgi.remote.configuration.type">pojo</property>
<property name="osgi.remote.configuration.pojo.address">
http://localhost:9000/auction
</property>
</service-description>
</service-descriptions>
Now run the AuctionClient bundle:
Items available for auction:
1: Doll $ 7.99 Sat Dec 05 08:00:00 GMT 2009
10: Joke $ 10.00 Mon Feb 09 15:48:12 GMT 2009
2: Empty sheet of paper $ 12.00 Tue May 11 21:10:00 IST 2010
3: Bike shed $126.75 Tue Sep 15 08:12:00 IST 2009
You can get all the code in this posting under the Apache license from the google code project. It's all in SVN at http://coderthoughts.googlecode.com/svn/trunk/gwt_auctionsite and http://coderthoughts.googlecode.com/svn/trunk/osgi_auctionsite .
Since it's all Eclipse projects, the easiest way to get it by doing the SVN checkout of the projects directly in Eclipse. It will give you a workspace that looks like this:
This posting is about using that OSGi service from a non-OSGi consumer. From an AJAX-powered web application that's running in the browser!
I'm writing the webapp using the Google Web Toolkit (GWT). Both the webapp as well as my OSGi service are hosted in the same OSGi container. With AJAX you can create a rich client application running inside the browser. So no Servlet/JSP style server-side execution. The webapp runs on the client machine. GWT makes creating the AJAX app easy: you write them in plain old Java. No need to sidestep into Javascript as GWT turns the Java into a Javascript AJAX app and all (well, almost) of the browser specific madness is taken care of by GWT too.
As with any website, the end-users users simply open it in their browser. No client install, no browser plugins. Any modern browser supports this stuff natively. Remote communication, such as obtaining a list of available items, listing a new item, placing a bid, is done via SOAP/HTTP calls directly on my OSGi AuctionService (the one from the previous posting) which has been remoted using the Apache CXF-based Distributed OSGi Reference Implementation.
To do all this I'm adding a component called Pax Web Extender to my OSGi container, on top of the Distributed OSGi bundles. Pax Web Extender turns the OSGi container into a web container which means that I can deploy a .WAR file into it. It internally leverages the OSGi HTTP Service. (Spring DM Server can do this too BTW).
My OSGi container is configured like this:

Besides the CXF Distributed OSGi and Pax-Web-Extender Bundles I have my AuctionService and AuctionInterface bundles deployed (see previous posting for the details), plus the .WAR file that holds my AJAX webapp.
The reason I can invoke my OSGi Service is because it was made available remotely over a standards-based mechanism. Distributed OSGi itself doesn't prescribe how you do your remoting, it only says that you can use standards-based wire protocols and bindings if you wish and that this can make OSGi Services available to non-OSGi consumers.
The CXF implementation of Distributed OSGi turns an OSGi Service into a Web Service that is accessible via SOAP/HTTP. GWT can already natively make remote HTTP invocations. I didn't actually even care looking for a SOAP library for GWT. SOAP is just XML and GWT has some pretty good XML parsing functionality.
The last thing that I need to worry about (besides security, but that's a separate topic) is the browser's single-origin policy. But hey: I've deployed my webapp in the same runtime as my OSGi Service so as long as I make them available over the same port there's no problem! I achieved this by sharing the same OSGi HTTP Service by both the Distributed OSGi runtime and the Pax Web Extender. Thanks to the OSGi Services architecture!
So I'm taking the AuctionService of the previous posting, but first of all I want to expose it on a slightly simpler URL. The default URL of http://localhost:9000/org/coderthoughts/auction/AuctionService is just a bit too long, let's use /auction as the context instead. I also want to make it use the OSGi HTTP Service (which CXF doesn't do by default). I can do both in one shot by setting the osgi.remote.configuration.pojo.httpservice.context service property to the value /auction. The HTTP Service that comes with CXF runs by default on port 8080 (you can change this by setting the org.osgi.service.http.port system property) so my Web Service now runs on http://localhost:8080/auction. Change the activator that registers the service to the following:
public class Activator implements BundleActivator {
private ServiceRegistration sr;
public void start(BundleContext context) throws Exception {
Dictionary props = new Hashtable();
props.put("osgi.remote.interfaces", "*");
props.put("osgi.remote.configuration.type", "pojo");
props.put("osgi.remote.configuration.pojo.httpservice.context",
"/auction");
sr = context.registerService(AuctionService.class.getName(),
new AuctionServiceImpl(), props);
}
public void stop(BundleContext context) throws Exception {
sr.unregister();
}
}
To double check that the service is operational on the new address, simply open http://localhost:8080/auction?wsdl and see if the WSDL appears again (just like in the previous posting).
I won't go into all the detail of writing the GWT app here. Look at the code in the SVN project for all of that.
I constructed my GWT application the usual way by creating a starting point with the projectCreator and applicationCreator scripts that come with GWT. This creates a nice Eclipse project skeleton for GWT from which I can start hacking my AJAX site in Plain Old Java :)
All you need to do in the GWT app to invoke on the Distributed OSGi service is:
- figure out where it's running, since the Web Service is running on the same host and port as where the AJAX app is served from on the /auction context, I can construct the Web Service URL as follows:
webServiceURL = "http://" + Window.Location.getHost() + "/auction/"; - create a SOAP message, just a bit of XML really.
- send it via a HTTP POST request to the WebService using a com.google.gwt.http.client.RequestBuilder that comes with GWT.
- register a callback object to process the SOAP (XML) response.
All of this happens in the AuctionSite class which is the webapp's main class. There are a few more classes such as data classes and a few dialogs. Check out the project from SVN to see them all...
To prepare my webapp (.WAR file) for running with the Pax Web Extender I'm turning it into an OSGi bundle by adding the following META-INF/MANIFEST.MF file:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: AuctionSite
Bundle-Version: 1.0.0
Webapp-Context: auctionsite
The Webapp-Context is important as this tells the Pax Web Extender where to register the webapp.
I also have to add a WEB-INF/web.xml file to the .WAR as this is the signature file that the Pax-Web Extender needs in order to spot a bundle as a webapp. However, I don't really need to put anything in it. My webapp consists only of static files (no servlets etc.) as far as the webserver is concerned, so my web.xml is simply:
<web-app>
<display-name>AuctionSite</display-name>
</web-app>
GWT comes with scrips that you run to turn your Java into AJAX.
I wrote a tiny little ant script that calls the GWT script and then creates a .WAR file from my GWT project in Eclipse.
Now lets boot is all up! I'm using Equinox 3.5M5 with the Multi Bundle Distribution of CXF-DOSGi.
To install the Multi Bundle Distribution of CXF-DOSGi, download it from here. Then unzip it in your Felix/Equinox installation dir.
Take the contents of the felix.config.properties.append or equinox.config.ini.append and append it to the configuration file of your OSGi container.
This will automatically load all the DOSGi bundles when starting up the OSGi container.
- Start Equinox with the DOSGi Multi Bundle configuration to make it load all the DOSGi bundles at startup.
- Then install and start the PAX Web Extender from here and your AuctionIntf and AuctionImpl bundles.
- Finally install and start the AuctionSite.war file, just like any other bundle in OSGi.
You should now have the following bundles running in Equinox:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20090127-1630
1 ACTIVE org.eclipse.osgi.services_3.2.0.v20081205-1800
2 ACTIVE org.apache.geronimo.specs.geronimo-annotation_1.0_spec_1.1.1
3 ACTIVE org.apache.geronimo.specs.geronimo-activation_1.1_spec_1.0.2
4 ACTIVE org.apache.geronimo.specs.geronimo-javamail_1.4_spec_1.2.0
5 ACTIVE org.apache.geronimo.specs.geronimo-ws-metadata_2.0_spec_1.1.2
6 ACTIVE com.springsource.org.apache.commons.logging_1.1.1
7 ACTIVE com.springsource.org.jdom_1.0.0
8 ACTIVE org.springframework.bundle.spring.core_2.5.5
9 ACTIVE org.springframework.bundle.spring.beans_2.5.5
10 ACTIVE org.springframework.bundle.spring.context_2.5.5
11 ACTIVE com.springsource.org.aopalliance_1.0.0
12 ACTIVE org.springframework.bundle.spring.aop_2.5.5
13 ACTIVE org.springframework.bundle.osgi.io_1.1.2
14 ACTIVE org.springframework.bundle.osgi.core_1.1.2
15 ACTIVE org.springframework.bundle.osgi.extender_1.1.2
16 ACTIVE org.ops4j.pax.web.service_0.5.1
17 ACTIVE org.apache.servicemix.specs.locator-1.1.1
18 ACTIVE org.apache.servicemix.bundles.jaxb-impl_2.1.6.1
19 ACTIVE org.apache.servicemix.bundles.wsdl4j_1.6.1.1
20 ACTIVE org.apache.servicemix.bundles.xmlsec_1.3.0.1
21 ACTIVE org.apache.servicemix.bundles.wss4j_1.5.4.1
22 ACTIVE org.apache.servicemix.bundles.xmlschema_1.4.2.1
23 ACTIVE org.apache.servicemix.bundles.asm_2.2.3.1
24 ACTIVE org.apache.servicemix.bundles.xmlresolver_1.2.0.1
25 ACTIVE org.apache.servicemix.bundles.neethi_2.0.4.1
26 ACTIVE org.apache.servicemix.bundles.woodstox_3.2.7.1
27 ACTIVE org.apache.cxf.cxf-bundle-minimal_2.2.0.SNAPSHOT
28 ACTIVE org.apache.servicemix.specs.saaj-api-1.3_1.1.1
29 ACTIVE org.apache.servicemix.specs.stax-api-1.0_1.1.1
30 ACTIVE org.apache.servicemix.specs.jaxb-api-2.1_1.1.1
31 ACTIVE org.apache.servicemix.specs.jaxws-api-2.1_1.1.1
32 ACTIVE cxf-dosgi-ri-discovery-local_1.0.0.SNAPSHOT
33 ACTIVE cxf-dosgi-ri-dsw-cxf_1.0.0.SNAPSHOT
34 ACTIVE org.ops4j.pax.web.extender.war_0.4.0
35 ACTIVE AuctionIntf_1.0.0
36 ACTIVE AuctionImpl_1.0.0
37 ACTIVE AuctionSite_1.0.0
Open the webapp at http://localhost:8080/auctionsite/AuctionSite.html. This kicks off the AJAX app in your browser. When you hit the reload button it makes a SOAP/HTTP invocation on the server to list all the items and get their details. The SOAP messages it sends map to the AuctionService.getItemIDs() and AuctionService.getItems() APIs. (At the bottom of the screen you see the SOAP message as it comes back form the server)

Let's list a new item...

After filling in the Javascript popup, hit OK.
It now sends the following SOAP message from the browser to the server:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:listNewItem xmlns:ns1="http://auction.coderthoughts.org/">
<ns1:arg0>Joke</ns1:arg0>
<ns1:arg1>1000</ns1:arg1>
<ns1:arg2>2009-02-09T15:48:22-00:00</ns1:arg2>
</ns1:listNewItem>
</soap:Body>
</soap:Envelope>
Once the remote invocation has completed, the list of items is updated again, which is the same as hitting the reload button.

I can still access the web service from my remote OSGi client that I developed in the previous post. The same remote OSGi service can obviously be shared among many consumers. When I run the AuctionClient bundle I'm also seeing my newly listed item.
Before I can do that I need to update the remote-services.xml file in the consumer bundle with the new location of the Web Service (when using Discovery this is not needed BTW):
<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
<service-description>
<provide interface="org.coderthoughts.auction.AuctionService"/>
<property name="osgi.remote.interfaces">*</property>
<property name="osgi.remote.configuration.type">pojo</property>
<property name="osgi.remote.configuration.pojo.address">
http://localhost:9000/auction
</property>
</service-description>
</service-descriptions>
Now run the AuctionClient bundle:
Items available for auction:
1: Doll $ 7.99 Sat Dec 05 08:00:00 GMT 2009
10: Joke $ 10.00 Mon Feb 09 15:48:12 GMT 2009
2: Empty sheet of paper $ 12.00 Tue May 11 21:10:00 IST 2010
3: Bike shed $126.75 Tue Sep 15 08:12:00 IST 2009
You can get all the code in this posting under the Apache license from the google code project. It's all in SVN at http://coderthoughts.googlecode.com/svn/trunk/gwt_auctionsite and http://coderthoughts.googlecode.com/svn/trunk/osgi_auctionsite .
Since it's all Eclipse projects, the easiest way to get it by doing the SVN checkout of the projects directly in Eclipse. It will give you a workspace that looks like this:
Tuesday, February 3, 2009
Distributed OSGi – A Simple Example
One of the exciting things to come out in 2009 is the new version of the OSGi Specification. It's called 4.2 but should really have been called 5.0 since there's a lot of new stuff in it. Distributed OSGi for example. (You can find a preview of the Distributed OSGi specification in this doc: http://www.osgi.org/download/osgi-4.2-early-draft2.pdf look for RFC 119 from page 196).
Distributed OSGi enables the distribution of OSGi Services across VMs and provides a standardized way of doing this. It doesn't specify what protocol or binding should be used on the wire for the inter-VM communication, that's up to the implementation. What it does specify is which standard properties you set on your OSGi Service to declare that it should be remoted.

The Service Implementation side
So here it is in its simplest form. Take an OSGi Auction Service that implements the following Java Interface:
public interface AuctionService {
int listNewItem(String description, int startPriceInCents, Date expiryDate);
void bid(int itemID, String user, int priceInCents)
Collection<Integer> getItemIDs(String query);
Collection<AuctionItem> getItems(int ... id);
}
With this you can list a new item, bid on an item, search for items and get item details given the item's IDs.
I've got a noddy little implementation of this service here: AuctionServiceImpl.java.
Note that I designed the interface to be suitable for distribution with the technology that I'll be using. This means that I don't rely on pass-by-reference for my method arguments and return types. In most cases distribution technologies will use pass-by-value so I made my design compatible with that.
I have put this interface in a separate bundle called AuctionIntf so that it can be used by both the service implementor and the consumer.
Now I want make this service available to my remote OSGi service consumers. The only thing I have to do for this is set a property on the OSGi service when I register it in the Activator with the local OSGi Service Registry: osgi.remote.interfaces=*. This means that I declare all the interfaces passed to bundleContext.registerService() are suitable for remoting. In my case I'm only passing one interface. (You could list individual interfaces instead of passing '*' if you only want to expose a subset).
public class Activator implements BundleActivator {
private ServiceRegistration sr;
public void start(BundleContext context) throws Exception {
Dictionary props = new Hashtable();
props.put("osgi.remote.interfaces", "*");
sr = context.registerService(AuctionService.class.getName(),
new AuctionServiceImpl(), props);
}
public void stop(BundleContext context) throws Exception {
sr.unregister();
}
}
I'm putting the service implementation and the Activator in a bundle called AuctionImpl which uses the AuctionService interface from the AuctionIntf bundle.
Any my Distributed Service is done!
Well... as long as I've got an implementation of Distributed OSGi running as well.
Lets do an experiment with the server side running on Equinox and the client side running on Felix. For Equinox you need version 3.5 built in December 2008 or later. For Felix you need version 1.4.1 or newer.
I'm using the Distributed OSGi DSW Reference Implementation which is based on Apache CXF and have the single-bundle version of that installed.
It's currently not yet released, but you can get a snapshot version via Maven from here (the bundle name is cxf-dosgi-ri-singlebundle-distribution).
Install this, plus its dependencies in Equinox and you'll get the following bundles:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20081201-1815
1 ACTIVE org.eclipse.osgi.services_3.2.0.v20081205-1800
2 ACTIVE javax.servlet_2.5.0.v200806031605
3 ACTIVE cxf-dosgi-ri-singlebundle-distribution
4 ACTIVE AuctionIntf_1.0.0
5 ACTIVE AuctionImpl_1.0.0
The distributed OSGi bundle depends on a few API's from the OSGi compendium spec, which are found in the org.eclipse.osgi.services bundle, which in turn depends on the javax.servlet bundle.
Hey, my service is now remoted using Web Services and available via SOAP over HTTP! CXF even automatically generates a WSDL: http://localhost:9000/org/coderthoughts/auction/AuctionService?wsdl should look like this:

This in itself is very useful. I can use this WSDL to invoke my OSGi service using any technology that can make Web Services invocations. So I could write a C++ or even a Visual Basic client for it! (In the next posting I'll use it from a remote AJAX Web client: calling a remote OSGi service straight from a browser!)
There is another way of finding out whether your service has been made available remotely, which works independently of the middleware used. Look in the OSGi Service Registry for services implementing the org.osgi.service.discovery.ServicePublication interface:
osgi> services (objectClass=*Publication)
{org.osgi.service.discovery.ServicePublication}={
osgi.remote.endpoint.location=http://localhost:9000/org/coderthoughts/auction/AuctionService,
service.properties={...},
service.interface=[org.coderthoughts.auction.AuctionService], service.id=34}
Registered by bundle: cxf-dosgi-ri-singlebundle-distribution [3]
When a Distributed OSGi implementation is remotely exposing a service, it will in turn register a service implementing the ServicePublication interface to advertise the remote service to any available Discovery mechanisms.
The Consumer side
My consumer code looks like a very ordinary OSGi Service Consumer: a little bit messy :) In real life I'd rather use something like the OSGi Blueprint (aka Spring-DM), iPOJO or Guice-OSGi, but in this posting I'd like to keep things a little focused so I'll go with writing plain OSGi service consumer code using a ServiceTracker.
public class Activator implements BundleActivator {
private ServiceTracker st;
public void start(final BundleContext bc) throws Exception {
st = new ServiceTracker(bc, AuctionService.class.getName(), null) {
@Override
public Object addingService(ServiceReference reference) {
Object svc = bc.getService(reference);
if (svc instanceof AuctionService) {
printServiceInfo((AuctionService) svc);
}
return super.addingService(reference);
}
};
st.open();
}
protected void printServiceInfo(AuctionService auctionService) {
System.out.println("Items available for auction:");
Collection<Integer> ids = auctionService.getItemIDs(null);
int[] idArray = toIntArray(ids);
for (AuctionItem item : auctionService.getItems(idArray)) {
System.out.printf("%3d: %25s $%,6.2f %tc\n",
item.getID(),
item.getDescription(),
(item.getPriceInCents() / 100.0),
item.getExpires());
}
}
private int[] toIntArray(Collection<Integer> ids) {
// details omitted
}
public void stop(BundleContext bc) throws Exception {
st.close();
}
}
As soon as the ServiceTracker gets a callback that the AuctionService is there, it prints out some details about the items available for auction.
Euh yeah, but where are the distribution bits in the consumer? Correct – there aren't any! A remote OSGi service is looked up exactly the same way as a local OSGi service. The simple fact that the client is expressing an interest in the service is enough for Distributed OSGi to go out and check for the existence of the service as a remote service. Behind the scenes it asynchronously checks any registered OSGi Remote Service Discovery services.
In this posting I'm not using a Discovery Service yet. I'm using a alternate, more static way, of specifying where my remote service is. Via a remote-services.xml file. This file sits by default in the OSGI-INF/remote-service directory of a bundle:
<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
<service-description>
<provide interface="org.coderthoughts.auction.AuctionService"/>
<property name="osgi.remote.interfaces">*</property>
<property name="osgi.remote.configuration.type">pojo</property>
<property name="osgi.remote.configuration.pojo.address">
http://localhost:9000/org/coderthoughts/auction/AuctionService
</property>
</service-description>
</service-descriptions>
The format of this file is specified by Distributed OSGi. osgi.remote.interfaces is the same standard property that I set on the service. The osgi.remote.configuration.pojo.address is a CXF-specific one that simply denotes where my remote service is running.
So let's run the consumer in Felix.
-> ps
START LEVEL 1
ID State Level Name
[ 0] [Active ] [ 0] System Bundle (1.4.1)
[ 1] [Active ] [ 1] Apache Felix Shell Service (1.0.2)
[ 2] [Active ] [ 1] Apache Felix Shell TUI (1.0.2)
[ 3] [Active ] [ 1] Apache Felix Bundle Repository (1.2.1)
[ 4] [Active ] [ 1] OSGi R4 Compendium Bundle (4.1.0)
[ 5] [Active ] [ 1] Distributed OSGi Distribution Software Single-Bundle Distribution
[ 6] [Active ] [ 1] AuctionIntf (1.0.0)
[ 7] [Active ] [ 1] AuctionClient (1.0.0)
Besides the default Felix system, shell and bundle repository bundles, I've also installed the OSGi Compendium bundle which contains some OSGi standard interfaces that we need.
After the client bundle has started it will receive a callback that the (remote) AuctionService it wants to use is available and it will print out some information about the available items:
Items available for auction:
1: Doll $ 7.99 Sat Dec 05 08:00:00 GMT 2009
2: Empty sheet of paper $ 12.00 Tue May 11 21:10:00 IST 2010
3: Bike shed $126.75 Tue Sep 15 08:12:00 IST 2009
You can also see the remote service represented in the local service registry the same way a local service is. It is registered on demand by the DSW bundle:
-> services 5
...
objectClass = org.coderthoughts.auction.AuctionService
osgi.remote = true
osgi.remote.configuration.type = pojo
osgi.remote.configuration.pojo.address = http://localhost:9000/org/coderthoughts/auction/AuctionService
osgi.remote.interfaces = *
service.id = 30
There's our remote service! Just like an ordinary OSGi service. An extra property is set on client side proxies: osgi.remote. This can be used to find out whether a service that you are dealing with is remote or not. It can also be used to change the default lookup behaviour. By default remote services are always included in the service lookups, but this default can be tweaked by registering a FindHook/EventHook, which is a new feature of the Service Registry specified in RFC 126.
You can find the full implementation of the AuctionIntf, AuctionImpl and AuctionClient OSGi bundles as Eclipse projects in SVN: http://coderthoughts.googlecode.com/svn/trunk/osgi_auctionsite
Next posting: an AJAX client UI written using the Google Web Toolkit (GWT).
Links
OSGi Specs: http://www.osgi.org/Specifications
Disributed OSGi Reference Implementation based on Apache CXF: http://cwiki.apache.org/confluence/display/CXF/Distributed+OSGi
Apache CXF Home page: http://cxf.apache.org
Distributed OSGi enables the distribution of OSGi Services across VMs and provides a standardized way of doing this. It doesn't specify what protocol or binding should be used on the wire for the inter-VM communication, that's up to the implementation. What it does specify is which standard properties you set on your OSGi Service to declare that it should be remoted.

The Service Implementation side
So here it is in its simplest form. Take an OSGi Auction Service that implements the following Java Interface:
public interface AuctionService {
int listNewItem(String description, int startPriceInCents, Date expiryDate);
void bid(int itemID, String user, int priceInCents)
Collection<Integer> getItemIDs(String query);
Collection<AuctionItem> getItems(int ... id);
}
With this you can list a new item, bid on an item, search for items and get item details given the item's IDs.
I've got a noddy little implementation of this service here: AuctionServiceImpl.java.
Note that I designed the interface to be suitable for distribution with the technology that I'll be using. This means that I don't rely on pass-by-reference for my method arguments and return types. In most cases distribution technologies will use pass-by-value so I made my design compatible with that.
I have put this interface in a separate bundle called AuctionIntf so that it can be used by both the service implementor and the consumer.
Now I want make this service available to my remote OSGi service consumers. The only thing I have to do for this is set a property on the OSGi service when I register it in the Activator with the local OSGi Service Registry: osgi.remote.interfaces=*. This means that I declare all the interfaces passed to bundleContext.registerService() are suitable for remoting. In my case I'm only passing one interface. (You could list individual interfaces instead of passing '*' if you only want to expose a subset).
public class Activator implements BundleActivator {
private ServiceRegistration sr;
public void start(BundleContext context) throws Exception {
Dictionary props = new Hashtable();
props.put("osgi.remote.interfaces", "*");
sr = context.registerService(AuctionService.class.getName(),
new AuctionServiceImpl(), props);
}
public void stop(BundleContext context) throws Exception {
sr.unregister();
}
}
I'm putting the service implementation and the Activator in a bundle called AuctionImpl which uses the AuctionService interface from the AuctionIntf bundle.
Any my Distributed Service is done!
Well... as long as I've got an implementation of Distributed OSGi running as well.
Lets do an experiment with the server side running on Equinox and the client side running on Felix. For Equinox you need version 3.5 built in December 2008 or later. For Felix you need version 1.4.1 or newer.
I'm using the Distributed OSGi DSW Reference Implementation which is based on Apache CXF and have the single-bundle version of that installed.
It's currently not yet released, but you can get a snapshot version via Maven from here (the bundle name is cxf-dosgi-ri-singlebundle-distribution).
Install this, plus its dependencies in Equinox and you'll get the following bundles:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20081201-1815
1 ACTIVE org.eclipse.osgi.services_3.2.0.v20081205-1800
2 ACTIVE javax.servlet_2.5.0.v200806031605
3 ACTIVE cxf-dosgi-ri-singlebundle-distribution
4 ACTIVE AuctionIntf_1.0.0
5 ACTIVE AuctionImpl_1.0.0
The distributed OSGi bundle depends on a few API's from the OSGi compendium spec, which are found in the org.eclipse.osgi.services bundle, which in turn depends on the javax.servlet bundle.
Hey, my service is now remoted using Web Services and available via SOAP over HTTP! CXF even automatically generates a WSDL: http://localhost:9000/org/coderthoughts/auction/AuctionService?wsdl should look like this:

This in itself is very useful. I can use this WSDL to invoke my OSGi service using any technology that can make Web Services invocations. So I could write a C++ or even a Visual Basic client for it! (In the next posting I'll use it from a remote AJAX Web client: calling a remote OSGi service straight from a browser!)
There is another way of finding out whether your service has been made available remotely, which works independently of the middleware used. Look in the OSGi Service Registry for services implementing the org.osgi.service.discovery.ServicePublication interface:
osgi> services (objectClass=*Publication)
{org.osgi.service.discovery.ServicePublication}={
osgi.remote.endpoint.location=http://localhost:9000/org/coderthoughts/auction/AuctionService,
service.properties={...},
service.interface=[org.coderthoughts.auction.AuctionService], service.id=34}
Registered by bundle: cxf-dosgi-ri-singlebundle-distribution [3]
When a Distributed OSGi implementation is remotely exposing a service, it will in turn register a service implementing the ServicePublication interface to advertise the remote service to any available Discovery mechanisms.
The Consumer side
My consumer code looks like a very ordinary OSGi Service Consumer: a little bit messy :) In real life I'd rather use something like the OSGi Blueprint (aka Spring-DM), iPOJO or Guice-OSGi, but in this posting I'd like to keep things a little focused so I'll go with writing plain OSGi service consumer code using a ServiceTracker.
public class Activator implements BundleActivator {
private ServiceTracker st;
public void start(final BundleContext bc) throws Exception {
st = new ServiceTracker(bc, AuctionService.class.getName(), null) {
@Override
public Object addingService(ServiceReference reference) {
Object svc = bc.getService(reference);
if (svc instanceof AuctionService) {
printServiceInfo((AuctionService) svc);
}
return super.addingService(reference);
}
};
st.open();
}
protected void printServiceInfo(AuctionService auctionService) {
System.out.println("Items available for auction:");
Collection<Integer> ids = auctionService.getItemIDs(null);
int[] idArray = toIntArray(ids);
for (AuctionItem item : auctionService.getItems(idArray)) {
System.out.printf("%3d: %25s $%,6.2f %tc\n",
item.getID(),
item.getDescription(),
(item.getPriceInCents() / 100.0),
item.getExpires());
}
}
private int[] toIntArray(Collection<Integer> ids) {
// details omitted
}
public void stop(BundleContext bc) throws Exception {
st.close();
}
}
As soon as the ServiceTracker gets a callback that the AuctionService is there, it prints out some details about the items available for auction.
Euh yeah, but where are the distribution bits in the consumer? Correct – there aren't any! A remote OSGi service is looked up exactly the same way as a local OSGi service. The simple fact that the client is expressing an interest in the service is enough for Distributed OSGi to go out and check for the existence of the service as a remote service. Behind the scenes it asynchronously checks any registered OSGi Remote Service Discovery services.
In this posting I'm not using a Discovery Service yet. I'm using a alternate, more static way, of specifying where my remote service is. Via a remote-services.xml file. This file sits by default in the OSGI-INF/remote-service directory of a bundle:
<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
<service-description>
<provide interface="org.coderthoughts.auction.AuctionService"/>
<property name="osgi.remote.interfaces">*</property>
<property name="osgi.remote.configuration.type">pojo</property>
<property name="osgi.remote.configuration.pojo.address">
http://localhost:9000/org/coderthoughts/auction/AuctionService
</property>
</service-description>
</service-descriptions>
The format of this file is specified by Distributed OSGi. osgi.remote.interfaces is the same standard property that I set on the service. The osgi.remote.configuration.pojo.address is a CXF-specific one that simply denotes where my remote service is running.
So let's run the consumer in Felix.
-> ps
START LEVEL 1
ID State Level Name
[ 0] [Active ] [ 0] System Bundle (1.4.1)
[ 1] [Active ] [ 1] Apache Felix Shell Service (1.0.2)
[ 2] [Active ] [ 1] Apache Felix Shell TUI (1.0.2)
[ 3] [Active ] [ 1] Apache Felix Bundle Repository (1.2.1)
[ 4] [Active ] [ 1] OSGi R4 Compendium Bundle (4.1.0)
[ 5] [Active ] [ 1] Distributed OSGi Distribution Software Single-Bundle Distribution
[ 6] [Active ] [ 1] AuctionIntf (1.0.0)
[ 7] [Active ] [ 1] AuctionClient (1.0.0)
Besides the default Felix system, shell and bundle repository bundles, I've also installed the OSGi Compendium bundle which contains some OSGi standard interfaces that we need.
After the client bundle has started it will receive a callback that the (remote) AuctionService it wants to use is available and it will print out some information about the available items:
Items available for auction:
1: Doll $ 7.99 Sat Dec 05 08:00:00 GMT 2009
2: Empty sheet of paper $ 12.00 Tue May 11 21:10:00 IST 2010
3: Bike shed $126.75 Tue Sep 15 08:12:00 IST 2009
You can also see the remote service represented in the local service registry the same way a local service is. It is registered on demand by the DSW bundle:
-> services 5
...
objectClass = org.coderthoughts.auction.AuctionService
osgi.remote = true
osgi.remote.configuration.type = pojo
osgi.remote.configuration.pojo.address = http://localhost:9000/org/coderthoughts/auction/AuctionService
osgi.remote.interfaces = *
service.id = 30
There's our remote service! Just like an ordinary OSGi service. An extra property is set on client side proxies: osgi.remote. This can be used to find out whether a service that you are dealing with is remote or not. It can also be used to change the default lookup behaviour. By default remote services are always included in the service lookups, but this default can be tweaked by registering a FindHook/EventHook, which is a new feature of the Service Registry specified in RFC 126.
You can find the full implementation of the AuctionIntf, AuctionImpl and AuctionClient OSGi bundles as Eclipse projects in SVN: http://coderthoughts.googlecode.com/svn/trunk/osgi_auctionsite
Next posting: an AJAX client UI written using the Google Web Toolkit (GWT).
Links
OSGi Specs: http://www.osgi.org/Specifications
Disributed OSGi Reference Implementation based on Apache CXF: http://cwiki.apache.org/confluence/display/CXF/Distributed+OSGi
Apache CXF Home page: http://cxf.apache.org
Wednesday, November 26, 2008
A Web Site Concentrator to ease AJAX development
Every now and then I do a little AJAX development and there is one thing that I always find frustrating during the development of AJAX apps: The browser's single-origin policy.
Now I agree that for non-development cases this policy is absolutely justified, but during development it's a big PITA.
Let's say you are developing an AJAX app that calls into a back-end app over XML and you want to debug both. Like in my case I have a little GWT app that invokes on a Distributed OSGi Service running on the back end in CXF over port 9000. Ultimately you'd deploy it all over a single server, so there wouldn't really be a problem in production, but during development my GWT app is running on http://localhost:8888/org.coderthoughts.dinner.DinnerClient while my CXF back end runs on http://localhost:9000/org/apache/cxf/dosgi/samples/springdm/DinnerService
If I try to invoke my back-end app in this setup my AJAX app complains:

Since your front-end and back-end are probably written in different languages chances are that they have different development and debugging environments, which makes adhering to the single-origin hard to do. Besides, you don't want to go through the hassle of rebuilding your .WAR files (or whatever format you might use) for every single change. I know MSIE has some options to alleviate this, but they don't always work. Also using JSON as a data format gives you some options to bypass the problem, but that only works if your data format is JSON. In my case it's XML.
Enter ProxyServlet. There's a few of these around, but they're generally a bit raw. I particularly liked the one from Frank Spieleck because it has no dependencies, so is simple to use.
Typically these ProxyServlets forward requests from one context to another location, so to build the multi-site concentrator that you need to make the browser think both of them come from the same source you need at least two of them. In my case I need the following proxy settings:
To ease this task I wrote a little commandline wrapper around Frank's ProxyServlet that simply generates a .WAR file with the right name to set the root context, the correct bits in the web.xml etc... So I generate 2 .WAR files:
java -jar genwebproxy.jar \
org.coderthoughts.dinner.DinnerClient \
http://localhost:8888/org.coderthoughts.dinner.DinnerClient
Created: org.coderthoughts.dinner.DinnerClient.war
java -jar genwebproxy.jar org http://localhost:9000/org
Created: org.war
and simply deploy them into Tomcat by copying them into the webapps directory. These are standard .WAR files so you can deploy them into any Webapp container. I've also put the PAX-WEB headers in, in case you want to deploy them into that.
Et voilà . It works!

Note that I access my AJAX app using the Tomcat port of 8080 instead of the GWT debug port of 8888. I did have to change the port number at with my webapp makes an invocation from 9000 to 8080 as well, but that's easy.
With Frank's permission I put the ProxyServlet plus my wrapping code for the genwebproxy.jar file in SVN here: http://coderthoughts.googlecode.com/svn/trunk/GenWebProxy
You can download the binary from here, the command line is:
java -jar genwebproxy.jar [context_root] [real_location]
Now I agree that for non-development cases this policy is absolutely justified, but during development it's a big PITA.
Let's say you are developing an AJAX app that calls into a back-end app over XML and you want to debug both. Like in my case I have a little GWT app that invokes on a Distributed OSGi Service running on the back end in CXF over port 9000. Ultimately you'd deploy it all over a single server, so there wouldn't really be a problem in production, but during development my GWT app is running on http://localhost:8888/org.coderthoughts.dinner.DinnerClient while my CXF back end runs on http://localhost:9000/org/apache/cxf/dosgi/samples/springdm/DinnerService
If I try to invoke my back-end app in this setup my AJAX app complains:
Since your front-end and back-end are probably written in different languages chances are that they have different development and debugging environments, which makes adhering to the single-origin hard to do. Besides, you don't want to go through the hassle of rebuilding your .WAR files (or whatever format you might use) for every single change. I know MSIE has some options to alleviate this, but they don't always work. Also using JSON as a data format gives you some options to bypass the problem, but that only works if your data format is JSON. In my case it's XML.
Enter ProxyServlet. There's a few of these around, but they're generally a bit raw. I particularly liked the one from Frank Spieleck because it has no dependencies, so is simple to use.
Typically these ProxyServlets forward requests from one context to another location, so to build the multi-site concentrator that you need to make the browser think both of them come from the same source you need at least two of them. In my case I need the following proxy settings:
- org.coderthoughts.dinner.DinnerClient => http://localhost:8888/org.coderthoughts.dinner.DinnerClient
- org => http://localhost:9000/org
To ease this task I wrote a little commandline wrapper around Frank's ProxyServlet that simply generates a .WAR file with the right name to set the root context, the correct bits in the web.xml etc... So I generate 2 .WAR files:
java -jar genwebproxy.jar \
org.coderthoughts.dinner.DinnerClient \
http://localhost:8888/org.coderthoughts.dinner.DinnerClient
Created: org.coderthoughts.dinner.DinnerClient.war
java -jar genwebproxy.jar org http://localhost:9000/org
Created: org.war
and simply deploy them into Tomcat by copying them into the webapps directory. These are standard .WAR files so you can deploy them into any Webapp container. I've also put the PAX-WEB headers in, in case you want to deploy them into that.
Et voilà . It works!
Note that I access my AJAX app using the Tomcat port of 8080 instead of the GWT debug port of 8888. I did have to change the port number at with my webapp makes an invocation from 9000 to 8080 as well, but that's easy.
With Frank's permission I put the ProxyServlet plus my wrapping code for the genwebproxy.jar file in SVN here: http://coderthoughts.googlecode.com/svn/trunk/GenWebProxy
You can download the binary from here, the command line is:
java -jar genwebproxy.jar [context_root] [real_location]
Monday, April 28, 2008
An OSGi Bundle dependency visualizer in GMF
When working with larger OSGi-base systems you sometimes wonder: why are all these bundles there? What other bundles does my bundle depend on at runtime? Is there any duplication going on?
For a project that I was working on I started manually creating Bundle Dependency diagrams. This got me thinking: it should be really easy to create a tool that does this for me using EMF (Eclipse Modeling Framework) and GMF (the Graphical Modeling Framework from Eclipse).
As always in Model Driven Development, you start with a model. In my case a model of how OSGi Bundles relate to each other.
Having the model, you just fill it with data, then use some GMF goodness to display is graphically.
Sounds easy? It was easy! With well under 300 lines of manually written code (and a whole bunch of EMF/GMF generated stuff) the end result looks like this:

In this picture I ran the visualizer in the ServiceMix 4 Kernel to see what was in it.
Main Components
There are two components in this application:
The model
1. Start with a simple model of a Framework (representing the OSGi Container) which contains bundles. Each bundle in turn could be importing stuff from other bundles:

Here are the model details:

After generating the genmodel file from my model file (I only modified the base package in the genmodel package properties) I generated the model code so I could start coding with it. (See here for an earlier post that outlines how to generate code from an EMF model).
The Introspector Bundle
To create a model instance with the bundle dependency data, I've written an self-contained OSGi bundle that I can drop on any OSGi runtime (well, at this point I only tried Equinox and Felix). When the bundle is started it walks all the active bundles in the container and figures out what other bundles each bundle depends on by using the bundle's classloader to resolve imported classes. (Since Package Imports are resolved dynamically this can only be done at runtime in an active OSGi container). The collected info is stored in an instance of my model. I stayed away from using any implementation-specific admin API's, instead I'm just using the bundle's classloader to resolve the packages listed in the Import-Package header to and figure out what bundle the OSGi runtime has linked them to.
Additionally, Require-Bundle dependencies are stored in the model too.
Finally, after all the bundles have been processed, I use the built-in EMF XMI serialization to save model instance to a file (currently always called save.bundles in your temp directory).
That's the hard bit done. You can see the code here in the BundleIntrospector and BundleIntrospectorTools classes which are invoked from my simple Activator.
The Visualizer
Believe it or not, the easy bit is in creating the graphical visualizer. GMF does all the hard work for me. I'm by no means a GMF connaisseur, so I used the GMF Cheat Sheet that comes with GMF in Eclipse. I ran all the wizards from the Cheat Sheet, and used all the defaults to create the .gmfgraph, .gmftool, .gmfmap and .gmfgen files. For some reason, there was one setting that I had to manually change: the Label Mapping, but the cheat sheet told me what to do.
Finally I hit 'generate diagram code' on the .gmfgen file and I'm done.
My Eclipse Workspace looks like this.

Running it
Running the introspector with Equinox
This is very easy from within Eclipse. To try this out, create a new OSGi Framework launch configuration with the introspector bundle and, to give it something to look at, I also include the org.mortbay.jetty bundle and it's dependencies:

Make sure that the introspector bundle is not automatically started. When I launch Equinox I have the following bundles loaded:
When I start the introspector bundle it starts analyzing the other bundles:
Running the Visualizer
Now that I have a data file, I can run the visualizer. Just right-click on one of your projects in Eclipse and select Run As Eclipse Application.
In the Eclipse Application that gets started, create a new Project and copy the save.bundles file in there.

At this point the save.bundles file is purely an EMF serialization into XMI, but GMF can initialize a picture from it, right-click 'initialize bundles_diagram file', and you'll get one:

Tadaa, a nice visualization of the bundles and their dependencies. The Jetty bundle uses the commons logging and servlet bundles (the system bundle is ommitted).
Now you can use the GMF features to rearrange your diagram, choose colours, line smoothness etc to make your diagram the way you want it (which is quite useful once you have a lot of bundles). You can even export the picture as a PNG, JPG or SVG file.
Running the introspector in ServiceMix 4 Kernel
The ServiceMix 4 Kernel is an OSGi based system built using Apache Felix. If you want to run the introspector in the ServiceMix 4 Kernel you can follow these steps:
1. Get hold of a SMX 4 Kernel distribution. I created mine by checking out the code from http://svn.apache.org/repos/asf/servicemix/smx4/kernel/trunk and running mvn install to build it. You will find the distribution in assembly/target subdirectory.
2. Run bin/servicemix
Move to the osgi shell and install the introspector, I'm doing this straight from the Google Code project downloads section:
When I start bundle 28 it will do the introspection and save this to the save.bundles file. When loaded in the visualizer, you'll get a picture like the first one in this posting.
Getting your environment set up
I used Eclipse 3.3.1.1 with the EMF/GMF plugins loaded. See this posting for details on setting it up.
Getting the code
All the code used here is available under the Apache License from the Google Code project via SVN. The Eclipse Projects are accessible from here: http://coderthoughts.googlecode.com/svn/trunk/osgi_visualizer/
Getting the distribution
If you just want to use or play with the visualizer, you can download the introspector bundle and visualizer plugins from the the download area: http://code.google.com/p/coderthoughts/downloads/list
Improvements are welcomed!
The project is by no means finished. I'm still in the process of learning more about GMF and any suggestions or improvements are appreciated.
For a project that I was working on I started manually creating Bundle Dependency diagrams. This got me thinking: it should be really easy to create a tool that does this for me using EMF (Eclipse Modeling Framework) and GMF (the Graphical Modeling Framework from Eclipse).
As always in Model Driven Development, you start with a model. In my case a model of how OSGi Bundles relate to each other.
Having the model, you just fill it with data, then use some GMF goodness to display is graphically.
Sounds easy? It was easy! With well under 300 lines of manually written code (and a whole bunch of EMF/GMF generated stuff) the end result looks like this:
In this picture I ran the visualizer in the ServiceMix 4 Kernel to see what was in it.
Main Components
There are two components in this application:
- A bundle that you drop into an OSGi container, when you start the bundle it will walk all the other bundles in the OSGi container and figure out what their dependencies are. The result is stored in an EMF model which is stored a file called save.bundles at the end of the process.
- An Eclipse GMF application that can create a visual diagram from the save.bundles file and allows you to tweak the resulting picture any way you like.
The model
1. Start with a simple model of a Framework (representing the OSGi Container) which contains bundles. Each bundle in turn could be importing stuff from other bundles:
Here are the model details:

After generating the genmodel file from my model file (I only modified the base package in the genmodel package properties) I generated the model code so I could start coding with it. (See here for an earlier post that outlines how to generate code from an EMF model).
The Introspector Bundle
To create a model instance with the bundle dependency data, I've written an self-contained OSGi bundle that I can drop on any OSGi runtime (well, at this point I only tried Equinox and Felix). When the bundle is started it walks all the active bundles in the container and figures out what other bundles each bundle depends on by using the bundle's classloader to resolve imported classes. (Since Package Imports are resolved dynamically this can only be done at runtime in an active OSGi container). The collected info is stored in an instance of my model. I stayed away from using any implementation-specific admin API's, instead I'm just using the bundle's classloader to resolve the packages listed in the Import-Package header to and figure out what bundle the OSGi runtime has linked them to.
Additionally, Require-Bundle dependencies are stored in the model too.
Finally, after all the bundles have been processed, I use the built-in EMF XMI serialization to save model instance to a file (currently always called save.bundles in your temp directory).
That's the hard bit done. You can see the code here in the BundleIntrospector and BundleIntrospectorTools classes which are invoked from my simple Activator.
The Visualizer
Believe it or not, the easy bit is in creating the graphical visualizer. GMF does all the hard work for me. I'm by no means a GMF connaisseur, so I used the GMF Cheat Sheet that comes with GMF in Eclipse. I ran all the wizards from the Cheat Sheet, and used all the defaults to create the .gmfgraph, .gmftool, .gmfmap and .gmfgen files. For some reason, there was one setting that I had to manually change: the Label Mapping, but the cheat sheet told me what to do.
Finally I hit 'generate diagram code' on the .gmfgen file and I'm done.
My Eclipse Workspace looks like this.
Running it
Running the introspector with Equinox
This is very easy from within Eclipse. To try this out, create a new OSGi Framework launch configuration with the introspector bundle and, to give it something to look at, I also include the org.mortbay.jetty bundle and it's dependencies:
Make sure that the introspector bundle is not automatically started. When I launch Equinox I have the following bundles loaded:
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.3.1.R33x_v20070828
1 ACTIVE org.mortbay.jetty_5.1.11.v200706111724
2 ACTIVE org.apache.commons.logging_1.0.4.v200706111724
3 ACTIVE javax.servlet_2.4.0.v200706111738
4 RESOLVED osgi_bundles.introspector.bundle_0.0.3.qualifier
When I start the introspector bundle it starts analyzing the other bundles:
osgi> start 4
Initializing data from bundle: org.eclipse.osgi
Initializing data from bundle: org.mortbay.jetty
Initializing data from bundle: org.apache.commons.logging
...
Saving... Done dependency model saved to: c:\temp\save.bundles
Finished introspecting, stopping bundle.
Running the Visualizer
Now that I have a data file, I can run the visualizer. Just right-click on one of your projects in Eclipse and select Run As Eclipse Application.
In the Eclipse Application that gets started, create a new Project and copy the save.bundles file in there.
At this point the save.bundles file is purely an EMF serialization into XMI, but GMF can initialize a picture from it, right-click 'initialize bundles_diagram file', and you'll get one:
Tadaa, a nice visualization of the bundles and their dependencies. The Jetty bundle uses the commons logging and servlet bundles (the system bundle is ommitted).
Now you can use the GMF features to rearrange your diagram, choose colours, line smoothness etc to make your diagram the way you want it (which is quite useful once you have a lot of bundles). You can even export the picture as a PNG, JPG or SVG file.
Running the introspector in ServiceMix 4 Kernel
The ServiceMix 4 Kernel is an OSGi based system built using Apache Felix. If you want to run the introspector in the ServiceMix 4 Kernel you can follow these steps:
1. Get hold of a SMX 4 Kernel distribution. I created mine by checking out the code from http://svn.apache.org/repos/asf/servicemix/smx4/kernel/trunk and running mvn install to build it. You will find the distribution in assembly/target subdirectory.
2. Run bin/servicemix
____ _ __ __ _
/ ___| ___ _ ____ _(_) ___ ___| \/ (_)_ __
\___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ /
___) | __/ | \ V /| | (_| __/ | | | |> <
|____/ \___|_| \_/ |_|\___\___|_| |_|_/_/\_\
ServiceMix (1.0-m3-SNAPSHOT)
Type 'help' for more information.
------------------------------------------------
servicemix>
Move to the osgi shell and install the introspector, I'm doing this straight from the Google Code project downloads section:
servicemix> osgi
servicemix osgi> install http://coderthoughts.googlecode.com/files/osgi_bundles.
introspector.bundle_0.0.3.200804202025.jar
Bundle ID: 28
servicemix osgi>
When I start bundle 28 it will do the introspection and save this to the save.bundles file. When loaded in the visualizer, you'll get a picture like the first one in this posting.
Getting your environment set up
I used Eclipse 3.3.1.1 with the EMF/GMF plugins loaded. See this posting for details on setting it up.
Getting the code
All the code used here is available under the Apache License from the Google Code project via SVN. The Eclipse Projects are accessible from here: http://coderthoughts.googlecode.com/svn/trunk/osgi_visualizer/
Getting the distribution
If you just want to use or play with the visualizer, you can download the introspector bundle and visualizer plugins from the the download area: http://code.google.com/p/coderthoughts/downloads/list
Improvements are welcomed!
The project is by no means finished. I'm still in the process of learning more about GMF and any suggestions or improvements are appreciated.
Monday, March 31, 2008
Using Jersey (JSR311) inside OSGi with Spring-DM
Or: using REST & OSGi to create a number guessing game
Jersey is an implementation of JSR 311 also know as JAX-RS. It makes writing a REST service quite simple with Java Annotations. So I wanted to use Jersey inside my OSGi bundle with the OSGi HTTP Service. However, as I found out, Jersey is not written to run in an OSGi container...
Fortunately, the problematic code in Jersey is pluggable. In this posting I'm writing a little Jersey REST Application that runs in my OSGi container. I'm using Spring-DM (aka Spring-OSGi) to do the OSGi Service dependency injection which keeps my code really lean & clean (Spring Clean ;) .
To illustrate I wrote a little number guessing game. The very first program I ever wrote was a game like this. This was on the Commodore Pet computer and I was about 10 years old. So beware...
Development Environment Setup
The Jersey version I got is 0.7-ea, which I downloaded from the Jersey download site.
I'm using the Equinox OSGi runtime in Eclipse 3.3.2 (get it here) with Spring-DM added in.
I downloaded Spring-DM 1.0.2 from here and copied all the jars from the dist and the lib directory of the download in my eclipse/plugins directory. The jars in the Spring-DM lib directory have been OSGi-ified by the Spring guys so we can nicely drop them in as OSGi bundles.
Bundle Dependencies
The general dependency picture is like the image below. I'm writing a Jersey app in a bundle that depends on a library bundle which contains the Jersey jars. This way multiple bundles can use the Jersey functionality to implement REST services while sharing the same Jersey Library bundle.

The Jersey Library Bundle
This is a simple wrapper around the Jersey libraries. At the moment I'm only depending on jersey.jar, jsr311-api.jar and asm-3.1.jar. So I'm simply creating an OSGi Bundle Project in Eclipse (Plug-in Project - see this posting for some details on how to do this), add these three jars from the Jersey install to the root of the bundle and then put them on the Bundle-Classpath. Finally simply export all the classes defined by these bundles. I guess a subset of the classes would do too, anyone fancy figuring out what the minimum Export-Package would be?
My MANIFEST.MF looks like this:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: JerseyLibBundle
Bundle-SymbolicName: JerseyLibBundle
Bundle-Version: 1.0.0
Bundle-ClassPath: asm-3.1.jar,
jersey.jar,
jsr311-api.jar,
.
Import-Package: javax.servlet,
javax.servlet.http
Export-Package: ...,
... export all the packages in these jars ...
That's the Jersey Library Bundle done. My Eclipse screen looks like this (click on it to see all the details):

The REST Bundle
This is the interesting bit. Here's where we'll have our REST Guessing Game implemented.
The REST application will be available on:
http://localhost/fun/numbers
Lists all the numbers available in XML format.
http://localhost/fun/numbers/{number}
Returns information about the requested number in text format. The information says what number it is (the same one you asked for) and whether or not you guessed the right number.
I have a jersey_osgi.rest.Number class:
package jersey_osgi.rest;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Number {
enum Location {LESS, FOUND, MORE};
private static final int MAX_NUM = 10;
static List<Number> NUMBERS;
static {
// Initialize with numbers 1 to 10,
// and pick a random on to guess.
NUMBERS = new ArrayList<Number>();
Random random =
new Random(System.currentTimeMillis());
int theOne = random.nextInt(MAX_NUM) + 1;
for (int i=1; i <= MAX_NUM; i++) {
Location location;
if (i == theOne) {
location = Location.FOUND;
} else if (i < theOne) {
location = Location.LESS;
} else {
location = Location.MORE;
}
NUMBERS.add(new Number(i, location));
}
};
private final int number;
private final Location location;
public Number(int num, Location l) {
number = num;
location = l;
}
public int getNumber() {
return number;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("I'm number ");
sb.append(number);
sb.append(". ");
switch (location) {
case FOUND:
sb.append("You guessed right!");
break;
case LESS:
sb.append("You need to guess higher.");
break;
case MORE:
sb.append("You need to guess lower.");
break;
}
return sb.toString();
}
}
Next thing we need is a JSR311 compliant class that binds our Number class to a REST API:
package jersey_osgi.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.ProduceMime;
@Path("/numbers")
public class NumberResource {
@GET
@ProduceMime("text/xml")
public String listNumbers() {
StringBuilder sb = new StringBuilder();
sb.append("<!-- Guess the right number! The following numbers are available. -->");
sb.append("\n");
sb.append("<numbers>");
sb.append("\n");
for (Number number : Number.NUMBERS) {
sb.append("<number>");
sb.append(number.getNumber());
sb.append("</number>");
sb.append("\n");
}
sb.append("</numbers>");
return sb.toString();
}
@GET
@Path("/{id}")
@ProduceMime("text/plain")
public String getNumber(@PathParam("id") String id) {
try {
int i = Integer.parseInt(id);
Number n = Number.NUMBERS.get(i-1);
return n.toString();
} catch (Throwable th) {
return "Sorry that number is out of range";
}
}
}
That's our REST implementation done. Only thing left to do is use the OSGi HTTPService to launch the Jersey Servlet and tell it what our REST Resource are, right? You wish! You would think that the following piece does the trick:
HttpService httpService = ...; // The OSGi HTTP Service
Hashtable initParams = new Hashtable();
initParams.put(
// The following are standard Jersey properties
"com.sun.ws.rest.config.property.resourceConfigClass",
"com.sun.ws.rest.api.core.PackagesResourceConfig");
initParams.put(
"com.sun.ws.rest.config.property.packages",
"jersey_osgi.rest");
Servlet jerseyServlet =
new com.sun.ws.rest.spi.container.servlet.ServletContainer();
httpService.registerServlet("/fun", jerseyServlet, initParams, null);
But hey! I'm getting an ugly exception:
com.sun.ws.rest.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.
This is because the com.sun.ws.rest.api.core.PackagesResourceConfig class contains OSGi unfriendly classloader code (it tries to treat classes as resources, which at least does'nt work on Equinox). Luckily this class is plugged into Jersey, so I can write an OSGi-friendly version. PackagesResourceConfig searches the specified packages for any classes with the JSR311 annotations.
My alternative implementation is called jersey_osgi.common.OSGiResourceConfig. The source is slightly too big for the posting, so just click on the link if you want to see it.
For my OSGi version I have to actually specify the classes that are annotated in a property called jersey_osgi.classnames. So I change to properties like this:
HttpService httpService = ...; // The OSGi HTTP Service
Hashtable initParams = new Hashtable();
initParams.put(
"com.sun.ws.rest.config.property.resourceConfigClass",
"jersey_osgi.common.OSGiResourceConfig");
initParams.put(
"jersey_osgi.classnames",
"jersey_osgi.rest.NumberResource");
Servlet jerseyServlet =
new com.sun.ws.rest.spi.container.servlet.ServletContainer();
httpService.registerServlet("/fun", jerseyServlet, initParams, null);
And run it. Now I'm getting:
com.sun.ws.rest.api.container.ContainerException: No WebApplication provider is present aaaargh! After some debugging I found out that Jersey heavily depends on the META-INF/services SPI architecture which is quite non-OSGi friendly. There are only two possible solutions to this that I can think of:
So I'm taking approach 2 as well and copy all the META-INF/services files of jersey.jar into my bundle. And now it works! I can nicely build my Jersey apps as OSGi bundles that all depend on shared Jersey code.
Where's the Spring stuff?
Spring-DM makes it really easy for me to interact with the OSGi HTTP Service as it simply injects it in my JerseyServletFactory class which then registers the Jersey Servlet. To trigger this, I put a jersey_osgi_spring.xml file in the META-INF/spring directory of my bundle:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="...">
<osgi:reference id="httpServiceRef"
interface="org.osgi.service.http.HttpService"/>
<bean name="jerseyServletFactory"
class="jersey_osgi.common.JerseyServletFactory" >
<property name="jerseyClassNames"
value="jersey_osgi.rest.NumberResource"/>
<property name="rootContext" value="/fun"/>
<property name="httpService" ref="httpServiceRef"/>
</bean>
</beans
The JerseyServletFactory registers the Jersey Servlet with the OSGi HTTP Service. For this it needs that HTTP Service in the first place. Those who had the pleasure of using the pure OSGi API's to get hold of an OSGi Service know that this is actually slightly tricky. So OSGi Declarative Services come to the rescue (which I used in the earlier article about writing a Card Game with OSGi Services). Spring-DM provides an alternative to OSGi-DS and brings with it all of the goodies that Spring has to offer. With the above Spring file, my JerseyServletFactory is nicely reusable (the Root Context and Jersey resource classes are also externalized into the Spring Configuration file) and no bigger than this:
package jersey_osgi.common;
import java.util.Hashtable;
import javax.servlet.Servlet;
import org.osgi.service.http.HttpService;
import com.sun.ws.rest.spi.container.servlet.ServletContainer;
public class JerseyServletFactory {
private String classNames;
private String rootContext;
// Spring uses the setters to inject our stuff
public void setJerseyClassNames(String names) {
classNames = names;
}
public void setRootContext(String ctx) {
rootContext = ctx;
}
public void setHttpService(HttpService httpService) throws Exception {
Hashtable<String, String> initParams =
new Hashtable<String, String>();
initParams.put(
"com.sun.ws.rest.config.property.resourceConfigClass",
"jersey_osgi.common.OSGiResourceConfig");
initParams.put(
"jersey_osgi.classnames",
classNames);
Servlet jerseyServlet =
new ServletContainer();
httpService.registerServlet(rootContext,
jerseyServlet, initParams, null);
}
}
Running it all inside Eclipse
Running Spring-DM inside Equinox as shipped with Eclipse requires careful definition of the runtime environment. You set this up by going to Run | Open Run Dialog ... in Eclipse where you create a new OSGi Framework run configuration. Deselect the Target Platform tickbox and only select the following bundles:
JerseyLibBundle_1.0.0
JerseyOsgiSpringDM_1.0.0
javax.servlet_2.4.0.v200706111738
org.apache.commons.logging_1.0.4.v200706111724
org.eclipse.core.jobs_3.3.1.R33x_v20070709
org.eclipse.core.runtime.compatibility.registry_3.2.100.v20070316
org.eclipse.equinox.common_3.3.0.v20070426
org.eclipse.equinox.http.jetty_1.0.1.R33x_v20070816
org.eclipse.equinox.http.registry_1.0.1.R33x_v20071231
org.eclipse.equinox.http.servlet_1.0.1.R33x_v20070816
org.eclipse.equinox.registry_3.3.1.R33x_v20070802
org.eclipse.osgi.services_3.1.200.v20070605
org.eclipse.osgi_3.3.2.R33x_v20080105
org.mortbay.jetty_5.1.11.v200706111724
org.springframework.bundle.osgi.core_1.0.2
org.springframework.bundle.osgi.extender_1.0.2
org.springframework.bundle.osgi.io_1.0.2
org.springframework.bundle.spring.aop_2.5.1
org.springframework.bundle.spring.beans_2.5.1
org.springframework.bundle.spring.context_2.5.1
org.springframework.bundle.spring.core_2.5.1
org.springframework.osgi.aopalliance.osgi_1.0.0.SNAPSHOT
Like this (I edited the unselected bundles out of the screenshot):

I found that if I don't do it exactly like this that I'm getting problems with the correct logger being instantiated, but this configuration works. Just hit 'Run' and you're off. You can now access the REST application from http://localhost/fun/numbers

I can guess a number: http://localhost/fun/numbers/5

... and try again: http://localhost/fun/numbers/3

Yay!
Get the code
You can get all the code (Apache License) as usual from the google code site. It's at available as 2 Eclipse projects at http://coderthoughts.googlecode.com/svn/trunk/jersey_osgi/. The easiest way to get them into your Eclipse installation is by using an SVN client inside Eclipse and check them out as projects. This is described in more detail in this posting (just search for the 'subclipse' in there).
Jersey is an implementation of JSR 311 also know as JAX-RS. It makes writing a REST service quite simple with Java Annotations. So I wanted to use Jersey inside my OSGi bundle with the OSGi HTTP Service. However, as I found out, Jersey is not written to run in an OSGi container...
Fortunately, the problematic code in Jersey is pluggable. In this posting I'm writing a little Jersey REST Application that runs in my OSGi container. I'm using Spring-DM (aka Spring-OSGi) to do the OSGi Service dependency injection which keeps my code really lean & clean (Spring Clean ;) .
To illustrate I wrote a little number guessing game. The very first program I ever wrote was a game like this. This was on the Commodore Pet computer and I was about 10 years old. So beware...
Development Environment Setup
The Jersey version I got is 0.7-ea, which I downloaded from the Jersey download site.
I'm using the Equinox OSGi runtime in Eclipse 3.3.2 (get it here) with Spring-DM added in.
I downloaded Spring-DM 1.0.2 from here and copied all the jars from the dist and the lib directory of the download in my eclipse/plugins directory. The jars in the Spring-DM lib directory have been OSGi-ified by the Spring guys so we can nicely drop them in as OSGi bundles.
Bundle Dependencies
The general dependency picture is like the image below. I'm writing a Jersey app in a bundle that depends on a library bundle which contains the Jersey jars. This way multiple bundles can use the Jersey functionality to implement REST services while sharing the same Jersey Library bundle.

The Jersey Library Bundle
This is a simple wrapper around the Jersey libraries. At the moment I'm only depending on jersey.jar, jsr311-api.jar and asm-3.1.jar. So I'm simply creating an OSGi Bundle Project in Eclipse (Plug-in Project - see this posting for some details on how to do this), add these three jars from the Jersey install to the root of the bundle and then put them on the Bundle-Classpath. Finally simply export all the classes defined by these bundles. I guess a subset of the classes would do too, anyone fancy figuring out what the minimum Export-Package would be?
My MANIFEST.MF looks like this:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: JerseyLibBundle
Bundle-SymbolicName: JerseyLibBundle
Bundle-Version: 1.0.0
Bundle-ClassPath: asm-3.1.jar,
jersey.jar,
jsr311-api.jar,
.
Import-Package: javax.servlet,
javax.servlet.http
Export-Package: ...,
... export all the packages in these jars ...
That's the Jersey Library Bundle done. My Eclipse screen looks like this (click on it to see all the details):
The REST Bundle
This is the interesting bit. Here's where we'll have our REST Guessing Game implemented.
The REST application will be available on:
http://localhost/fun/numbers
Lists all the numbers available in XML format.
http://localhost/fun/numbers/{number}
Returns information about the requested number in text format. The information says what number it is (the same one you asked for) and whether or not you guessed the right number.
I have a jersey_osgi.rest.Number class:
package jersey_osgi.rest;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Number {
enum Location {LESS, FOUND, MORE};
private static final int MAX_NUM = 10;
static List<Number> NUMBERS;
static {
// Initialize with numbers 1 to 10,
// and pick a random on to guess.
NUMBERS = new ArrayList<Number>();
Random random =
new Random(System.currentTimeMillis());
int theOne = random.nextInt(MAX_NUM) + 1;
for (int i=1; i <= MAX_NUM; i++) {
Location location;
if (i == theOne) {
location = Location.FOUND;
} else if (i < theOne) {
location = Location.LESS;
} else {
location = Location.MORE;
}
NUMBERS.add(new Number(i, location));
}
};
private final int number;
private final Location location;
public Number(int num, Location l) {
number = num;
location = l;
}
public int getNumber() {
return number;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("I'm number ");
sb.append(number);
sb.append(". ");
switch (location) {
case FOUND:
sb.append("You guessed right!");
break;
case LESS:
sb.append("You need to guess higher.");
break;
case MORE:
sb.append("You need to guess lower.");
break;
}
return sb.toString();
}
}
Next thing we need is a JSR311 compliant class that binds our Number class to a REST API:
package jersey_osgi.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.ProduceMime;
@Path("/numbers")
public class NumberResource {
@GET
@ProduceMime("text/xml")
public String listNumbers() {
StringBuilder sb = new StringBuilder();
sb.append("<!-- Guess the right number! The following numbers are available. -->");
sb.append("\n");
sb.append("<numbers>");
sb.append("\n");
for (Number number : Number.NUMBERS) {
sb.append("<number>");
sb.append(number.getNumber());
sb.append("</number>");
sb.append("\n");
}
sb.append("</numbers>");
return sb.toString();
}
@GET
@Path("/{id}")
@ProduceMime("text/plain")
public String getNumber(@PathParam("id") String id) {
try {
int i = Integer.parseInt(id);
Number n = Number.NUMBERS.get(i-1);
return n.toString();
} catch (Throwable th) {
return "Sorry that number is out of range";
}
}
}
That's our REST implementation done. Only thing left to do is use the OSGi HTTPService to launch the Jersey Servlet and tell it what our REST Resource are, right? You wish! You would think that the following piece does the trick:
HttpService httpService = ...; // The OSGi HTTP Service
Hashtable
initParams.put(
// The following are standard Jersey properties
"com.sun.ws.rest.config.property.resourceConfigClass",
"com.sun.ws.rest.api.core.PackagesResourceConfig");
initParams.put(
"com.sun.ws.rest.config.property.packages",
"jersey_osgi.rest");
Servlet jerseyServlet =
new com.sun.ws.rest.spi.container.servlet.ServletContainer();
httpService.registerServlet("/fun", jerseyServlet, initParams, null);
But hey! I'm getting an ugly exception:
com.sun.ws.rest.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.
This is because the com.sun.ws.rest.api.core.PackagesResourceConfig class contains OSGi unfriendly classloader code (it tries to treat classes as resources, which at least does'nt work on Equinox). Luckily this class is plugged into Jersey, so I can write an OSGi-friendly version. PackagesResourceConfig searches the specified packages for any classes with the JSR311 annotations.
My alternative implementation is called jersey_osgi.common.OSGiResourceConfig. The source is slightly too big for the posting, so just click on the link if you want to see it.
For my OSGi version I have to actually specify the classes that are annotated in a property called jersey_osgi.classnames. So I change to properties like this:
HttpService httpService = ...; // The OSGi HTTP Service
Hashtable
initParams.put(
"com.sun.ws.rest.config.property.resourceConfigClass",
"jersey_osgi.common.OSGiResourceConfig");
initParams.put(
"jersey_osgi.classnames",
"jersey_osgi.rest.NumberResource");
Servlet jerseyServlet =
new com.sun.ws.rest.spi.container.servlet.ServletContainer();
httpService.registerServlet("/fun", jerseyServlet, initParams, null);
And run it. Now I'm getting:
com.sun.ws.rest.api.container.ContainerException: No WebApplication provider is present aaaargh! After some debugging I found out that Jersey heavily depends on the META-INF/services SPI architecture which is quite non-OSGi friendly. There are only two possible solutions to this that I can think of:
- Export-Package META-INF.services in the Jersey Library Bundle. This works but is kinda nasty because you can only do it once in a single OSGi runtime. If you have multiple bundles exporting the same package, the OSGi runtime will only link you to only one of them for this package. If multiple bundles export META-INF.services you will get unexpected behaviour.
- Copy the META-INF/services directory from the jersey.jar into our own bundle. Other projects with OSGi bundles seem to be taking this approach too.
So I'm taking approach 2 as well and copy all the META-INF/services files of jersey.jar into my bundle. And now it works! I can nicely build my Jersey apps as OSGi bundles that all depend on shared Jersey code.
Where's the Spring stuff?
Spring-DM makes it really easy for me to interact with the OSGi HTTP Service as it simply injects it in my JerseyServletFactory class which then registers the Jersey Servlet. To trigger this, I put a jersey_osgi_spring.xml file in the META-INF/spring directory of my bundle:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="...">
<osgi:reference id="httpServiceRef"
interface="org.osgi.service.http.HttpService"/>
<bean name="jerseyServletFactory"
class="jersey_osgi.common.JerseyServletFactory" >
<property name="jerseyClassNames"
value="jersey_osgi.rest.NumberResource"/>
<property name="rootContext" value="/fun"/>
<property name="httpService" ref="httpServiceRef"/>
</bean>
</beans
The JerseyServletFactory registers the Jersey Servlet with the OSGi HTTP Service. For this it needs that HTTP Service in the first place. Those who had the pleasure of using the pure OSGi API's to get hold of an OSGi Service know that this is actually slightly tricky. So OSGi Declarative Services come to the rescue (which I used in the earlier article about writing a Card Game with OSGi Services). Spring-DM provides an alternative to OSGi-DS and brings with it all of the goodies that Spring has to offer. With the above Spring file, my JerseyServletFactory is nicely reusable (the Root Context and Jersey resource classes are also externalized into the Spring Configuration file) and no bigger than this:
package jersey_osgi.common;
import java.util.Hashtable;
import javax.servlet.Servlet;
import org.osgi.service.http.HttpService;
import com.sun.ws.rest.spi.container.servlet.ServletContainer;
public class JerseyServletFactory {
private String classNames;
private String rootContext;
// Spring uses the setters to inject our stuff
public void setJerseyClassNames(String names) {
classNames = names;
}
public void setRootContext(String ctx) {
rootContext = ctx;
}
public void setHttpService(HttpService httpService) throws Exception {
Hashtable<String, String> initParams =
new Hashtable<String, String>();
initParams.put(
"com.sun.ws.rest.config.property.resourceConfigClass",
"jersey_osgi.common.OSGiResourceConfig");
initParams.put(
"jersey_osgi.classnames",
classNames);
Servlet jerseyServlet =
new ServletContainer();
httpService.registerServlet(rootContext,
jerseyServlet, initParams, null);
}
}
Running it all inside Eclipse
Running Spring-DM inside Equinox as shipped with Eclipse requires careful definition of the runtime environment. You set this up by going to Run | Open Run Dialog ... in Eclipse where you create a new OSGi Framework run configuration. Deselect the Target Platform tickbox and only select the following bundles:
JerseyLibBundle_1.0.0
JerseyOsgiSpringDM_1.0.0
javax.servlet_2.4.0.v200706111738
org.apache.commons.logging_1.0.4.v200706111724
org.eclipse.core.jobs_3.3.1.R33x_v20070709
org.eclipse.core.runtime.compatibility.registry_3.2.100.v20070316
org.eclipse.equinox.common_3.3.0.v20070426
org.eclipse.equinox.http.jetty_1.0.1.R33x_v20070816
org.eclipse.equinox.http.registry_1.0.1.R33x_v20071231
org.eclipse.equinox.http.servlet_1.0.1.R33x_v20070816
org.eclipse.equinox.registry_3.3.1.R33x_v20070802
org.eclipse.osgi.services_3.1.200.v20070605
org.eclipse.osgi_3.3.2.R33x_v20080105
org.mortbay.jetty_5.1.11.v200706111724
org.springframework.bundle.osgi.core_1.0.2
org.springframework.bundle.osgi.extender_1.0.2
org.springframework.bundle.osgi.io_1.0.2
org.springframework.bundle.spring.aop_2.5.1
org.springframework.bundle.spring.beans_2.5.1
org.springframework.bundle.spring.context_2.5.1
org.springframework.bundle.spring.core_2.5.1
org.springframework.osgi.aopalliance.osgi_1.0.0.SNAPSHOT
Like this (I edited the unselected bundles out of the screenshot):
I found that if I don't do it exactly like this that I'm getting problems with the correct logger being instantiated, but this configuration works. Just hit 'Run' and you're off. You can now access the REST application from http://localhost/fun/numbers
I can guess a number: http://localhost/fun/numbers/5
... and try again: http://localhost/fun/numbers/3
Yay!
Get the code
You can get all the code (Apache License) as usual from the google code site. It's at available as 2 Eclipse projects at http://coderthoughts.googlecode.com/svn/trunk/jersey_osgi/. The easiest way to get them into your Eclipse installation is by using an SVN client inside Eclipse and check them out as projects. This is described in more detail in this posting (just search for the 'subclipse' in there).
Subscribe to:
Posts (Atom)