Develop and Deploy Web Services as OSGi Bundles

An SOA strategy for deploying and supporting multiple versions of a Web service

This article describes a step-by-step approach to developing and deploying Web service components as OSGi bundles. Apache CXF's distributed OSGi framework, cxf-dosgi, will be used with Eclipse's Equinox OSGi framework for developing and deploying the service bundles. A simple web application client is developed to access the distributed service bundles. A web service provider often faces the challenge of supporting multiple versions of a service at the same time. The article also demonstrates how OSGi provides a clean and uncluttered environment to facilitate just such a need.

Nalla Senthilnathan, IT Consultant, Greater Detroit

Nalla SenthilnathanNalla has been working as an IT consultant in the Metro Detroit area since the year 2000. He has designed and developed several enterprise level IT projects for major automotive manufacturers. Nalla holds a Ph.D in Mechanical Engineering from the National University of Singapore.



14 October 2009

Also available in Chinese

Introduction

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.


Pre-requisites

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.

Prepare the OSGi container

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
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
choose 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
required bundles

Our OSGi container is now ready to rock and roll for some distributed service deployments.


Develop a service bundle

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
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.

Deploy the service bundle

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
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
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.


New version of service bundle

An interesting feature of deploying a Web service as an OSGi bundle is multiple versions of a web service can be deployed simultaneously. Since class loading is sandboxed to each bundle, a jar used in one version of the service will not affect the other version of the service. 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
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
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
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.


Invoking the new service

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.


Summary

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.


Download

DescriptionNameSize
Service and Client Bundles for this articlecxf-dosgi-dw-article.zip3,562KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into SOA and web services on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=435720
ArticleTitle=Develop and Deploy Web Services as OSGi Bundles
publish-date=10142009