Using CDI to Inject OSGi Bundles as Services in NetBeans IDE

This document demonstrates how the integrated support for the Open Services Gateway Initiative (OSGi) framework
in NetBeans IDE simplifies the process of creating OSGi bundles and using the bundles in your projects.
In this tutorial you will create two simple OSGi bundles from the Maven OSGi bundle archetype and
then deploy the bundles to the GlassFish Server Open Source Edition 3.1.

After you create the basic OSGi bundles, you will create a web client application and use CDI to inject the bundles as a service.
You will then deploy the web application as a bundle to the server.
The tutorial will then demonstrate how to use the OSGi Admin Console to work with OSGi bundles.

Using an OSGi bundle in an Enterprise Application can provide greater modularity and flexibility
with respect to updating individual bundles.
The out-of-the-box support for OSGi in the GlassFish server makes incorporating bundles into your application very easy.

Creating the Parent POM Project

In this section you will create a parent POM project for the OSGi bundles that you will create in this tutorial.
You will edit the project POM (pom.xml) to add Dependency Management elements
that will be inherited as dependencies by the child projects.

Choose New Project (Ctrl-Shift-N; ⌘-Shift-N on Mac) from the main menu.

Select POM Project from the Maven category.

Type MavenOSGiCDIProject as the Project name. Click Finish.

When you click Finish, the IDE creates the POM project and opens the project in the Projects window.

Expand the Project Files node in the Projects window and double-click pom.xml to open the file in the editor.

In this exercise you specified explicitly an artifact and artifact version that will be used in the project.
By using Dependency Management and specifying the artifacts in the parent POM,
you can make the POMs in the child projects simpler and ensure that the
versions of dependencies are consistent in the project.

Creating the OSGi Bundle Projects

The Maven category in the New Projects wizard includes an OSGi Bundle archetype for creating OSGi bundle projects.
When you create an OSGi bundle project, the generated POM declares
the org.osgi.core JAR as a dependency and specifies the maven-bundle-plugin for building the project.

Creating the MavenHelloServiceApi Interface Bundle

In this exercise you will use the New Project wizard to create an OSGi bundle project that will provide a simple interface that will be
implemented by other bundles.
After you create the bundle and interface, you will modify the POM to update the dependency
on the org.osgi.core artifact that you specified in the parent POM project.

Choose File > New Project to open the New Project wizard.

Choose OSGi Bundle from Maven category. Click Next.

Type MavenHelloServiceApi for the Project Name.

Click Browse and select the MavenOSGiCDIProject POM project as the Location. Click Finish.

When you click Finish, the IDE creates the bundle project and opens the
project in the Projects window.
If you open pom.xml for the MavenHelloServiceApi project in the editor you can see that the packaging element specifies bundle
and that the maven-bundle-plugin will be used when building the bundle.

Add the following sayHello method to the interface (in bold) and save your changes.

public interface Hello {
String sayHello(String name);
}

Right-click the project node in the Projects window and choose Build.

After you build the project, if you open the Files window and expand the project node you can see that MavenHelloServiceApi-1.0-SNAPSHOT.jar
is created in the target folder.

The maven-bundle-plugin handles the generation of the MANIFEST.MF file when you build the project.
If you open the MANIFEST.MF file in the compiled JAR you will see that the
plugin generated a manifest header that declares the export packages.
For OSGi, all bundles that you want to be exposed and available to other bundles must be listed in the Export-Package element
in MANIFEST.MF.

Confirm that the MANIFEST.MF contains the Export-Package element
(the element shown in bold in the example below).

The OSGi container will read the Export-Package manifest header to determine the classes in the bundle that
can be accessed from outside the bundle.
In this example, the classes in the com.mycompany.mavenhelloserviceapi package are exposed.

Note. If the MANIFEST.MF does not contain the Export-Package element,
you will need to enable the default plugin behavior for the plugin in the Project Properties window and rebuild the project.
In the Project Properties window, select the Export Packages category and select the Default maven-bundle-plugin behavior option.
You can use the Export Packages panel of the Project Properties window to explicitly specify the packages that should be exposed or
specify the packages directly in pom.xml.

Creating the MavenHelloServiceImpl Implementation Bundle

In this exercise you will create the MavenHelloServiceImpl in the POM project.

Choose File > New Project to open the New Project wizard.

Choose OSGi Bundle from the Maven category. Click Next.

Type MavenHelloServiceImpl for the Project Name.

Click Browse and select the MavenOSGiCDIProject POM project as the Location (if not selected). Click Finish.

Right-click the project node in the Projects window and choose Properties.

Select the Sources category in the Project Properties dialog box.

Set the Source/Binary Format
to 1.6 and confirm that the Encoding is UTF-8. Click OK.

When you implement Hello, the IDE will display an error that you need
to resolve by adding the MavenHelloServiceApi project as a dependency.

Right-click the Dependencies node of MavenHelloServiceImpl in the Projects window
and choose Add Dependency.

Click the Open Projects tab in the Add Library dialog.

Select MavenHelloServiceApi OSGi Bundle. Click Add.

Right-click in the HelloImpl.java class that is open in the editor and choose Fix Imports (Alt-Shift-I; ⌘-Shift-I on Mac) to add an import statement for com.mycompany.mavenhelloserviceapi.Hello. Save your changes.

Expand the com.mycompany.mavenhelloserviceimpl package and double-click
Activator.java to open the file in the editor.

The IDE automatically created the Activator.java bundle activator class in your project.
A bundle activator is used to manage the lifecycle of a bundle.
The bundle activator class is declared in the MANIFEST.MF of the bundle and
instantiated when the bundle is started by the container.

An OSGi bundle does not require a bundle activator class, but you can use the
start() method in the activator class,
for example, to initialize services or other resources that are required by the bundle.
In this exercise you will add some lines of code to the class that will print messages to the Output window.
This will make it easier for you to identify when the bundle starts and stops.

Modify the start() and stop() methods in the bundle activator class to add the following lines (in bold).

You can see that the bundle activator class imports org.osgi.framework.BundleActivator and
org.osgi.framework.BundleContext. By default the generated class contains two methods: start() and stop().
The OSGi framework invokes the start() and stop() methods to start and to stop the
functionality provided by the bundle. When the bundle is started, the service component provided by the bundle is
registered in the OSGi service registry.
After a bundle is registered, other bundles can use the registry to look up and then use the active services via
the bundle context.

If you look at the POM for the project you can see the <Bundle-Activator>
element that specifies the bundle activator under the configuration element for the maven-bundle-plugin.

When you build the bundle, the plugin will generate a Manifest Header in the bundle's manifest file in the JAR
and specify the Bundle Activator class.
The OSGi runtime looks for the Bundle-Activator header in the manifest file when a bundle is deployed.

Expand the Dependencies node and confirm that the org.osgi.core artifact is listed as a dependency.

Note. Remove any older versions of the artifact that are listed under
the Dependencies node by right-clicking the artifact and choosing Remove Dependency.
The only dependencies should be the MavenHelloServiceApi project and the
org.osgi.core artifact.

Building and Deploying the OSGi Bundles

In this exercise you will build the OSGi bundles and deploy the bundles to GlassFish.

Right-click the MavenOSGiCDIProject node in the Projects window and choose Clean and Build.

When you build the project the IDE will create the JAR files in the
target folder of each of the projects and also install the snapshot JAR in the local repository.
In the Files window, you can expand the target folder for each of the two bundle projects
to see the two JAR archives (MavenHelloServiceApi-1.0-SNAPSHOT.jar and MavenHelloServiceImpl-1.0-SNAPSHOT.jar).

Start the GlassFish server if not already started.

Copy the MavenHelloServiceApi-1.0-SNAPSHOT.jar
to the glassfish/domains/domain1/autodeploy/bundles/ directory of your
GlassFish installation.

You should see output similar to the following in the GlassFish Server log in the Output window.

Creating a Web Client Application

This section demonstrates how to create a Java EE web client that accesses the service provided by the OSGi bundle.
You will create a simple servlet in a web application and then inject the declared services.
Before you create the project you will add some dependency management elements to the parent POM project.

Configuring Dependencies in Parent POM Project

In this exercise you will specify dependency elements in the parent POM project.
You will also add a repository for artifacts that will be used by the project.

Expand the Project Files node of the MavenOSGiCDIProject project
in the Projects window and double-click pom.xml to open the file in the editor.

After you add the GlassFish repository to the POM, if you view the list of repositories
under the Maven Repositories node in the Services window you will see that the IDE automatically added
a node for the GlassFish repository.
By default, the IDE displays a node for the Local Maven repository.
When an open project specifies a repository, the IDE automatically adds a node for the
repository under the Maven Repositories node.

In this exercise you added additional artifacts and artifact versions that will be used in the project.
You also added the GlassFish repository that contains the osgi-cdi-api artifacts.

Creating the MavenHelloWebClient Web Application

You will first create a regular web application and then modify the project to make it an
OSGi bundle (Web Application bundle (WAB)).

Note. You will need to build the web application manually if the web application
is not built automatically when you build the MavenOSGiCDIProject project .

In the Files window, expand the project node for the web application and confirm that
the archive MavenHelloWebClient-1.0-SNAPSHOT.war was created in the target directory.
If you expand the WAR archive of the web client and examine the MANIFEST.MF,
you will see that the manifest contains lines similar to the following.

Building the Web Application as an OSGi Bundle

To use @OSGiService and retrieve registered OSGi bundles,
you need to make the web application a bundle which can access BundleContext.
To make the WAR an OSGi bundle (Web Application Bundle),
you add the Web-ContextPath meta-data to the MANIFEST.MF in the WAR.
To do this, specify the <Web-ContextPath> element in the instructions
for the maven-bundle-plugin and the manifest generated by the plugin will contain the element.
You then modify the maven-war-plugin configuration
to instruct the plugin to add the manifest that was generated by the
maven-bundle-plugin to the WAR archive.

In the Projects window, expand the Project Files node under MavenHelloWebClient and
double-click pom.xml to open the file in the editor.

Right-click the MavenHelloWebClient project node in the Projects window and choose Clean and Build.

If you now expand the WAR archive and open MANIFEST.MF in the editor,
you can see that MANIFEST.MF now contains additional information,
including the Web-ContextPath: /mavenhellowebclient entry
that you specified in the maven-bundle-plugin configuration
and bundle name entries.

Installing and Using the OSGi Admin Console

You can use the GlassFish OSGi Admin Console to install, start and stop OSGi bundles that are deployed to the server.
In this exercise you will enable the GlassFish OSGi Admin Console and then view the list of registered OSGi bundles.

Perform the following steps to install the required GlassFish add-ons to enable the OSGi Console
and view the deployed bundles in the GlassFish Domain Admin Console.

Important: If you are running GlassFish Server 3.1.2.2
you need to modify the osgi.properties file located in the
GLASSFISH-INSTALL/glassfish/config/ directory and set the value of the
org.osgi.framework.startlevel.beginning property to "2"
(org.osgi.framework.startlevel.beginning=2).
See the following forum post for more details:
Cannot start web console in Glassfish version 3.1.2.2.

Open the Admin Console again and click server (Admin Server) in the left navigation column.

Click the OSGi Console tab to view a list of the deployed OSGi bundles.

Note. You might be prompted to enter the username and password to
view the list of OSGi bundles. Confirm that the authorization dialog is not hidden if you do not see a list
of bundles in the OSGi Console tab. The default username for the GlassFish 4 server is admin
if you installed the server when you installed the IDE. The password is empty by default.

You can scroll down the list to view the status of registered OSGi bundles and start and stop individual bundles.
If you sort the list by Id (highest to lowest), you will see that the three bundles that you have deployed are displayed near the top of the list.