In this tutorial we will take a look at the development of a simple OSGi Web Application and what tools can save us some time.

The Maven Bundle Plugin makes our life much easier here as does the OSGi Bundle Repository that offers some nice bundles – in our case the servlet API and an embedded Jetty web server.

So lets develop some bundles ..

Prerequisites

You are going to need a JDK (>=5), Maven2, the Apache Felix OSGi implementation and and text editor/http://eclipse.org/[IDE] of your choice.

Install everything and continue to step 2 :)

Information Broker Bundle

  • The first bundle we are going to create just exports a service class that can be used from other bundles

  • Create a new Maven Project with mvn archetype:generate mvn archetype:create or your IDE e.g. Eclipse with the Maven Plugin

  • Include the dependency to the Felix OSGi implementation to your pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
         <modelVersion>4.0.0</modelVersion>
         <groupId>com.hascode.bundle</groupId>
         <artifactId>information-broker-bundle</artifactId>
         <version>0.0.1-SNAPSHOT</version>
         <name>Information Broker Service Bundle</name>
         <packaging>bundle</packaging>
         <dependencies>
             <dependency>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>org.osgi.core</artifactId>
                 <version>1.0.0</version>
             </dependency>
         </dependencies>
    </project>
  • Create two packages – one for the export com.hascode.bundle.information_broker.api – and (optional) another for your implementation com.hascode.bundle.information_broker.impl

  • Add the Maven Bundle Plugin to your pom.xml and define the export + private packages and the activator class

    <build>
     <plugins>
     <plugin>
     <groupId>org.apache.felix</groupId>
     <artifactId>maven-bundle-plugin</artifactId>
     <extensions>true</extensions>
     <configuration>
     <instructions>
     <Export-Package>com.hascode.bundle.information_broker.api</Export-Package>
     <Private-Package>com.hascode.bundle.information_broker.*</Private-Package>
     <Bundle-Activator>com.hascode.bundle.information_broker.impl.Activator</Bundle-Activator>
     </instructions>
     </configuration>
     </plugin>
     </plugins>
    </build>
  • Create a new interface for the exported service -  InformationBroker

    package com.hascode.bundle.information_broker.api;
    
    public interface InformationBroker {
     public abstract String getInformation();
    }
  • Create an implementation to the interface – InformationBrokerImpl

    package com.hascode.bundle.information_broker.impl;
    
    import com.hascode.bundle.information_broker.api.InformationBroker;
    
    public class InformationBrokerImpl implements InformationBroker {
    
     public String getInformation() {
     return "Visit www.hascode.com!";
     }
    }
  • Create the defined activator class Activator

    package com.hascode.bundle.information_broker.impl;
    
    import java.util.Properties;
    
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    
    import com.hascode.bundle.information_broker.api.InformationBroker;
    
    public class Activator implements BundleActivator {
     public void start(BundleContext ctx) throws Exception {
     ctx.registerService(InformationBroker.class.getName(),
     new InformationBrokerImpl(), new Properties());
     }
    
     public void stop(BundleContext ctx) throws Exception {
     }
    }
  • Create the bundle with mvn package

  • If you take a look into the Manifest.mf in the generated bundle named information-broker-bundle-0.0.1-SNAPSHOT.jar it could look like this

    Manifest-Version: 1.0
    Export-Package: com.hascode.bundle.information_broker.api
    Built-By: mk
    Tool: Bnd-0.0.357
    Bundle-Name: Information Broker Service Bundle
    Created-By: Apache Maven Bundle Plugin
    Bundle-Version: 0.0.1.SNAPSHOT
    Build-Jdk: 1.6.0_20
    Bnd-LastModified: 1279985826087
    Bundle-ManifestVersion: 2
    Bundle-Activator: com.hascode.bundle.information_broker.impl.Activator
    Import-Package: com.hascode.bundle.information_broker.api,org.osgi.framework;version
     ="1.3"
    Bundle-SymbolicName: com.hascode.bundle.information_broker.information-broker-bundle
  • Now lets install the bundle – in your felix directory run java -jar bin/felix.jar, install the bundle using felix:install file, list the bundles with lb and start the bundle with start <ID>

    _______________
    Welcome to Apache Felix Gogo
    
    g! felix:install file:/var/project/information-broker-bundle/target/information-broker-bundle-0.0.1-SNAPSHOT.jar
    Bundle ID: 6
    g! lb
    START LEVEL 1
     ID|State      |Level|Name
     0|Active     |    0|System Bundle (3.0.1)
     1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
     2|Active     |    1|Apache Felix Gogo Command (0.6.0)
     3|Active     |    1|Apache Felix Gogo Runtime (0.6.0)
     4|Active     |    1|Apache Felix Gogo Shell (0.6.0)
     6|Installed  |    1|Information Broker Service Bundle (0.0.1.SNAPSHOT)
    g! start 6
    g! lb
    START LEVEL 1
     ID|State      |Level|Name
     0|Active     |    0|System Bundle (3.0.1)
     1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
     2|Active     |    1|Apache Felix Gogo Command (0.6.0)
     3|Active     |    1|Apache Felix Gogo Runtime (0.6.0)
     4|Active     |    1|Apache Felix Gogo Shell (0.6.0)
     6|Active     |    1|Information Broker Service Bundle (0.0.1.SNAPSHOT)
    g!
  • Install the bundle using mvn install

Adding the Servlet API and a Bundled Web Server

  • For this task we are going to use the OSGi Bundle Repository – just start the Felix console again and type obr:list to get a list of available bundles

    g! obr:list
    Apache Felix Bundle Repository (1.4.3, ...)
    Apache Felix Configuration Admin Service (1.0.4, ...)
    Apache Felix Declarative Services (1.4.0, ...)
    Apache Felix EventAdmin (1.0.0)
    Apache Felix File Install (2.0.8, ...)
    Apache Felix Gogo Shell Commands (0.2.0)
    Apache Felix Gogo Shell Console (0.2.0)
    Apache Felix Gogo Shell Launcher (0.2.0)
    Apache Felix Gogo Shell Runtime (0.2.0)
    Apache Felix Http Api (2.0.4)
    Apache Felix Http Base (2.0.4)
    Apache Felix Http Bridge (2.0.4)
    Apache Felix Http Bundle (2.0.4)
    Apache Felix Http Jetty (2.0.4, ...)
    Apache Felix Http Proxy (2.0.4)
    Apache Felix Http Samples - Filter (2.0.4)
    Apache Felix Http Samples - Whiteboard (2.0.4)
    Apache Felix Http Whiteboard (2.0.4)
    Apache Felix iPOJO (1.6.2, ...)
    Apache Felix iPOJO (0.8.0)
    Apache Felix iPOJO API (1.6.0, ...)
    Apache Felix iPOJO Arch Command (1.6.0, ...)
    Apache Felix iPOJO Composite (1.6.0, ...)
    [..]
  • Now install the API and the Jetty server using obr:deploy

    g! obr:deploy "Apache Felix Http Api"
    Target resource(s):
    -------------------
       Apache Felix Http Api (2.0.4)
    
    Required resource(s):
    ---------------------
       Apache Felix Http Bundle (2.0.4)
    
    Optional resource(s):
    ---------------------
       Apache Felix iPOJO (1.6.2)
    
    Deploying...done.
    g! obr:deploy "Apache Felix Http Api"
    Target resource(s):
    -------------------
       Apache Felix Http Api (2.0.4)
    
    Required resource(s):
    ---------------------
       Apache Felix Http Bundle (2.0.4)
    
    Optional resource(s):
    ---------------------
       Apache Felix iPOJO (1.6.2)
    
    Deploying...done.
    g! obr:deploy "Apache Felix Http Jetty"
    Target resource(s):
    -------------------
       Apache Felix Http Jetty (2.0.4)
    
    Deploying...done.
  • Now start the new installed bundles

    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.0.1)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.6.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.6.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.6.0)
        6|Active     |    1|Information Broker Service Bundle (0.0.1.SNAPSHOT)
        7|Installed  |    1|Apache Felix Http Bundle (2.0.4)
        8|Installed  |    1|Apache Felix Http Api (2.0.4)
        9|Installed  |    1|Apache Felix iPOJO (1.6.2)
       10|Installed  |    1|Apache Felix Http Jetty (2.0.4)
    g! start 7
    [INFO] Started bridged http service
    g! start 8
    g! start 9
    g! start 10
    g! [INFO] Started jetty 6.1.x at port 8080

Servlet Bundle using the Information Broker

Now we are going to create a new bundle that includes a servlet to display information from the information broker bundle so

  • Create a new maven project

  • Add the dependencies to the http-bridge, the felix-framework and our information-broker-bundle to your pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.hascode.bundle</groupId>
      <artifactId>information-broker-servlet-bundle</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <name>Information Broker Servlet Bundle</name>
    	<packaging>bundle</packaging>
    
    	<dependencies>
        <dependency>
          <groupId>org.apache.felix</groupId>
          <artifactId>org.osgi.core</artifactId>
          <version>1.0.0</version>
          <type>bundle</type>
        </dependency>
        <dependency>
        	<groupId>org.apache.felix</groupId>
        	<artifactId>org.apache.felix.framework</artifactId>
        	<version>3.0.1</version>
        	<type>bundle</type>
        </dependency>
        <dependency>
        	<groupId>com.hascode.bundle</groupId>
        	<artifactId>information-broker-bundle</artifactId>
        	<version>0.0.1-SNAPSHOT</version>
        	<type>bundle</type>
        </dependency>
        <dependency>
        	<groupId>org.apache.felix</groupId>
        	<artifactId>org.apache.felix.http.bridge</artifactId>
        	<version>2.0.4</version>
        	<type>bundle</type>
        </dependency>
        <dependency>
        	<groupId>org.apache.felix</groupId>
        	<artifactId>javax.servlet</artifactId>
        	<version>1.0.0</version>
        	<type>bundle</type>
        </dependency>
    	</dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
              <instructions>
                <Bundle-Activator>com.hascode.bundle.information_broker_servlet.impl.Activator</Bundle-Activator>
              </instructions>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
  • Create the servlet that receives information from the information-broker-bundleInfoBrokerServlet

    package com.hascode.bundle.information_broker_servlet.impl;
    
    import java.io.IOException;
    
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.osgi.util.tracker.ServiceTracker;
    import com.hascode.bundle.information_broker.api.InformationBroker;
    
    public class InfoBrokerServlet extends HttpServlet {
        private static final long serialVersionUID = 1110490906466282279L;
        private ServiceTracker serviceTracker;
    
        public InfoBrokerServlet(ServiceTracker serviceTracker) {
            this.serviceTracker = serviceTracker;
        }
        protected void doGet(HttpServletRequest req, HttpServletResponse res) {
            try {
                res.getOutputStream().println("<html><body>");
                InformationBroker broker = (InformationBroker) serviceTracker.getService();
                if (broker != null) {
                    res.getOutputStream().println(broker.getInformation());
                }
                res.getOutputStream().println("</body></html>");
            } catch (IOException e) {
            }
        }
    }
  • Create the bundle activator that registers the servlet – Activator

    package com.hascode.bundle.information_broker_servlet.impl;
    
    import javax.servlet.ServletException;
    
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.ServiceReference;
    import org.osgi.service.http.HttpService;
    import org.osgi.service.http.NamespaceException;
    import org.osgi.util.tracker.ServiceTracker;
    
    import com.hascode.bundle.information_broker.api.InformationBroker;
    
    public class Activator implements BundleActivator {
        private ServiceTracker infoSrvTracker;
    
        private ServiceTracker httpSrvTracker;
    
        public void start(BundleContext ctx) throws Exception {
            infoSrvTracker = new ServiceTracker(
                                                ctx,
                                                InformationBroker.class.getName(),
                                                null);
            httpSrvTracker = new ServiceTracker(ctx, HttpService.class.getName(),
                                                null) {
                public Object addingService(ServiceReference reference) {
                    HttpService httpService = (HttpService) super.addingService(reference);
                    try {
                        httpService.registerServlet(
                                                    "/",
                                                    new InfoBrokerServlet(
                                                                          infoSrvTracker),
                                                    null, null);
                    } catch (ServletException e) {
                    } catch (NamespaceException e) {
                    }
                    return httpService;
                }
    
                public void removedService(ServiceReference reference,
                        Object service) {
                    ((HttpService) service).unregister("/");
                    super.removedService(reference, service);
                }
            };
    
            infoSrvTracker.open();
            httpSrvTracker.open();
        }
    
        public void stop(BundleContext ctx) throws Exception {
            infoSrvTracker.close();
            httpSrvTracker.close();
        }
    }

Install and Run

  • Now enter the Felix console again, install and start the bundles

    $> java -jar bin/felix.jar
    g! install file:/var/project/information-broker-bundle/target/information-broker-bundle-0.0.1-SNAPSHOT.jar
    Bundle ID: 13
    g! install file:/var/project/information-broker-servlet-bundle/target/information-broker-servlet-bundle-0.0.1-SNAPSHOT.jar
    Bundle ID: 14
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.0.1)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.6.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.6.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.6.0)
        7|Active     |    1|Apache Felix Http Bundle (2.0.4)
        8|Active     |    1|Apache Felix Http Api (2.0.4)
        9|Active     |    1|Apache Felix iPOJO (1.6.2)
       10|Active     |    1|Apache Felix Http Jetty (2.0.4)
       13|Installed  |    1|Information Broker Service Bundle (0.0.1.SNAPSHOT)
       14|Installed  |    1|Information Broker Servlet Bundle (0.0.1.SNAPSHOT)
    g! start 13
    g! start 14
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.0.1)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.6.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.6.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.6.0)
        7|Active     |    1|Apache Felix Http Bundle (2.0.4)
        8|Active     |    1|Apache Felix Http Api (2.0.4)
        9|Active     |    1|Apache Felix iPOJO (1.6.2)
       10|Active     |    1|Apache Felix Http Jetty (2.0.4)
       13|Active     |    1|Information Broker Service Bundle (0.0.1.SNAPSHOT)
       14|Active     |    1|Information Broker Servlet Bundle (0.0.1.SNAPSHOT
  • Now open your browser, go to http://localhost:8080 and enjoy the advertisement ;)

Tutorial Sources

Please feel free to download the tutorial sources from my GitHub repository, fork it there or clone it using Git:

git clone https://bitbucket.org/hascode/osgi-felix-webapp-tutorial.git

If you’re interested in OSGi dependency wiring using OSGi blueprints, please feel free to have a look at the following article of mine: “Wiring made easy using OSGi Blueprint and Apache Karaf“.

Article Updates

  • 2017-09-25: Link to sources/repository added.

  • 2015-03-03: Table of contents added, link to other articles added.