GlassFish V3 Extensions, part 4 : OSGi Declarative Services

Neil Bartlett was absolutely right that my last entry might have been a little too deep so I am simplifying the whole example in this entry by using plain OSGi Declarative Services in GlassFish v3. Declarative Services are described by Neil there and even more concisely by Peter Kriens with bnd at this location.

So I am going to have 2 modules in this example :

  • service bundle, this is my plain OSGi bundle, which packages two classes, the API and one implementation of that API. 
  • webclient, plain war file that use Java EE injection to access the OSGi declared service in the above service bundle.
Files can be downloaded there, there are two sub directories for each module. 

OSGi Declarative Service bundle

The OSGi bundle project is using maven to build as usual with GlassFish V3, the project contains 5 files

./pom.xml
./src
./src/main/java/examples/services/api/SimpleService.java
./src/main/java/examples/services/impl/SimpleServiceImpl.java
./src/main/resources/META-INF/MANIFEST.MF
./src/main/resources/OSGI-INF/simpleservice.xml

 Let's dive in the content now, first the service definition (unchanged from last entry) :

package examples.services.api;
/\*\*
 \* Simple service defition
 \* @author Jerome Dochez
 \*/
public interface SimpleService {
   /\*\*
    \* Returns a implementation specific string
    \* @return a String
    \*/
   public String getString();
}

The powerful implementation is using a different package and consist of the following java class :

package examples.services.impl;
import examples.services.api.SimpleService;
public class SimpleServiceImpl implements SimpleService {
    public String getString() {
        return "Simple Declarative Service implementation at your service !";
    }
} 

now the serious things can start, first with the manifest file containing the OSGi metadata :

Bundle-Version: 1.0
Bundle-SymbolicName: examples.services.declarative
Bundle-Name: Services definition bundle for OSGi Declarative Services in GlassFish
Export-Package: examples.services.api
Service-Component: OSGI-INF/simpleservice.xml
Bundle-ManifestVersion: 2 

Two things are worth mentioning, first only the API package is exported, the implementation package is a private entity of the module. Encapsulation is one of the benefits of modularization. Second the "Service-Component" entry points to a separate xml file describing the services provided by this module (hence the name Declarative Services I suppose). 

The content of the service definition file, is defined by the OSGi alliance specification, in this example the resulting xml is pretty simple :

<?xml version="1.0"?>
<component name="decl-service-1" immediate="true">
	<implementation class="examples.services.impl.SimpleServiceImpl"/>
	<service>
		<provide interface="examples.services.api.SimpleService"/>
	</service>
</component> 

Note that I gave a name (decl-service-1) to that service implementation, the curious reader should now experiment with creating more than services implementations, giving a different name to each of them. Build the project (mvn install).

The Java EE client

Very similar to the last blog entry where I was using Java EE injection (through the @Resource annotation), the webclient has not changed much :

import ...
import examples.services.api.SimpleService;
@WebServlet(urlPatterns={"/hello"})
public class HelloWorld extends HttpServlet {
    @Resource(mappedName="decl-service-1")
    SimpleService simpleService;
    public void doGet(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {      
        PrintWriter pw = res.getWriter();
	try {
	    pw.println("Service class is " + SimpleService.class + "<br>");
	    pw.println("First service is " + simpleService);
 	    if (simpleService!=null) {
		pw.println("SimpleService says " + simpleService.getString());
		pw.println("<br>");
	    }
	} catch(Exception e) {
	    e.printStackTrace();
	}
    }
} 

Needless to say that the servlet is not importing the implementation package, just the API. In fact even if it tried, it would fail at runtime (not compile time unfortunately until JDK 7 starts supporting modules and OSGi metadata) since only the API package is exported by the bundle. Another mvn install to get the resulting war file.

Getting things together

GlassFish V3 does not ship with all the OSGi services, just the basic runtime, so first, to be able to use OSGi declarative services you need to download the support for Declarative Services for Felix from there , you will need to take the SCR jar file. Once downloaded you should deploy it to the application server and deploy the service bundle as well as the webclient web application (they should be in the respective target directories of your project if you built successfully)

asadmin deploy --type osgi org.apache.felix.scr-1.0.8.jar
asadmin deploy --type osgi simple-declarative-service.jar
asadmin deploy webclient.war

now point your web browser to http://localhost:8080/webclient/hello

Service class is interface examples.services.api.SimpleService<br>
First service is examples.services.impl.SimpleServiceImpl@ec0c06f 
SimpleService says Simple Declarative Service implementation at your service ! 

Now combine this with the example of my last blog entry, you can see that I can now have my service API implemented either with a Spring component, or by a plain old OSGi Declarative Service and the actual implementation location will be immaterial to the servlet client code. Ah ! a good service based architecture can solve many problems just like a level of indirection can often lead to better code...

My next entry ? Maybe implementing my service with an EJB component, and show how one service can be implemented by a Spring bean, by an OSGi Declarative Service and by an EJB and have all three of them injected in the same servlet instance and be invoked transparently by the servlet code... would you be interested ?

Comments:

Nice article
I would be very interested in the next one with Spring service + EJB
Question :
I have currently a case where i would like a system OSGi-like.
My application, started as a demo, with Grails :
I have currenlty Interfaces, Base classes externalized in JAR under my GRAILS_APP/LIB.
Now i should add incrementaly , with automatic wiring of Spring Beans in the parent context :
- implemeneted classes for the processing (which is a little workflow) these are the beans i should register to the parent app context(Spring)
- a service
- a controller for incoming HTTP calls.

As i'd like to do this without restart.. i interested some days ago in Osgi, which seems fit my needs.
My question is : in my bundle i should put the implemented classes + services.
Then add/update controller/servlet in the web app.
Could i keep the web front end with grails (not OSGi) , deployed in Glassfish, and add bundles each time i implement new processes

Posted by Laurent on June 09, 2009 at 04:58 PM PDT #

For anyone trying this out, make sure you use promoted build 49 onward.
GlassFish v3 promoted builds are here - http://download.java.net/glassfish/v3/promoted/
You can also update your existing install using the http://pkg.glassfish.org/v3/dev repository.

Posted by Alexis MP on June 10, 2009 at 11:32 PM PDT #

Very nice. I am trying to do something very similar to this, only I have OSGi services that I want to remote using Hessian or Burlap, then consume them with an RCP client. Any examples of now remoting these services using the Spring Dispatcher servlet? See this: http://static.springframework.org/spring/docs/2.5.x/reference/remoting.html#remoting-introduction

Posted by Kendal on June 19, 2009 at 03:00 AM PDT #

I'm just now getting around to actually trying your examples from part 3 and part 4, and I've been playing around with getting them working on the equinox platform. I've got bundles that I need to deploy that currently deploy under equinox, but don't work well under felix. I've followed your instructions using b49, b50, and now b51 builds of glassfish v3 preview, but using equinox as the OSGi platform, the servlet always returns results similar to:
Service class is interface examples.services.api.SimpleService<br>
First service is null

It seems the service implementation are never actually getting injected, but I see no errors, and I certainly see the services deploy properly, and I can see that they're installed and active in the felix / equinox consoles. Any help here -- is this a feature that should be felix specific?

Posted by Kendal on June 22, 2009 at 07:02 AM PDT #

Post a Comment:
Comments are closed for this entry.
About

dochez

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today