OSGi is a dynamic module system for Java. OSGi Alliance (See Resources) publishes the specifications for the module system. Some of the popular OSGi containers include Eclipse Equinox (See Resources) and Apache Felix among others (See Resources). OSGi is fast gaining momentum as a framework for developing and deploying modular reusable Java programs.
An OSGi container enables deploying java modules ("bundles" in OSGi-speak) in jar format. An interesting feature of OSGi is multiple versions of a bundle can be deployed to the same container. All the bundles deployed in an OSGi container run in one JVM. If a client of a service resides outside this OSGi container then the service bundle need to have distributed capability. Apache cxf-dosgi (See Resources) is a new services framework that enables distributed capability for OSGi bundles.
When a web services provider develops a newer version of a service, it often becomes necessary to continue supporting existing clients. A web services provider therefore has a need to deploy and maintain multiple versions of a service simultaneously. OSGi naturally offers a compelling choice for this need.
I have chosen Eclipse Equinox as the OSGi container and Apache CXF as a web services framework since CXF team has released a new framework called cxf-dosgi which enables OSGi bundles to be distributed. Using this framework, one can develop and deploy a web service as an OSGi bundle. Since multiple versions of a bundle can co-exist simultaneously, one could deploy and maintain multiple versions of a web service at the same time. I will use Apache Tomcat as a servlet container to deploy the clients.
In this article I will describe a step by step approach to developing a cxf-dosgi service bundle, how to deploy it in an OSGi container and access it with a simple web client running in a different JVM than the one where the OSGi container is running. I will also describe developing a different version of the same service, deploy it to the same OSGi container and show that the two versions of the service can co-exist serving multiple types of clients.
First download and install Eclipse 3.5 (Galileo). Eclipse 3.5 includes an OSGi framework called Equinox (See Resources) below.
Next download cxf-dosgi single bundle distribution and the osgi compendium bundle. Download both these bundles to the same local directory. See Resources below for download links.
Download and install Apache Tomcat 5.5.9. We will use this servlet container outside the OSGi container (Eclipse) to install and run our service clients.
Before we develop a distributed service bundle we first prepare the OSGi container by starting the container and registering cxf-dosgi as the service provider enabler.
Start Eclipse 3.5 with an empty workspace. Set the Perspective to "Plug-In Development". An Eclipse plug-in is basically an OSGi bundle.
Next import the cxf-dosgi osgi compendium bundle and the osgi compendium bundle using the menu option:
File/Import/Plug-In Development/Plug-ins and Fragments
and choose the directory where the bundles are downloaded. See Figure 1 below.
Figure 1. Import required bundles. specify directory location
Click Next. In the next dialog Eclipse displays the downloaded bundles. See Figure 2 below.
Figure 2. Import required bundles, select the downloaded bundles
Click Add All and Finish. Eclipse automatically creates two Plug-In Development projects called org.osgi.compendium and cxf-dosgi-ri-singlebundle-distribution. Next we need to specify that the osgi compendium
bundle as the required bundle to the dosgi bundle. Double-click the META-INF/MANIFEST.MF file in the cxf-dosgi-ri-singlebundle-distribution project. When Eclipse opens the manifest file in design mode, select the Dependencies tab and add org.osgi.compendium as the "Required Plug-ins". Your Eclipse environment should now look like Figure 3.
Figure 3. Import required bundles
Our OSGi container is now ready to rock and roll for some distributed service deployments.
Next, we will create a simple POJO based Web service called DictionaryService with just
one method - lookupWord(string) which returns a string (meaning of the word) as
response.
To create a service bundle in Eclipse, first ensure the Perspective is set to "Plug-in
Development". Create a new Plug-in project called DictionaryService. Select
com.demo.cxfdemo.Activator as the package structure while creating the project.
Replace the default Activator.java created by Eclipse with the Activator.java,
DictionaryService.java and DictionaryServiceImpl.java found in the attached bundle
(DictionaryService_1.0.0.200908011529.jar in the cxf-dosgi-dw-article.zip file) (See the Downloads link below).
Double-click on the META-INF/MANIFEST.MF in the DictionaryService project. Eclipse should display the design
view of the manifest file. Click on the Dependencies tab and clear the Required Plug-
ins and add org.osgi.framework in the Imported Packages. Your Eclipse should look like
Figure 4 below.
Figure 4. Create a service bundle
The sources for Activator.java, DictionaryService.java and
DictionaryServiceImpl.java look like Listing 1.
Listing 1. DictionaryService bundle code
package com.demo.cxfdosgi;
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
public class Activator implements BundleActivator {
private ServiceRegistration registration;
public void start(BundleContext bc) throws Exception {
Dictionary<String, String> props = new Hashtable<String, String>();
props.put("osgi.remote.interfaces", "*");
props.put("osgi.remote.configuration.type", "pojo");
props.put("osgi.remote.configuration.pojo.address",
"http://localhost:9000/DictionaryService");
registration = bc.registerService(DictionaryService.class.getName(),
new DictionaryServiceImpl(), props);
}
public void stop(BundleContext context) throws Exception {
registration.unregister();
}
}
package com.demo.cxfdosgi;
public interface DictionaryService {
public String lookupWord(String word) throws Exception;
}
package com.demo.cxfdosgi;
public class DictionaryServiceImpl implements DictionaryService {
public String lookupWord(String word) throws Exception {
return word + " means...";
}
}
|
Our Web service is basically a pojo (interface and implementation). The Activator class sets the service properties and registers the service. Remarkably the DictionaryService does not have to implement or extend any cxf classes! We do not even have to set the dosgi single bundle as a required plug-in. By the magic of cxf-dosgi, when the Run configuration is executed it will be deployed as a cxf Web service.
The next step is to deploy and run the service bundle. For this we need to create a
Run Configuration. Right-click the DictionaryService project and select Run As/Run
Configurations. Create a new configuration in the OSGi Framework folder called
demo_dosgi. Your Run Configuration popup dialog should look like Figure
5.
Figure 5. Run configuration
Click Apply and Run. Eclipse should now start its internal OSGi framework (Equinox) install and start the three bundles in the workspace. Your Eclipse environment should now look like Figure 6.
Figure 6. Run bundles
Note that Eclipse does not automatically display the osgi> prompt. Click on the
Console window once to get this prompt. Run the command ss (short status) at this
prompt to see the status of the bundles. To get a list of other available commands,
run ? at the prompt. The above display also confirms that the service endpoint URL
http://localhost:9000/DictionaryService is available for use. This can be confirmed by
running the URL http://localhost:9000/DictionaryService?wsdl in a browser which
should now display the WSDL content. Save this xml document as
DictionaryService.wsdl in a temporary folder. We will use this in our next section to
generate a client.
Develop Web client to invoke service
To invoke the newly deployed Web service, we now create a simple Web application client.
In Eclipse Switch to Java EE Perspective. Create a new Dynamic Web Application
project called DictionaryServiceClient. Copy the DictionaryService.wsdl to the
WebContent folder. Right-click on the DictionaryService.wsdl file and select Web
Services/Generate Client. Eclipse should now have created a set of client Java files in
the src folder with a package name com.demo.cxfdosgi. We now create a jsp file
dictionaryServiceClient.jsp to invoke this service proxy like Listing 2 below:
Listing 2. dictionaryServiceClient.jsp code
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
import="com.demo.cxfdosgi.DictionaryServicePortTypeProxy"%>
<html>
<body>
<%
DictionaryServicePortTypeProxy proxy = new
DictionaryServicePortTypeProxy();
out.println("?? DictionaryService response =
"+proxy.lookupWord("whatisthis"));
%>
</body>
</html>
|
Right-click on the DictionaryServiceClient project and export a war file
DictionaryServiceClient.war. Copy this to the C:/jakarta-tomcat-5.5.9/webapps
folder. Run C:/jakarta-tomcat-5.5.9/bin/startup.exe and access
http://localhost:8082/DictionaryServiceClient/dictionaryServiceClient.jsp. The
browser will display:
?? DictionaryService response = whatisthis means... |
Since Eclipse and Tomcat are running in two different JVMs, we have tested the service bundle with a distributed client. Note: Tomcat's HTTP port is set to 8082 since Eclipse is already using 8080 to deploy cxf Web service.
An interesting feature of deploying a Web service as an OSGi bundle is multiple versions of a web service can be deployed simultaneously. We now develop a next version of the DictionaryService as DictionaryServiceV2 whose lookupWord method returns array of two strings, one with the meaning of the word and the other its synonyms. Since we are changing the method signature, we are clearly breaking the existing clients. By deploying the revised Web service as a separate bundle, we enable the old clients to ontinue to work while enabling new clients to use the newer version of the service.
In Eclipse switch to the Plug-in Development Perspective and create a new Plug-in
project called DictionaryServiceV2 with the three files: Activator.java,
DictionaryServiceV2.java, DictionaryServiceV2Impl.java with the following sources:
Listing 3. DictionaryServiceV2 bundle code
package com.demo.cxfdosgi.v2;
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
public class Activator implements BundleActivator {
private ServiceRegistration registration;
public void start(BundleContext bc) throws Exception {
Dictionary<String, String> props = new Hashtable<String, String>();
props.put("osgi.remote.interfaces", "*");
props.put("osgi.remote.configuration.type", "pojo");
props.put("osgi.remote.configuration.pojo.address",
"http://localhost:9000/DictionaryServiceV2");
registration = bc.registerService(DictionaryServiceV2.class.getName(),
new DictionaryServiceV2Impl(), props);
}
public void stop(BundleContext context) throws Exception {
registration.unregister();
}
}
package com.demo.cxfdosgi.v2;
public interface DictionaryServiceV2 {
/**
* @param word - String, whose meaning and synonyms are requested
* @return String[] - where String[0] has the word meaning and
* String[1] has synonyms
* @throws Exception
*/
public String[] lookupWord(String word) throws Exception;
}
package com.demo.cxfdosgi.v2;
public class DictionaryServiceV2Impl implements DictionaryServiceV2 {
public String[] lookupWord(String word) throws Exception {
// TODO Auto-generated method stub
String[] result = new String[2];
result[0] = word + " means...";
result[1] = "Synonyms:...";
return result;
}
}
|
Your Eclipse window should look like Figure 7.
Figure 7. Create DictionaryServiceV2 bundle
Edit the demo_dosgi Run configuration and ensure that DictionaryServiceV2 bundle
is included in the configuration, Figure 8.
Figure 8. Revised Run configuration
Click Apply and Run. Eclipse should now restart the OSGi framework, install the fourth
bundle (DictionaryServiceV2) and start all four bundles. Your Eclipse should
now look like Figure 9.
Figure 9. Run bundles
Which confirms that all four bundles are installed and running. The log message also confirms that the service endpoints:
http://localhost:9000/DictionaryService, and
http://localhost:9000/DictionaryServiceV2
are active. Access the second service in a browser like
http://localhost:9000/DictionaryServiceV2?wsdl and save the displayed wsdl content
to a file DictionaryServiceV2.wsdl.
To invoke the newer version of the web service we need to generate a new client.
Create a new project DictionaryServiceV2Client as a Dynamic web Application. Copy
the wsdl and generate the Java client using the same steps as described for the first
version. Create a new jsp file dictionaryServiceV2Client.jsp like:
Listing 4. dictionaryServiceV2Client.jsp code
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"
import="com.demo.cxfdosgi.v2.DictionaryServiceV2PortTypeProxy"%>
<html>
<body>
<%
DictionaryServiceV2PortTypeProxy proxy = new
DictionaryServiceV2PortTypeProxy();
String[] resp = proxy.lookupWord("whatisthis");
out.println("?? DictionaryService response = "+resp[0]);
%>
<br/>
<%
out.println("?? DictionaryService response = "+resp[1]);
%>
</body>
</html>
|
Export this project as DictionaryServiceV2Client.war and install it to a tomcat server
running outside Eclipse. Accessing
http://localhost:8082/DictionaryServiceV2Client/dictionaryServiceV2Client.jsp in a
browser should now display:
?? DictionaryService response = whatisthis means... ?? DictionaryService response = Synonyms:... |
We have now successfully developed, deployed and tested two versions of a web service.
In this article we did not use any of the cxf-dosgi API classes in our pojo service bundle. However, it is possible to use cxf-dosgi classes by importing the specific package by editing the manifest.mf file ("Imported Packages" section above). Note that all J2SE classes are available natively to a bundle. However, to use any JEE services like sending mails etc. from a service bundle, you need to import the specific JEE package by editing the manifest.mf file. Eclipse provides most of the JEE packages available for importing.
I have described a step-by-step approach to developing and deploying a web service as an OSGi bundle and invoking the service using a simple web application client. I have also discussed the benefits of this SOA strategy in deploying and supporting multiple versions of a service at the same time in an uncluttered OSGi container environment.
| Description | Name | Size | Download method |
|---|---|---|---|
| Service and Client Bundles for this article | cxf-dosgi-dw-article.zip | 3,562KB | HTTP |
Information about download methods
Learn
- Learn more about the OSGi specifications at
OSGi Alliance.
- Check out some popular OSGi containers "Eclipse Equinox" and
"Apache Felix".
-
"Best
practices for Web Services Versioning" (developerWorks, Jan 2004).
-
Designing and versioning compatible Web services,
Strategies for Web services versioning.
- Browse the
technology bookstore
for books on these and other technical topics.
Get products and technologies
-
"Eclipse IDE for Java EE Developers"
Download Eclipse 3.5 (includes Equinox) for developing and deploying OSGi bundles.
-
"Apache cxf-dosgi"
Download Apache cxf-dosgi single-bundle distribution (jar).
-
"OSGi Compendium bundle"
A required bundle for cxf-dosgi.
-
"Apache Tomcat 5.5.9"
Servlet container to deploy web clients that invoke the OSGi service bundles.
- Download
IBM product evaluation versions
or explore
the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from
DB2®, Lotus®, Rational®, Tivoli®, and
WebSphere®.
Discuss
- Check out
developerWorks
blogs and
get involved in the
developerWorks community.
Comments (Undergoing maintenance)






