13 September 2013

WebLogic Server - Using OSGi Bundles with Java EE Applications

The WLS 12c (12.1.2) release includes a new feature that enables OSGi bundles to be installed and used by deployed applications.

The full documentation is here:

http://docs.oracle.com/middleware/1212/wls/WLPRG/osgi.htm

In short this feature enables WLS to create an OSGi framework (Apache Felix 4.03) in which OSGi Bundles are installed and accessed by applications.

Applications provide an XML reference element to define the named OSGi framework and Bundle of interest, which is then  published into the JNDI tree from where it can be referenced and used.

An OSGi Bundle can be included as part of the application archive being deployed or it can be provided as part of the server library set.

To provide a simple example, the Apache Felix tutorial Dictionary Service was first implemented and packaged as an OSGi Bundle.

The Bundle manifest looks as follows:
  Manifest-Version: 1.0
  Bnd-LastModified: 1378960044511
  Build-Jdk: 1.7.0_17
  Built-By: sbutton
  Bundle-Activator: tutorial.example2.Activator
  Bundle-ManifestVersion: 2
  Bundle-Name: DictionaryService OSGi Bundle
  Bundle-SymbolicName: tutorial.example2.service.DictionaryService
  Bundle-Version: 1.0.0.SNAPSHOT
  Created-By: Apache Maven Bundle Plugin
  Export-Package: tutorial.example2.service;version="1.0.0.SNAPSHOT"
  Import-Package: org.osgi.framework;version="[1.6,2)"
  Tool: Bnd-1.50.0

The Bundle archive contains only a few classes, the DictionaryService interface and an Activator implementation which provides an inner class implementation of the DictionaryService that is registered when the Bundle is activated.


 
A small web application was then developed to make use of the DictionaryService Bundle using a Servlet.

The Servlet performs the following tasks:
  • Injects the Bundle reference from JNDI using the @Resource annotation
  • Looks up the ServiceReference for the DictionaryService.class to be used 
  • Obtains an instance of the DictionaryService from the ServiceReference
  • Makes calls on the DictionaryService to check whether a word is in the known word list

Inject Bundle reference from its JNDI location:
@WebServlet(name = "TestServlet", urlPatterns = {"/TestServlet", "/test", "/osgi"})
public class TestServlet extends HttpServlet {

    @Resource(lookup = "java:app/osgi/Bundle")
    Bundle bundle;
    ...
}

The Bundle provides access to the registered Services, in this case the DictionaryService:
  if (bundle != null) {              
                             
    BundleContext bc = bundle.getBundleContext();
           
    ServiceReference dictionaryServiceRef = 
      bc.getServiceReference(DictionaryService.class);
    DictionaryService dictionaryService = 
      (DictionaryService) bc.getService(dictionaryServiceRef);

    ...

  }
 
The methods on the DictionaryService can then be used:

  out.printf("<div>wordlist: %s </div>", 
             Arrays.toString(dictionaryService.wordlist()));

  out.printf("<div>checkWord(\"%s\"): %s</div>", 
             wordToCheck, dictionaryService.checkWord(wordToCheck));


The Bundle then needs to be defined for the web application to use, which is done using the weblogic deployment descriptor.  In this example, the weblogic.xml file contains the following entry:
  <osgi-framework-reference>
    <name>test</name>
    <application-bundle-symbolic-name>
      tutorial.example2.service.DictionaryService
    </application-bundle-symbolic-name>
  </osgi-framework-reference>

The bundle-symbolic-name is used to specify the bundle to be used.

The name element specifies the name of the OSGi framework that has been configured.  With WebLogic Server 12c (12.1.2) there are several ways to define and configure OSGi frameworks such as the Admin Console, WLST, programmatically with Java or by directly editing the domain config.xml file.

With this small web application, the DictionaryService Bundle was deployed as part of the WAR file itself.  This is performed by placing the JAR file in the WEB-INF/osgi-lib directory, whereupon WLS will detect it and install it.  The DictionaryService Bundle could also be installed by copying it into the $ORACLE_HOME/wlserver/server/osgi-lib directory.

With the WAR file packaged and deployed to WLS,  the console logs show the DictionaryService Bundle being Activated, where System.out.println() calls were inserted into the start and stop Activator methods to view them being called:

*** START Bundle org.apache.felix.framework.BundleContextImpl@21052189
tutorial.example2.service.DictionaryService ***
Finally the TestServlet is accessed, demonstrating the DictionaryService being accessed and used: