Tag Archives: karaf

Use Jersey to provide REST APIs from karaf applications

The sample application https://github.com/steinarb/jersey-demo demonstrates how to use Jersey to provide a REST API from a Declarative Services (DS) component registering with the Pax Web Whiteboard Extender in apache karaf.

The way Jersey works is that it initially scans a package in the classpath for classes with JAX-RS annotations (e.g. @Path, @GET, @POST), and matches @Path annotations to possible endpoints in the REST API. When Jersey receives a REST call to a endpoint that matches a resource, Jersey will instanciate the appropriate resource class, call a method on the instanciated resource and then release the resource to Java garbage collection.

To be able to do something useful in these resource objects we use HK2 to dependency inject OSGi services.

To be able to dependency inject OSGi services into Jersey resources the following is done:

  1. Create a whiteboard DS component exposing a Servlet service from Jersey ServletContainer, configuring the package to scan for API resources:
    @Component(
        service=Servlet.class,
        property={"alias=/jerseyinkaraf/api",
                  HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX+ServerProperties.PROVIDER_PACKAGES+"=no.priv.bang.demos.jerseyinkaraf.webapi.resources"
        } )
    public class CounterServiceServlet extends ServletContainer {
        ...
    }
  2. Make the DS component of ServletContainer depend on OSGi services Counter and LogService
    public class CounterServiceServlet extends ServletContainer {
        ...
        @Reference
        public void setCounter(Counter counter) {
            this.counter = counter;
        }
    
        @Reference
        public void setLogservice(LogService logservice) {
            this.logservice.setLogService(logservice);
        }
        ...
    }
  3. Override the ServletContainer.init(WebConfig) method, and:
    1. Call super.init(WebConfig) to make sure that a ServletConfig containing the information set up by the http whiteboard is created (contains the servletcontext, the servlet name and the package to scan for Jersey resources)
              super.init(webConfig);
    2. Copy the ResourceConfig of the ServletContainer (because that ServletConfig is immutable after the setup, and calling ServletConfig.register() will cause an IllegalOperationException)
              ResourceConfig copyOfExistingConfig = new ResourceConfig(getConfiguration());
    3. On the ServletConfig copy, register an anonymous inner inheriting AbstractBinder that in its configure() method registers the OSGi services injected into the ServletContainer as JSR330 injections in the Jersey resources
              copyOfExistingConfig.register(new AbstractBinder() {
                      @Override
                      protected void configure() {
                          bind(logservice).to(LogService.class);
                          bind(counter).to(Counter.class);
                      }
                  });
    4. Call ServletContainer.reload(ResourceConfig) with the ResourceConfig copy as the argument
              reload(copyOfExistingConfig);

      Note: The copyOfExistingConfig object at this point contains both the initial configuration created by the ServletContainer itself, and the two added OSGi services for dependency injection.

  4. In the resources use JSR330 injections of the registered services
    @Path("/counter")
    @Produces(MediaType.APPLICATION_JSON)
    public class CounterResource {
    
        @Inject
        Counter counter;
    
        @GET
        public Count currentValue() {
            return counter.currentValue();
        }
    
        @POST
        public Count increment() {
            return counter.increment();
        }
    
    }

To try out the application:

  1. Clone this project and build it:
    git clone https://github.com/steinarb/jersey-demo.git
    cd jersey-demo
    mvn clean install
    
  2. Install apache karaf and start it  according to the karaf quick start guide (alternatively, see Develop OSGi applications using karaf)
  3. At the karaf command line give the following commands
    feature:repo-add mvn:no.priv.bang.demos.jerseyinkaraf/jerseyinkaraf/LATEST/xml/features
    feature:install jerseyinkaraf.webapi
    feature:install jerseyinkaraf.webgui
  4. Open http://localhost:8181/jerseyinkaraf in a web browser and click on the button to increment the counter value

The demo consists of the following maven project and modules:

  1. jerseyinkaraf The top project which in addition to containing common configuration, and the list of modules, also creates a karaf feature repository containing the features of all bundles created in the modules, and attaches the karaf feature repository to the maven artifact
  2. jerseyinkaraf.servicedef which is an OSGi bundle containing the interfaces and bean defining the OSGi service for doing the counting
  3. jerseinkaraf.services which is an OSGi bundle containing a DS component implementing the services
  4. jerseyinkaraf.webapi which is an OSGi bundle containing a DS component that defines a REST API that plugs into the Web Whiteboard Extender and exposes the OSGi services
  5. jerseyinkaraf.webgui which is an OSGi bundle containing a DS component that exposes an HTML and JavaScript application that plugs into the Web Whiteboard Extender

Deliver react.js from apache karaf

There’s a small barebones demo application/testbed that delivers a single-page web application, created with react.js from apache karaf, at https://github.com/steinarb/frontend-karaf-demo

Screenshot of the demo open on the “counter” page

The react.js application is webpack‘d into a single bundle.js file. The packing is done by the frontend-maven-plugin (i.e. no local node.js installation required).

The bundle.js and its wrapping index.xhtml page, are served as static resources from the OSGi bundle’s classpath by a DS component that registers a Servlet service with the web whiteboard extender on the path /frontend-karaf-demo

The react.js features featured in this application, are:

  • react.js to render the application’s page
  • redux to hold the application’s state
  • redux-saga and axios for REST API communication and asynchronous update of the application’s state (the REST service used by axios, is provided by an OSGi DS whiteboard Servlet)
  • react-router to route between different pages (however this requires hardcoding the ReactServlet’s path into the react app, and requires the ReactServlet to return the top level index.html from all routes)
  • react-bootstrap and bootstrap v3 to style the application in a responsive way (I haven’t made any effort to make it look good. I just include the boostrap style and activate the responsive formatting in a meta header tag in the index.html page)

To try out the application:

  1. Clone this project and build it:
    git clone https://github.com/steinarb/frontend-karaf-demo.git
    cd frontend-karaf-demo/
    mvn clean install
  2. Install apache karaf and start it  according to the karaf quick start guide (alternatively, see Develop OSGi applications using karaf)
  3. At the karaf command line give the following commands
    feature:repo-add mvn:no.priv.bang.demos/frontend-karaf-demo/LATEST/xml/features
    feature:install frontend-karaf-demo
  4. Open http://localhost:8181/frontend-karaf-demo in a web browser and try it out

Develop OSGi applications using karaf

Apache Karaf is a good platform for deploying OSGi based applications. Karaf is also a good platform for testing and debugging these applications. This article describes how to test and debug OSGi bundles and OSGi applications with karaf and eclipse.

The basic flow of development, is:

  1. Build the application with maven
  2. Start karaf as your own user in a way that makes it listen for remote debug connections
  3. Install the application from the karaf console
  4. Connect eclipse to karaf for a remote debug session
  5. Make karaf listen to updates to bundles with SNAPSHOT versions, and automatically load the updated bundles
  6. Make a change in eclipse
  7. Run a maven build of the project
  8. Observe that the change appears in karaf or in the debugger

For more detail, read on.

Preparations

Do the following:

  1. Install eclipse
    1. Open a web browser on https://www.eclipse.org/downloads/ and download the installer for your system
    2. Run the installer to the end, using defaults for everything
  2. Install apache maven
    1. On debian GNU/linux, just do
      apt-get install maven
  3. Download and unpack the binary karaf distribution. In bash on GNU/linux (or in git bash on Windows), do:
    mkdir -p ~/karaf
    cd ~/karaf/
    wget http://apache.uib.no/karaf/4.1.4/apache-karaf-4.1.4.tar.gz
    tar --strip-components=1 -xf apache-karaf-4.1.4.tar.gz

Clone and build the sample application

  1. Clone and build the sample application
    mkdir -p ~/workspaces/ws01
    cd ~/workspaces/ws01/
    git clone https://github.com/steinarb/hello-karaf-demo.git
    cd ~/workspaces/ws01/hello-karaf-demo/
    mvn clean install
  2. Import the sample application into eclipse:
    1. Start eclipse
    2. Open the workspace at ~/workspaces/ws01
    3. Import the existing maven project hello-karaf-demo into the workspace (File->Import… then select Maven->Existing Maven Projects and click the wizard through to the end)

Install the application into karaf

  1. Open a command line window and start karaf with an argument that makes karaf listen for remote debug connections
    cd ~/karaf/
    bin/karaf debug
  2. From the karaf console prompt:
    1. Install the run-time requirements for the test application
      feature:repo-add mvn:no.priv.bang.osgi.service.adapters/service-adapters-karaf/1.0.0/xml/features
      feature:install adapter-for-osgi-logservice
      feature:install pax-http-whiteboard
    2. Install the sample application with the following commands
      bundle:install mvn:no.priv.bang.demos/hello-karaf-demo/1.0.0-SNAPSHOT
      bundle:start mvn:no.priv.bang.demos/hello-karaf-demo/1.0.0-SNAPSHOT
  3. Open a web browser on the following URL http://localhost:8181/hello

Debug into the application running in karaf

  1. Set up a remote debug connection in karaf
    1. Open the menu Run->Debug Configurations…
    2. In the debug configurations dialog:
      1. Select “Remote Java Application”
      2. Click the “New launch configuration”
      3. In the Name field, write
        Remote karaf debug
      4. In the Port field, write
        5005
      5. Select the “Source” tab
      6. Click the button “Add…”
      7. In the “Add Source” dialog:
        1. Select “Java Project”
        2. Click the button “OK”
        3. In the “Project Selection” dialog
          1. Click the checkbox of “hello-karaf-demo”
          2. Click the button “OK”
      8. Click the button “Debug”
  2. Set a breakpoint in the code
    1. Open the HelloServlet.java file (press Ctrl-Shift-t to open the “Open Type” dialog, type HelloServlet and select the HelloServlet class)
    2. Go to line 60 (press Ctrl-l, then type 60, and press Enter), i.e. this line
                  response.setStatus(200);
    3. Press Ctrl-Shift-b to set a breakpoint on line 61
  3. Reload the web page in the web browser
  4. Observe that the debugger stops at the breakpoint
  5. Press F8 to make the code continue to run

Make a modification in the code, picked up by karaf

    1. In the karaf console, give the following command to make karaf listen in the local repository for new versions of bundles with SNAPSHOT version
      bundle:watch *
    2. Modify the code in eclipse
      1. In the HelloServlet.java file, change
            private static final String TITLE = "Hello world!";
            private static final String PARAGRAPH = "This is sent via PAX Web Whiteboard Extender.";
        

        to

            private static final String TITLE = "Hello karaf world!";
            private static final String PARAGRAPH = "Powered by Apache Karaf.";
        
      2. Save the HelloServlet.java file
    3. Build the project with maven
      1. In eclipse, select the menu Run->Run Configurations…
      2. In the dialog Run Configurations:
        1. Select “Maven Build” in the list on the left
        2. Click the “New launch configuration” icon (top left in the dialog)
        3. In the “Name:” field, type:
          mvn install hello-karaf-demo
        4. In the “Base directory” field, type:
          ${project_loc:hello-karaf-demo}
        5. In the “Goals” field, type:
          install
        6. Click the button “Run”
    4. Reload the web page in the web browser and observe that the change now is present

Installing with a karaf feature

In the installation example earlier in this article the runtime requirements of the sample application were first installed into karaf (pax-http-whiteboard and adapter-for-osgi-logservice).

It is possible to install this example application in a way that also pulls in the dependencies:

  1. The first thing to do, is to remove the existing installation in karaf:
    1. Stop karaf
      logout
    2. Remove the “data” subdirectory
      rm -rf data
    3. Start karaf
      bin/karaf debug
  2. Removing the data directory removes all state in karaf, and karaf is back to a fresh installation, this can be verfied by:
    1. listing the bundles in the karaf console
      bundle:list
    2. Verifying that http://localhost:8181/hello results in a 404 Not Found
  3. The first thing to do, is to add the feature repository for the hello world application. The feature repository is an XML file containing one or more “karaf features”. A karaf feature can be a list of bundles to load, and it can also contain references to other features.  The feature file for the hello world application is attached to the maven bundle artifact and can be installed with the following command:
    feature:repo-add mvn:no.priv.bang.demos/hello-karaf-demo/1.0.0-SNAPSHOT/xml/features

    Note: This is the same karaf commando as the first command of the dependencies install. The pax-http-whiteboard feature is built-in to karaf and doesn’t require a feature repository install

  4. Now the feature for the hello world application can be installed
    feature:install hello-karaf
  5. Verify that the feature install has pulled in dependencies
    bundle:list
  6. Verify that the application is running on http://localhost:8181/hello

Some things to try on your own:

  1. Remove the data directory again and try installing the bundle without the dependencies and see what happens
  2. Start karaf watching for bundle modifications in the local maven repository
  3. List bundles on different levels with the bundle:list command with the threshold argument (hint: all karaf commands take the “–help” argument)
  4. Try launching the “mvn install” for the bundle using eclipse hotkeys after modifying the java file and observe that karaf loads the rebuilt module

Installing apache karaf on debian

Until the RFP (Request For Packaging) bug for karaf in the debian bug tracker is resolved, here is an APT archive with a karaf package for debian (architecture “all”).  The package is created using native debian packaging tools, and built from a source tarball and the APT archive itself is created, using aptly.

The package has been tested on Debian 9 “stretch” (the current stable), amd64.

Do the following commands as root on a debian GNU/linux system:

  1. Add the key for the APT archive
    wget -O - https://apt.bang.priv.no/apt_pub.gpg | apt-key add -
  2. Open the /etc/apt/sources.list file in a text editor, and add the following lines:
    # APT archive for apache karaf
    deb http://apt.bang.priv.no/public stable main
  3. Install karaf with apt-get
    apt-get update
    apt-get install openjdk-8-jdk karaf
  4. Log in with SSH (password is “karaf” (without the quotes)) and try giving some commands:
    ssh -p 8101 karaf@localhost

 

Packaging karaf with native debian packaging tools

Note! This is an improvement over the packaging in  Installing apache karaf on debian stretch, this package is packaged using native debian packaging tools instead of fpm, and is built from the karaf source tarball instead of the karaf binary tarball.

Apache karaf is an OSGi container and application server that is provisioned from maven, and has an ssh server. Basically it is possible to start an empty karaf, ssh in and give some commands to install an application using maven.

There still isn’t a native .deb package on maven (see  the RFP (Request For Packaging) bug for karaf in the debian bug tracker), but this package can be installed from my own maven repository.

The packacing projecct can be found on github: https://github.com/steinarb/karaf-debian

Procedure to build the package

  1. Install the required build tools
    apt-get update
    apt-get install openjdk-sdk git maven-debian-helper devscripts
  2. Clone the karaf package repository
    mkdir -p ~/git
    cd ~/git/
    git clone https://github.com/steinarb/karaf-debian.git
  3. Build the package
    cd ~/git/karaf-debian/
    dpkg-buildpackage

After this, there will be a karaf-*.deb package in the directory above the karaf-debian directory.

Installing apache karaf on debian stretch

Edit: It is now possible to install karaf on debian without building it yourself, the package installed is not the one described here, but the new and improved package built from source with native debian packaging tools, that can be found here  https://github.com/steinarb/karaf-debian

Apache karaf is an OSGi container/application server with some nice properties:

  1. It has an SSH server you can log into and a command line where you can inspect and configure the karaf instance
  2. It can be provisioned using apache maven, basically you can start with an empty karaf, ssh into the SSH server and pull in and start your application using “maven magic”
  3. It is much simpler to get an OSGi application up and running in apache karaf, than in any other system I have tried, since I first was to introduced to OSGi in 2006
  4. Karaf can also be used to run non-OSGi applications packaged as jar or war files
  5. In a development setting is very simple to deploy new versions of the code using maven and remote debug the deployed code frome eclipse or IntelliJ

Running karaf on a debian GNU/linux system is a little hampered by there not being a native .deb package. I have opened an RFP (Request For Packaging) bug for karaf in the debian bug tracker. When/if that issue is ever resolved as done, karaf will be easily availabel on debian and also on all of the distros that are based on debian (e.g. ubuntu and mint).

Until then do my own debian packaging. I forked the packaging I found at https://github.com/DemisR/karaf-deb-packaging and made some changes:

  1. Switched from oracle JDK 8, to openjdk 8
  2. Updated to karaf version 4.0.7 (the currently newest stable release at the time of forking), later upgraded to karaf 4.1.1 and again upgraded to karaf 4.1.2
  3. Use /var/lib/karaf/data instead of /usr/local/karaf/data
  4. Use package version “-1” instead of “-3”
  5. Switched from using the the service wrapper (karaf-wrapper) to plain systemd start using the scripts and config from bin/contrib in the karaf distribution
  6. Made the stop of running services more robust

The resulting .deb package will follow the usual service pattern of a debian service: the service will run with a user named after the service (i.e. user “karaf” which is the single member of group “karaf” and the owner of all files the service need to touch). The service will log to the regular debian syslog. The configuration will end up in /etc/karaf and all files not part of the installation will be left untouched on a .deb package uninstall and upgrade.

My fork of the packaging, lives at https://github.com/steinarb/karaf-deb-packaging

To create the package and install karaf, do the following steps:

  1. Log in as root on a debian system
  2. Install the prequisites for building the package, debian packages and ruby gem:
    apt-get update
    apt-get install git maven openjdk-8-jdk postgresql ruby ruby-dev build-essential
    gem install fpm
  3. Clone the packaging project and build the deb package:
    cd /tmp
    git clone https://github.com/steinarb/karaf-deb-packaging
    cd karaf-deb-packaging
    ./dist_karaf.sh
    mkdir -p /root/debs
    cp *.deb /root/debs
  4. Install the .deb package:
    dpkg --install karaf_4.1.4-1_all.deb

After karaf has been installed it is possible to log in as user “karaf”, with the following command

ssh -p 8101 karaf@localhost

The password is also “karaf” (without the quotes).

This opens the karaf console command line

        __ __                  ____
       / //_/____ __________ _/ __/
      / ,<  / __ `/ ___/ __ `/ /_
     / /| |/ /_/ / /  / /_/ / __/
    /_/ |_|\__,_/_/   \__,_/_/

  Apache Karaf (4.1.4)

Hit '<tab>' for a list of available commands
and '[cmd] --help' for help on a specific command.
Hit 'system:shutdown' to shutdown Karaf.
Hit '<ctrl-d>' or type 'logout' to disconnect shell from current session.

karaf@root()>

At this command line, you can eg.

  1. install an application
  2. start, stop and list running applications
  3. set the configuration used by the applications

But all of these except for the first, will be items for later posts.