corner imagecorner image
IDEPlatformPluginsDocs & SupportCommunityPartners

OSGi Declarative Services Using Maven

This document demonstrates how the integrated support for the Open Services Gateway Initiative (OSGi) framework in NetBeans IDE 6.9 simplifies the process of creating OSGi bundles and using the bundles in your projects. In this tutorial you will first create a simple OSGi bundle from the Maven OSGI bundle archetype and then deploy the bundle to the Felix OSGi container that is included with the IDE.

After you create the basic OSGi bundle, you will implement OSGi declarative services in the bundle and use the Apache Felix Maven SCR plugin to build the bundle. You then deploy the bundle to the GlassFish Server Open Source Edition 3.0.1 and the Felix container starts the services provided by the bundle. After you deploy the bundle you will create a simple Java EE web client that accesses the services.

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.

This tutorial is based on the TOTD #124 OSGi Declarative Services blog post and other blog entries which can be found on Arun Gupta's blog. Be sure to visit the blog and see many other excellent entries on working with OSGi.

Tutorial Exercises

Content on this page applies to NetBeans IDE 6.9

To follow this tutorial, you need the following software and resources.

Software or Resource Version Required
NetBeans IDE 6.9, Java version
Java Development Kit (JDK) version 6
GlassFish Server Open Source Edition 3.0.1
Maven 2.09 or higher

Note. The GlassFish server requires Java Development Kit (JDK) 6.

Prerequisites

This document assumes you have some basic knowledge of, or programming experience with, the following technologies:

  • Java Programming
  • NetBeans IDE
  • Maven framework

Before starting this tutorial you may want to familiarize yourself with the following documentation.

Creating the OSGi Bundle Project

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 Bundle

In this exercise you will use the New Project wizard to create an OSGi bundle project.

  1. Choose File > New Project to open the New Project wizard.
  2. Choose Maven OSGi Bundle from Maven category. Click Next.
    screenshot of New Project wizard
  3. Type MavenHelloService for the Project Name. Click Finish.
  4. Open the project's Properties window and confirm that the Source/Binary Format is set to 1.6 and that the Encoding is UTF-8 in the Sources category.

When you create an OSGi bundle project using the Maven OSGi Bundle archetype, the IDE automatically adds org.osgi.core-1.4.0.jar as a dependency. If you look at pom.xml, you can see that the packaging element specifies bundle.

<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>MavenHelloService</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>MavenHelloService OSGi Bundle</name>

The POM also specifies that the maven-bundle-plugin will be used when building the bundle.

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.0.1</version>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>

Adding a Bundle Activator

In this exercise you will use a wizard to create a Java class named Installer that implements the org.osgi.framework.BundleActivator interface. A bundle activator is used to manage the lifecycle of a bundle. The bundle activator class is 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.

  1. Right-click the bundle project in the Projects window and choose New > Other.
  2. Choose Bundle Activator in the OSGi category. Click Next.
  3. Type Installer for the Class Name and choose com.mycompany.mavenhelloservice as the Package. Click Finish.
    screenshot of New Bundle Activator wizard
  4. Open Installer.java in the editor and modify the start() and stop() methods to add the following lines.
    package com.mycompany.mavenhelloservice;
    
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    
    /**
     *
     * @author nb
     */
    public class Installer implements BundleActivator {
    
        public void start(BundleContext context) throws Exception {
            String userName = context.getProperty("user.name");
            System.out.println("Maven Hello Service: Started OSGi bundle");
            System.out.println("User Name: " + userName);
        }
    
        public void stop(BundleContext context) throws Exception {
            System.out.println("Maven Hello Service: Stopped OSGi bundle");
        }
    
    }
  5. Save your changes.

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 that the IDE added the <Bundle-Activator> element to the configuration for the maven-bundle-plugin.

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <version>2.0.1</version>
    <extensions>true</extensions>
      <configuration>
            <instructions>
                  <Bundle-Activator>com.mycompany.mavenhelloservice.Installer</Bundle-Activator>
            </instructions>
      </configuration>
</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.

Building and Checking the Bundle

In this exercise you will build the OSGi bundle. You can then check to see that the bundle is working correctly by deploying the bundle to the embedded Apache Felix OSGi container. Apache Felix is included with the IDE, but you can register other OSGi containers such as Eclipse Equinox.

  1. Right-click the project and choose Build.

    When you click Build, the IDE builds and installs the snapshot JAR in the local repository.

  2. Click Run and you will see the following in the Output window.
    Welcome to Felix
    ================
    
    Maven Hello Service: Started OSGi bundle
    User Name: nb

Now that you have created a basic OSGi bundle with a bundle activator you can start adding some functionality. Later in this tutorial you will modify this bundle to make it a service that implements an interface, but first you will create the interface.

Creating the Interface Bundle

In this section you will create a new OSGi bundle that will provide an interface that will be implemented by other bundles. The interface is a simple class with a sayHello method. After you create the bundle and class, you will make the bundle accessible to other bundles by modifying the POM so that the appropriate manifest header is generated when you build the bundle.

Creating the API Bundle

In this exercise you create the bundle and interface.

  1. Open the New Project wizard and select Maven OSGi Bundle from the Maven category. Click Next.
  2. Type MavenHelloServiceAPI as the Project Name. Click Finish.
  3. Right-click the Source Packages node of the MavenHelloServiceAPI project and choose New > Java Interface.
  4. Type HelloService as the Class Name.
  5. Select com.mycompany.mavenhelloserviceapi as the Package. Click Finish.
  6. Modify the interface to add the following code and save your changes.
    public interface HelloService {
    
        public String sayHello(String name);
    
    }

Specifying the Packages to Export

In this exercise you will open the project's Properties window and select the packages that you want to be accessible to other bundles and projects. By default, classes in a bundle are not visible to other bundles. If you want some classes in a bundle to be accessible, the packages you want to export need to be declared in the MANIFEST.MF. Other bundles can then import the exposed packages.

  1. Right-click the project node and choose Properties.
  2. Select the Export Packages category and then select the com.mycompany.mavenhelloserviceapi package. Click OK.
    screenshot of Export Packages in the Properties window

    When you select the export packages in the Properties window, the IDE modifies the POM to specify the export package.

    <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.0.1</version>
        <extensions>true</extensions>
        <configuration>
            <instructions>
                <Export-Package>com.mycompany.mavenhelloserviceapi</Export-Package>
                <Private-Package>com.mycompany.mavenhelloserviceapi.*</Private-Package>
            </instructions>
        </configuration>
    </plugin>
  3. Right-click the project node and choose Build.

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 that are specified in the POM.

Manifest-Version: 1.0
Export-Package: com.mycompany.mavenhelloserviceapi
Bundle-Version: 1.0.0.SNAPSHOT
Build-Jdk: 1.6.0_17
Built-By: nb
Tool: Bnd-0.0.357
Bnd-LastModified: 1274279178454
Bundle-Name: MavenHelloServiceApi OSGi Bundle
Bundle-ManifestVersion: 2
Created-By: Apache Maven Bundle Plugin
Import-Package: com.mycompany.mavenhelloserviceapi
Bundle-SymbolicName: com.mycompany.MavenHelloServiceApi

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.

Deploying the OSGi Bundle to the GlassFish Server

In this exercise you will deploy the interface bundle to the GlassFish server where it can be accessed by other bundles or applications. To deploy a bundle to the GlassFish server you only need to copy the bundle to the appropriate directory on the server and the Felix container will automatically activate and register the bundle.

In this exercise you will deploy the OSGi bundles to the GlassFish server from the command line because the IDE does not have a UI for doing this. There are different ways to deploy bundles and in this example we will use the asadmin deploy command. An alternative is to simply copy the JAR to the domains/domain1/autodeploy/bundles directory of your GlassFish server installation.

For additional examples and details of deploying OSGi bundles to the GlassFish server, see Arun Gupta's TOTD #118: Managing OSGi bundles in GlassFish v3 - asadmin, filesystem, telnet console, web browser, REST, osgish. You could also created your own watched directory using the Apache Felix File Install agent as described in Sahoo's blog post Using filesystem operations to manage OSGi bundles in GlassFish.

  1. Start the GlassFish server from the Services window. Alternatively, you can start the server from the command line.
  2. Open a command line terminal.
  3. From the command line, navigate to the target directory that contains MavenHelloServiceApi-1.0-SNAPSHOT.jar.
  4. Type the following in the terminal.
    <glassfish-install>/glassfish/bin/asadmin deploy --type osgi MavenHelloServiceApi-1.0-SNAPSHOT.jar
    

    Where <glassfish-install> is the location of your GlassFish server installation. You will see something similar to the following in the terminal window:

    Authentication failed with password from login store: /Users/nb/.asadminpass
    Enter admin password for user "admin">
    
    Application deployed successfully with name MavenHelloServiceApi-1.0-SNAPSHOT.
    Command deploy executed successfully.

    Note. Hit the Enter key when you are prompted for the password (the default admin password is "null").

You will see something similar to the following in the Output window of the IDE.

INFO: MavenHelloServiceApi-1.0-SNAPSHOT was successfully deployed in 372 milliseconds.

In the terminal you can view the deployed applications and bundles by typing the following:

<glassfish-install>/glassfish/bin/asadmin list-applications
Authentication failed with password from login store: /Users/nb/.asadminpass
Enter admin password for user "admin">
MavenHelloServiceApi-1.0-SNAPSHOT

The bundle is now deployed and accessible to other bundles. The next section will demonstrate how to create a service that implements the API bundle.

Making the OSGi Bundle a Service

This section shows how to modify the MavenHelloService bundle to add the Maven SCR Plugin so that the bundle provides a service that implements the API bundle. To do this you will modify the MavenHelloService project to add some annotations to the code to declare the services and the annotations will be processed and the configuration files will be generated during compilation by the plugin. The declaration of services in configuration files in OSGi bundles is enabled by the Declarative Services Specification.

For more about the plugin and the Declarative Services Specification, see Apache Felix Maven SCR Plugin.

Adding Support for SCR Annotations

In this exercise you will add a dependency on the org.apache.felix.scr.annotations library to enable the use of annotations for Components and Services in your code. The Maven SCR Plugin will process the annotations to generate the XML configuration files when you build the bundle.

  1. Expand the MavenHelloService project in the Projects window.
  2. Right-click the Dependencies node and choose Add Dependency.
  3. Type org.apache.felix for the GroupId, org.apache.felix.scr.annotations for the ArtifactId and 1.3.0 for the Version. Click OK.

    Alternatively, you can enter search terms in the window (for example, "scr.annotations") and search the Maven repositories.

screenshot of Add Dependency dialog

The IDE modifies the POM to declare the dependency and displays the dependency under the Libraries node in the Projects window.

Creating an Implementation of the Service Interface

In this exercise you will create a simple implementation class in the bundle and add annotations to declare the service.

  1. Right-click Source Packages and choose New > Java Class. Click Next.
  2. Type HelloImpl as the Class Name.
  3. Type com.mycompany.mavenhelloservice.impl as the Package. Click Finish.
  4. Implement the HelloService interface and then implement the abstract methods.
  5. Modify the sayHello method to return the string name.
    public class HelloImpl implements HelloService {
        public String sayHello(String name) {
            return "Hello " + name;
        }
    }
  6. Add the @Service and @Component annotations.
    package com.mycompany.mavenhelloservice.impl;
    
    import com.mycompany.mavenhelloservice.api.HelloService;
    import org.apache.felix.scr.annotations.Component;
    import org.apache.felix.scr.annotations.Service;
    
    /**
     *
     * @author nb
     */
    @Component(name="hello-service")
    @Service
    public class HelloImpl implements HelloService {
    
        public String sayHello(String name) {
            return "Hello " + name;
        }
    
    }

    Notice that the name attribute of the @Component annotation is used to specify the name of the service.

  7. Fix the imports to import the org.apache.felix.scr.annotations.Component and org.apache.felix.scr.annotations.Service libraries.

Adding the Felix Maven SCR Plugin to the POM

In this exercise you will edit the POM to add the maven-scr-plugin as a build plugin and add instructions so that the plugin will generate the XML configuration file.

  1. Expand the Project Files node and open pom.xml in the editor.
  2. Modify the POM to add maven-scr-plugin as a build plugin.
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-scr-plugin</artifactId>
                <executions>
                       <execution>
                            <id>generate-scr-scrdescriptor</id>
                            <goals>
                                <goal>scr</goal>
                            </goals>
                       </execution>
                </executions>
            </plugin>

For details on the behavior of the plugin, see the Apache Felix Maven SCR Plugin page.

Building the and Deploying the Bundle

In this exercise you will build the bundle and examine the contents of the bundle JAR.

  1. Right-click the bundle project and choose Build.

    When you choose Build, the IDE creates the JAR in the target directory of the project and copies the JAR to the local repository. You will see output similar to the following in the Output window.

    Installing com/mycompany/MavenHelloService/1.0-SNAPSHOT/MavenHelloService-1.0-SNAPSHOT.jar
    Writing OBR metadata
    ------------------------------------------------------------------------
    BUILD SUCCESSFUL
    ------------------------------------------------------------------------
    Total time: 5 seconds
    Finished at: Fri May 07 16:34:41 CEST 2010
    Final Memory: 23M/79M
    ------------------------------------------------------------------------
    

    You can expand the JAR created in the target directory to see that MANIFEST.MF was created in the META-INF directory and that serviceComponents.xml was created in the OSGI-INF directory. If you open MANIFEST.MF you can see the following manifest header details.

    Manifest-Version: 1.0
    Service-Component: OSGI-INF/serviceComponents.xml
    Export-Package: com.mycompany.mavenhelloservice;uses:="com.mycompany.m
     avenhelloserviceapi,org.osgi.framework"
    Built-By: nb
    Tool: Bnd-0.0.357
    Bundle-Name: MavenHelloService OSGi Bundle
    Created-By: Apache Maven Bundle Plugin
    Build-Jdk: 1.6.0_17
    Bundle-Version: 1.0.0.SNAPSHOT
    Bnd-LastModified: 1274279195883
    Bundle-ManifestVersion: 2
    Bundle-Activator: com.mycompany.mavenhelloservice.Installer
    Bundle-SymbolicName: com.mycompany.MavenHelloService
    Import-Package: com.mycompany.mavenhelloservice,com.mycompany.mavenhel
     loserviceapi,org.osgi.framework;version="1.5"
    
    

    You can see that the maven-bundle-plugin generated a manifest header in the MANIFEST.MF file to declare Bundle Activator class as specified in the POM. The file also specifies the location of the serviceComponents.xml descriptor file where the services are declared

    The maven-scr-plugin handles the generation of the serviceComponents.xml descriptor file. If you open serviceComponents.xml, you can see that file declares the name, implementation class and interface of the named services.

    <components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
        <scr:component enabled="true" name="hello-service">
            <implementation class="com.mycompany.mavenhelloservice.HelloImpl"/>
            <service servicefactory="false">
                <provide interface="com.mycompany.mavenhelloserviceapi.HelloService"/>
            </service>
            <property name="service.pid" value="hello-service"/>
        </scr:component>
    </components>
  2. From the command line, navigate to the target directory that contains MavenHelloService-1.0-SNAPSHOT.jar.
  3. Deploy the bundle by typing the following in the terminal.
    <glassfish-install>/glassfish/bin/asadmin deploy --type osgi MavenHelloService-1.0-SNAPSHOT.jar
                

This time you will see something similar to the following in the Output window of the IDE when you deploy the bundle.

INFO: Maven Hello Service: Started OSGi bundle
INFO: User Name: nb
INFO: MavenHelloService-1.0-SNAPSHOT was successfully deployed in 372 milliseconds.
        

From the message "Maven Hello Service: Started OSGi bundle" you can see that the Installer bundle activator class was instantiated when the bundle was deployed.

Now that the bundle is deployed you can consume the service from other bundles and applications. The next section will demonstrate how to access the service from a web client.

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 the web application and then inject the declared services.

Creating the Web Project

In this exercise you create a web application project and add dependencies on the MavenHelloService bundle.

  1. Choose File > New Project and select Maven Web Application from the Maven category. Click Next.
  2. Type MavenHelloWebClient for the Project Name. Click Finish.
  3. Open the project's Properties window and set the Server to GlassFish Server 3 in the Run category.
  4. Type /HelloClient as the Relative URL. Click OK.
  5. Right-click the project node and choose New > Servlet.
  6. Type HelloClient for the Class Name and select the com.mycompany.mavenhellowebclient package from the dropdown list. Click Finish.
  7. Right-click the Dependencies node and choose Add Dependency.
  8. Type helloservice in the Query text field to search the local repository.
  9. Select the MavenHelloServiceAPI Snapshot bundle in the group com.mycompany. Click OK.

    Alternatively, if the bundle project is open in the IDE you can click the Open Projects tab in the Add Dependency dialog and select the project from the list.

  10. Open the POM and add a <scope> element to the dependency declaration for MavenHelloServiceAPI and specify that the dependency is provided.
    <dependency>
          <groupId>${project.groupId}</groupId>
          <artifactId>MavenHelloServiceAPI</artifactId>
          <version>${project.version}</version>
          <scope>provided</scope>
    </dependency>

By specifying the scope as provided, the MavenHelloServiceAPI bundle will not be included in the generated WAR archive. It is not necessary to include the bundle because in the previous section you deployed the bundle to the server.

Injecting the Services

In this exercise you inject the HelloService resource into the servlet and then modify the servlet to invoke the service to print a string to the web page.

  1. Inject the service resources using annotations.
    @WebServlet(name="HelloClient", urlPatterns={"/HelloClient"})
    public class HelloClient extends HttpServlet {
    
       @Resource(mappedName="hello-service")
       HelloService helloService;
  2. Modify the processRequest method to add println to call the sayHello method in the services
    out.println("<h1>Servlet HelloClient at " + request.getContextPath () + "</h1>");
    
    out.println(helloService.sayHello("Duke"));
    
    out.println("</body>");
    out.println("</html>");
  3. Fix your imports and save your changes.

Building and Running the Application

You can now build and run the web application.

  1. Right-click the web application project and choose Run.

When you choose Run, the IDE builds the application, deploys the WAR archive to the server and opens the browser to the HelloClient page.

screenshot of browser window showing servlet

If you look at the project in the Files window, you can see that the target directory contains the MavenHelloWebClient.war archive. If you expand the WAR, you can see that the archive does not contain the MavenHelloServiceAPI JAR.

Deploying and Undeploying an OSGi Bundle

This tutorial demonstrated how to use the deploy command in the terminal to deploy a bundle to the GlassFish server. This section describes how to undeploy an OSGi bundle on the GlassFish server using the undeploy command and also how you can deploy OSGi bundles by copying the bundles to the server and and undeploy bundles by deleting them.

Using the undeploy Command

When you ran the deploy command you used the type parameter to specify OSGi. When you ran the command, the OSGi bundle was copied to the <GLASSFISH-INSTALL>/glassfish/domains/domain1/applications directory in the GlassFish server. To undeploy a bundle, for example MavenHelloService-1.0-SNAPSHOT.jar, you can type the following in the terminal.

<glassfish-install>/glassfish/bin/asadmin undeploy MavenHelloService-1.0-SNAPSHOT

Deploying By Copying OSGi Bundles

By default, any OSGi bundles that are copied into the autodeploy/bundles directory of the GlassFish server are automatically deployed. For example, you can use the copy command (e.g., cp) to copy an OSGi bundle JAR to the <GLASSFISH-INSTALL>/glassfish/domains/domain1/autodeploy/bundles directory.

cp /Users/nb/Documents/nbproject/MyOSGiBundle/target/MyOSGiBundle-1.0-SNAPSHOT.jar modules/autostart

When you copy the JAR to the directory you will see output similar to the following in the Output window.

INFO: Installed /Applications/NetBeans/glassfishv3/glassfish/modules/autostart/MyOSGiBundle-1.0-SNAPSHOT.jar
INFO: Started bundle: file:/Applications/NetBeans/glassfishv3/glassfish/modules/autostart/MyOSGiBundle-1.0-SNAPSHOT.jar

If you look in the autostart directory you can see that the directory now contains the JAR.

You can use the remove command (e.g. rm) to delete the JAR from the autostartdirectory. When you remove the JAR you will see output similar to the following in the Output window.

INFO: Uninstalled /Applications/NetBeans/glassfishv3/glassfish/domains/domain1/autodeploy/bundles/MavenHelloService-1.0-SNAPSHOT.jar

References and Further Reading

The following documents may be helpful and can provide you with further information about some of the concepts presented in this tutorial.



See Also

For more information about using NetBeans IDE and Maven to develop OSGi bundles, see the following resources:

To send comments and suggestions, get support, and keep informed on the latest developments on the NetBeans IDE Java EE development features, join the nbj2ee mailing list.