Category Archives: maven

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

Making a Java windows service in 10 minutes

This blog post describes how to create a windows service from a Java application, it is a slightly more fleshed out version of the JavaZone 2016 lightning talk “A Java windows service in 10 minutes”.

A problem sometimes encountered by a Java programmer, is to make your Java program into a Windows Service. This is may be a bump in your project, particularly if you don’t know anything about windows services, or much about windows for that matter.

The demo created a running, working, Windows service server using 14 lines of Java code, and some maven configuration.

Before starting on the demo, a few words on what windows services are (from a GNU/linux/UNIX perspective):

  • Windows services are the “daemons” of the windows world
  • Windows services are normally started when the windows system starts, and stopped when the windows system shuts down
  • Windows services can be stopped and started by administrator users, both using a GUI and using command line commands
  • Windows services can be configured to run with a particular user, restricting what the service can do (default is the local user “Local System”)

To create the installer the demo use a maven plugin called maven-windows-service-installer-plugin. The maven plugin in turn relies on izpack for the installer and uses the apache commons daemon to execute the Java program.

The Java program turned into a windows service during the demo, is the Wiser test SMTP server. Wiser was picked, because:

  1. It has an appropriate API
  2. An SMTP service is easy to demonstrate, and it is something other than yet another HTTP service

Since the demo might be hard to follow (a lot of information in 10 minutes), this blog post describes all steps of the demo (note: the complete code can be found on github at https://github.com/sbang/ansmtpserver ).

Required prior knowledge:

  • Java programming
  • Apache maven

Required software to retrace the demo:

  • Apache maven (any maven 2 or 3 will do)
  • A Java SDK (I’m using the newest Java 1.8, but any Java SDK 1.7 will probably do)
  • An eclipse IDE (I’m using Eclipse Neon, but any recent eclipse will probably do)
  • A telnet command line application (since this is for windows, just use Windows cygwin bash with the inetutils package, just run the installer and include inetutils)

To retrace the demo, do the following operations:

  1. Start eclipse and open the Workspace “C:\workspace”
  2. Right click the package explorer and select New->Other…
  3. In the “New” dialog box:
    1. Select Maven->Maven Project
    2. Click the “Next>” button
    3. Checkmark the checkbox “Create a simple project (skip archetype selection)” at the to of the dialogbox
    4. Click the “Next>” button
    5. In the “Group id” text box, type
      ansmtpserver
    6. In the “Artifact id” text box, type
      ansmtpserver
    7. Click the “Finish” button
  4. Open the “ansmtpserver” project and double click “pom.xml” to open it
  5. In the pom.xml editor (title “ansmtpserver/pom.xml”):
    1. Select the Dependencies tab
    2. Click the “Add…” button
    3. In the “Select Dependency” dialog box:
      1. In the field “Enter groupId, artifactId or sha1 prefix or pattern (*)”, type
        windows-installer
      2. Select “com.alexkasko.installer windows-service-installer-common”
      3. Click the “OK” button
    4. Click the “Add…” button
    5. In the “Select Dependency” dialog box:
      1. In the field “Enter groupId, artifactId or sha1 prefix or pattern (*)”, type
        subethamail
      2. Select “org.subethamail subethasmtp”
      3. Click the “OK” button
    6. Click the “Add…” button
    7. In the “Select Dependency” dialog box:
      1. In the field “Enter groupId, artifactId or sha1 prefix or pattern (*)”, type
        slf4j-simple
      2. Select “org.slf4j slf4j-simple”
      3. Click the “OK” button
    8. Save the pom.xml file
  6. Right-click ansmtpserver->src/main/java in the “Package Explorer” and select New->Package
  7. In the “New Java Package” dialog box:
    1. Let the “Name” field have its default (“ansmtpserver”)
    2. Click the “Finish” button
  8. Right-click the ansmtpserver->src/java/main->ansmtpserver package in the “Package Explorer” and select New->Class
  9. In the “New Java Class Dialog”
    1. In the “Name” field, type
      AnSmtpServer
    2. In “Interfaces”, click the “Add…” button
    3. In the “Implemented Interfaces Selection” dialog box:
      1. In “Choose interfaces”, type
        dae
      2. In “Matching items”, select “DaemonLauncher – com.alexkasko.installer”
      3. Click the “OK” button
    4. Click the “Finish” button
  10. Modify the generated AnSmtpServer.java file in the following way
    package ansmtpserver;
    
    import org.subethamail.wiser.Wiser;
    
    import com.alexkasko.installer.DaemonLauncher;
    
    public class AnSmtpServer implements DaemonLauncher {
    
    	private Wiser server;
    
    	public AnSmtpServer() {
    		super();
    		server = new Wiser();
    		server.setHostname("javazone");
    		server.setPort(2200);
    	}
    
    	public void startDaemon() {
    		server.start();
    	}
    
    	public void stopDaemon() {
    		server.stop();
    	}
    
    }
    1. Add a Wiser field
    2. In the constructor, create an Wiser instance, set the host name, and the port number
    3. In the startDaemon() method start the Wiser server
    4. In the stopDaemon() method stop the Wiser server
  11. Save the modified AnSmtpServer.java file
  12. Right-click ansmtpserver->src/main/resources in the “Package Explorer” and select New->File
  13. In the “New File” dialog box
    1. In “File name”, type
      simplelogger.properties
    2. Click the “Finish” button
  14. Modify the “simplelogger.properties” file to have the following content
    org.slf4j.simpleLogger.defaultLogLevel=debug

    and save the file

  15. Select the “ansmtpserver/pom.xml” editor, and select the “pom.xml” tab, and paste the following before the </project> end tag. This configuration will be the same for all installers with the exception of the <prunsrvDaemonLauncherClass> tag
     <build>
      <plugins>
       <plugin>
        <groupId>com.alexkasko.installer</groupId>
        <artifactId>maven-windows-service-installer-plugin</artifactId>
        <version>1.0.6</version>
        <dependencies>
         <dependency>
          <groupId>com.alexkasko.installer</groupId>
          <artifactId>windows-service-installer-common</artifactId>
          <version>1.0.6</version>
         </dependency>
        </dependencies>
        <configuration>
         <prunsrvDaemonLauncherClass></prunsrvDaemonLauncherClass>
         <use64BitJre>true</use64BitJre>
        </configuration>
        <executions>
         <execution>
          <id>build-installer</id>
          <phase>package</phase>
          <goals>
           <goal>installer</goal>
          </goals>
         </execution>
        </executions>
       </plugin>
      </plugins>
     </build>
  16. Open ansmtpserver->src/main/java->ansmtpserver->AnSmtpServer.java in the “Package Explorer”, right-click the “AnSmtpServer” class, and select “Copy Qualified Name” and paste the name into the <prunsrvDaemonLauncherClass> element
  17. Save the pom.xml file
  18. Open a cmd.exe window, and type the following commands to build the installer
    cd c:\windows\ansmtpserver
    mvn clean install
  19. Open a windows explorer on C:\Windows\ansmtpserver\target
  20. Right click the ansmtpserver-0.0.1-SNAPSHOT-installer.zip file and select “Extract all…” to the folder “C:\workspace\ansmtpserver\target”
  21. Open the folder “C:\workspace\ansmtpserver\target\ansmtpserver-0.0.1-SNAPSHOT-installer”, right-click the “install.exe” file and select “Run as administrator”
  22. Open a “Cygwin 64 terminal” window and type the following command
    telnet localhost 2022

    The expected response is

    Trying 127.0.0.1...
    telnet: Unable to connect to remote host: Connection refused

    since nothing is listening to port 2200

  23. Click the installer all the way to the end, using defaults for everything
  24. Open the windows services window and there will be a new windows service “ansmtpservice” shown as “Running”Windows services with the ansmtpserver shown
  25. Try the “telnet localhost 2200” command again, and this time there will be a response, and it will be possible to talk SMTP over the connectiontelnet_session
  26. Stop the “ansmtpservice” service and the telnet connection will be disconnected

Thus ends the installer part.

Some simple improvements to this installer are possible:

  • Better descrption for the service in “Windows Services”
    • Just add the following to the <configuration> setting of the maven-windows-service-installer-plugin:
      <prunsrvServiceName>AnSmtpServer</prunsrvServiceName>
      <prunsrvDisplayName>An SMTP server</prunsrvDisplayName>
      <prunsrvDescription>This service responds to incoming STMP connections on port 2200.</prunsrvDescription>
  • Install the service under “C:\Programs and Files”
    • Just add the following to the <configuration> setting of the maven-windows-service-installer-plugin:
      <izpackDefaultInstallDir>$APPLICATIONS_DEFAULT_ROOT\ansmtpserver</izpackDefaultInstallDir>
  • Attach the zip file containing the installer to the maven artifact, so that the installer can be deployed to a maven repository, where other maven files can download and unpack the installer from (easy distribution)
    • Add the following inside <build><plugins></plugins></build> of the pom.xml build
         <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>build-helper-maven-plugin</artifactId>
          <version>1.10</version>
          <executions>
           <execution>
            <id>attach-artifacts</id>
            <phase>package</phase>
            <goals>
             <goal>attach-artifact</goal>
            </goals>
            <configuration>
             <artifacts>
              <artifact>
               <file>target/${project.artifactId}-${project.version}-installer.zip</file>
               <type>zip</type>
               <classifier>installer</classifier>
              </artifact>
             </artifacts>
            </configuration>
           </execution>
          </executions>
         </plugin>
        </plugins>
      

A windows-service-installer that contains the above improvements and more, is this installer for Apache Jena Fuseki.