Developing OSGi Applications with Blueprint bundles and WebSphere Application Server V8.5 Liberty Profile

Z Jacek Laskowski - Wiki Amatora Programowania
Skocz do: nawigacji, wyszukiwania

This article demonstrates the OSGi Blueprint Container (see 121 Blueprint Container Specification Version 1.0 in the OSGi Service Platform Enterprise Specification Version 4.2) and how it simplifies developing OSGi Applications with WebSphere Application Server V8.5 Liberty Profile and IBM WebSphere Application Server V8.5 Liberty Profile Developer Tools V8.5.1.

The article uses the latest IBM WebSphere Application Server Liberty Profile V8.5.Next Alpha and IBM WebSphere Application Server Developer Tools for Eclipse (WDT) V.Next Alpha as they offer more Java EE 6 features you may eventually use (more importantly support for EJB Lite and CDI application development) - the sooner we jump in on the WAS V.Next's bandwagon the better. You've been warned.

jacek:~/apps/wlp.next
$ ./bin/server version
WebSphere Application Server wlp-1.0.1.20121006-0828(websphere-kernel_1.0.1) on Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_13-b20
Liberty.next-was-dev-tools-eclipse-about.png

Spis treści

liberty.hello.web - Web Application Bundle

In this part of the article you develop a very simple servlet that prints out a message. It is to make sure that the development and runtime environment are all set up properly and show that a Web Application Bundle (WAB) is a mere Web ARchive (WAR) with the OSGi support.

In Eclipse, go to File > New > OSGi Bundle Project.

Use the following to configure the project:

  • Project name: liberty.hello.web
  • Target runtime: WebSphere Application Server V8.5.Next Liberty Profile (or whatever name you used to define the WAS.Next runtime)
  • Check Add Web support and select Web 3.0
  • Check Add bundle to application and use liberty.hello.app for the name
Liberty-blueprint-osgi-bundle-project-web.png

Click Next > twice until the Web Module panel is presented where you specify the Context root of the web application to be hello.

Liberty-blueprint-osgi-bundle-project-web-context-root.png

Click Next >.

Change Version to be 1.0.0.

Liberty-blueprint-osgi-bundle-project-web-bundle-version.png

Click Finish.

The project should appear in the Enterprise Explorer.

Liberty-blueprint-enterprise-explorer-liberty-hello-web.png

liberty.hello.web.HelloServlet - the servlet

Create a new servlet by right-clicking the liberty.hello.web project in the Enterprise Explorer view and selecting New > Servlet.

Use the following to configure the project:

  • Java package: liberty.hello.web
  • Class name: HelloServlet
Liberty-blueprint-new-servlet.png

Click Next > twice.

Uncheck Constructors from superclass and doPost checkboxes (it's merely to minimize the clutter in the servlet as we won't need the constructors and method)

Liberty-blueprint-new-servlet-modifiers.png

Click Finish.

Change the servlet's body so it's as follows.

package liberty.hello.web;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.printf("<h2>%s</h2>", "Hello from Servlet (in WAB)");
    }
 
}

Right-click the servlet and select Run As > Run on Server.

Select the Liberty Profile server and click Finish (you may also want to check Always use this server when running the project to get rid of the panel the next time).

Launching defaultServer (wlp-1.0.1.20121006-0828/websphere-kernel_1.0.1) on Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_13-b20 (en_US)
[AUDIT   ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT   ] CWWKZ0058I: Monitoring dropins for applications. 
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://localhost:9080/hello/*
[AUDIT   ] CWWKZ0001I: Application liberty.hello.app started in 1.700 seconds.
[AUDIT   ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.

You should see a browser tab open with "Hello from Servlet (in WAB)" displayed.

Liberty-blueprint-hello-from-servlet.png

If not, refresh the browser - the browser may have come up faster than the Liberty Profile.

liberty.hello.api - API bundle

Create another OSGi Bundle Project for a service contract (the API).

Specify the project name as liberty.hello.api and add the bundle to the liberty.hello.app application.

Liberty-blueprint-osgi-bundle-project-api.png

Click Next > twice until the Configure OSGi bundle settings panel appears.

Change the Version field to be 1.0.0.

Liberty-blueprint-osgi-bundle-project-api-bundle-version.png

Click Finish.

The project appears in the Enterprise Explorer view.

Liberty-blueprint-enterprise-explorer-liberty-hello-api.png

liberty.hello.api.Hello - the interface

Create a new interface - liberty.hello.api.Hello in the liberty.hello.api project. Right-click it and select New > Interface.

Use the following to configure the project:

  • Package: liberty.hello.api
  • Name: Hello
Liberty-blueprint-new-interface.png

Click Finish.

Change the body of the interface to look as follows:

package liberty.hello.api;
 
public interface Hello {
    String hello();
}

The contract assumes a single method hello that returns a text.

Export the contract

Right-click the liberty.hello.api project and select Plug-in Tools > Open Manifest. In the Manifest editor, switch to the Runtime tab.

Liberty-blueprint-api-manifest-exported-packages.png

Click Add... in the Exported Packages pane and add the only available package liberty.hello.api.

Liberty-blueprint-api-export.png

Save the changes.

The application gets redeployed to the WebSphere Liberty Profile, but since it doesn't change anything from a user's perspective you won't notice the change when you refresh the browser. Give it a try anyway to make sure the application is still of use.

Verification stage 1: liberty.hello.api visibility in servlet

The only bundles (parts of the OSGi application) that can use the exported liberty.hello.api package and hence the liberty.hello.api.Hello interface are the ones that declared dependency on it (in their Import-Package header in META-INF/MANIFEST.MF).

Go to the liberty.hello.web bundle project and open the manifest (right-click the project and select Plug-In Tools > Open Manifest).

In the Dependencies tab, click Add... in the Imported Packages pane. Add the liberty.hello.api package (start typing the package's name and it will eventually be the only one available in the list) .

Liberty-blueprint-servlet-import.png

Save the changes.

Open the servlet's class - liberty.hello.web.HelloServlet - and change it so it looks as follows.

package liberty.hello.web;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import liberty.hello.api.Hello;
 
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.printf("<h2>%s</h2>", "Hello from Servlet (in WAB)");
 
        Hello hello = new Hello() {
 
            @Override
            public String hello() {
                return "Hello from inner class";
            }
        };
        out.printf("<h2>%s</h2>", hello.hello());
    }
 
}

It shows that the liberty.hello.api.Hello interface is only visible to the servlet after we have imported it and therefore we can create or use classes implementing the interface.

Hopefully you haven't closed the browser tab yet and therefore can notice the simplicity of the development environment with the Liberty Profile and Eclipse. Just refresh the browser. You should see the "Hello from inner class" message in the page. Unless you do, right-click the servlet and select Run As > Run on Server.

Liberty-blueprint-hello-from-inner-class.png

liberty.hello.service - Blueprint service bundle

With the API defined and available (the liberty.hello.api project) and the servlet running fine (the liberty.hello.web project), you can now create a OSGi service with the help of OSGi Blueprint, often called a OSGi Blueprint service to explicitly refer to the underlaying specification - the OSGi Blueprint.

Quoting the specification (page 193):

"This specification therefore defines a dependency injection framework, specifically for OSGi bundles, that understands the unique dynamic nature of services. It provides an OSGi bundle programming model with minimal implementation dependencies and virtually no accidental complexity in the Java code."

Let's create the service bundle based upon the OSGi Blueprint.

Create a new OSGi Bundle Project. Use the following to configure the project:

  • Project name: liberty.hello.service
  • Check the Generate blueprint file checkbox
  • Check the Add bundle to application checkbox and select liberty.hello.app as the application

Since the bundle project is supposed to use the OSGi Blueprint Container it therefore needs to instruct the environment about its intent and the Generate blueprint file checkbox does that.

Liberty-blueprint-new-service.png

Click Next > twice until the Configure OSGi bundle settings panel shows up. Use 1.0.0 for the Version.

Liberty-blueprint-osgi-bundle-project-service-bundle-version.png

Click Finish.

The project appears in the Enterprise Explorer view.

Liberty-blueprint-enterprise-explorer-liberty-hello-service.png

Package Import - liberty.hello.api

You will use the liberty.hello.api.Hello interface from the other bundle (the liberty.hello.api bundle project) and as you may have already remembered the only way to access it is to import the package the interface is a part of.

Right-click the liberty.hello.service project and select Plug-in Tools > Open Manifest. Switch to the Dependencies tab and click the Add button in the Imported Packages pane to add the package liberty.hello.api (start typing the package's name until it's the only package to choose).

Liberty-blueprint-service-import.png

Save the changes.

Blueprint Service

With the liberty.hello.api package imported, you can use it in the other bundle project to base a Blueprint service upon it. The package and its contained classes and interfaces are now in the scope of the service bundle.

In the liberty.hello.service project create a new class that implements the interface. Use the following to configure the class:

  • Package: liberty.hello.service
  • Name: HelloOSGiBlueprintWorld
  • Interfaces: liberty.hello.api.Hello (click Add... next to the Interfaces text area and select the interface - don't forget to start typing the name so you can select it easier)
Liberty-blueprint-service-class.png

Click Finish.

Change the class so it's as follows.

package liberty.hello.service;
 
import liberty.hello.api.Hello;
 
public class HelloOSGiBlueprintWorld implements Hello {
 
    @Override
    public String hello() {
        return "Hello from OSGi Blueprint service bundle";
    }
 
}

It's a regular POJO class with no extensions to OSGi. It could be used with any framework, but you will use it with the OSGi Blueprint.

Defining Blueprint Service - HelloOSGiBlueprintWorldBeanService

Right-click the liberty.hello.service project and select OSGi > Open Blueprint File.

In the Design tab, select the Blueprint entry and click Add... in the Overview pane.

Liberty-blueprint-service-blueprint-design.png

Double-click Service (or select the entry and click OK).

Liberty-blueprint-service-blueprint-service.png

In the New Blueprint Service popup window, Browse... to the imported interface - liberty.hello.api.Hello.

Click New... next to the Bean Reference field.

In the New Blueprint Bean popup window, click Browse... to select the just-created POJO class - liberty.hello.service.HelloOSGiBlueprintWorld.

Liberty-blueprint-service-blueprint-service-bean.png

Click OK.

The New Blueprint Service popup window gets the other fields filled out for the Service ID and the Bean Reference.

Liberty-blueprint-service-blueprint-service-complete.png

Click OK.

Save the changes.

The Blueprint editor should ultimately be as follows.

Liberty-blueprint-service-blueprint-design-complete.png

Switch to the Source tab and make sure the Blueprint configuration is as follows.

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  <bean id="HelloOSGiBlueprintWorldBean" class="liberty.hello.service.HelloOSGiBlueprintWorld" />
  <service id="HelloOSGiBlueprintWorldBeanService" ref="HelloOSGiBlueprintWorldBean" 
           interface="liberty.hello.api.Hello" />
</blueprint>

With the configuration whatever bundle is in the runtime environment, it can reference the service via the liberty.hello.api.Hello interface.

Verification stage 2: OSGi Blueprint Service Reference in servlet

The HelloOSGiBlueprintWorldBeanService service is registered in the OSGi Service Registry with the help of the Blueprint Container. To be more precise, the service is registered as one possessing the attribute interface to be liberty.hello.api.Hello. Upon running the service bundle, the container reads the configuration file and registers service(s) defined in the file. Since you defined the service it can now be looked up in the service registry.

There are a few ways to access the service registry, but in this article you will leverage the OSGi Blueprint's approach - to define a service reference in the blueprint file for the other, servlet bundle.

Service Reference

Right-click the liberty.hello.web project and select New > Blueprint File. Click Finish.

In the Design tab, select Blueprint node in the Overview pane and click Add.... Select Reference and click OK.

Use the following to configure the Blueprint Reference:

  • Reference Interface: liberty.hello.api.Hello
  • Reference ID: helloRef
Liberty-blueprint-servlet-blueprint-service-reference.png

Click OK.

The complete Blueprint configuration file should be as follows.

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  <reference id="helloRef" interface="liberty.hello.api.Hello" />
</blueprint>

With the blueprint file, helloRef references any OSGI service that implements the liberty.hello.api.Hello interface. However there's only one such an OSGi service, there might very well ve many such services. Just be aware of it.

Import JNDI package - javax.naming

You are going to use the JNDI API to reference the OSGi service from within the servlet. Before you can use the approach in the servlet bundle you have to declare the dependency on JNDI packages in the OSGi Manifest file.

Right-click the liberty.hello.web project and select Plug-in Tools > Open Manifest. In the Dependencies tab, click Add... button in the Imported Packages pane to import/add javax.naming package.

Liberty-blueprint-servlet-import-javax-naming.png

Save the changes.

Adding feature to Liberty Profile - jndi-1.0

Provided WebSphere Liberty Profile's still up and running, upon saving the Manifest's changes, Eclipse notices a missing feature of the Liberty Profile and asks to add it to the configuration. The jndi-1.0 feature (a subsystem) is required for the proper JNDI naming resolution of applications deployed onto WebSphere Liberty Profile.

Liberty-blueprint-add-jndi-feature-liberty-configuration.png

Click Yes.

[AUDIT   ] CWWKG0017I: The server configuration was successfully updated in 0.8 seconds.
[AUDIT   ] CWWKZ0003I: The application liberty.hello.app updated in 0.51 seconds.
[AUDIT   ] CWWKF0012I: The server installed the following features: [jndi-1.0].
[AUDIT   ] CWWKF0008I: Feature update completed in 0.29 seconds.

The application gets re-deployed.

Servlet changes to use OSGi Blueprint Service

You're now ready to make the necessary changes to the servlet.

Open the liberty.hello.web.HelloServlet servlet and change it so it looks up the service reference helloRef and executes the hello() method. You will use the blueprint:comp namespace to look up the reference.

package liberty.hello.web;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import liberty.hello.api.Hello;
 
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.printf("<h2>%s</h2>", "Hello from Servlet (in WAB)");
 
        Hello hello = new Hello() {
 
            @Override
            public String hello() {
                return "Hello from inner class";
            }
        };
        out.printf("<h2>%s</h2>", hello.hello());
 
        Context context;
        try {
             context = new InitialContext();
             hello = (Hello) context.lookup("blueprint:comp/helloRef");
             out.printf("<h2>%s</h2>", hello.hello());
        } catch (NamingException e) {
             e.printStackTrace();
        }
    }
 
}

Run the servlet. Hopefully you haven't closed the browser tab in the meantime so a simple refresh of the browser shows the changes.

Liberty-blueprint-hello-from-osgi-blueprint-service-bundle.png

It therefore concludes the article. You have just developed a modular, service-based OSGi Application using the OSGi Blueprint Container in WebSphere Liberty Profile. Congratulations!

Questions? Suggestions? Ideas? You're kindly welcome to send me an email to jacek@japila.pl. Thanks!

Osobiste
Przestrzenie nazw

Warianty
Działania
Nawigacja
Narzędzia