Developers, Developers, Developers! Maksim Sorokin IT Blog

19Jul/11Off

Maven + Apache Felix: Easy Development and Debugging With Eclipse

This is a first post on in series about Maven + Apache Felix + CXF + DOSGi. Here we will combine Maven, Apache Felix and Eclipse. You have to use M2Eclipse plugin for this (or similar Maven-Eclipse integration plugin).

The problem:

  • Integrating Felix with Eclipse tutorial requires manual download and configuration of Felix distributable into workspace
  • Felix allows deploying only jar bundles, which is inappropriate for easy development and debugging

We can use the power of Maven and these two resources to solve both problems.

The idea about the first one is to use Maven dependency management mechanism to download Felix dependencies and put them to required locations.The idea about the second one is to use OPS4J Pax URL to load a bundle from a folder (not a jar).

We will have two projects -- one solely for launching Felix environment and another one for a test bundle.

We start with Felix launcher felixLauncher project. We create a Maven project (if you have M2Eclipse installed, that is easier) in Eclipse. First warning is that packaging type should be "jar", not "pom" (the reason will be explained later).

To understand what is happening and what Felix framework requires, you may take a look into Felix Framework Distribution. you will see that there is a "bundle" folder which contains several jars. Also there is a "conf" folder which has "config.properties" inside it. So we will do the same for our felixLauncher project. We will dump those jars (gogo) into "bundle" folder. Also, we dump "osgi compendium" jar into "bundle" folder, because it will be needed for our projects. Since "bundle" folder is populated automatically, we also would like to clean it on the "clean" goal. Therefore, we tell Maven Clean Plugin to remove "bundle" folder.
Lastly, we specify Felix Distribution Framework as our dependency, because we want to launch Felix Framework directly from Eclipse. Since we want to use OPS4J Pax URL to launch our projects from folders, not from jars, we have to depend on that project as well to make it available for Eclipse.
So here is 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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>dk.sorokin.maksim</groupId>
  <artifactId>felixLauncher</artifactId>
  <version>1.0.0-SNAPSHOT</version>

  <name>Felix Launcher</name>

  <properties>
    <felix.bundlerepository.version>1.6.4</felix.bundlerepository.version>
    <felix.gogo.version>0.8.0</felix.gogo.version>
    <felix.framework.version>3.2.2</felix.framework.version>
  </properties>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.4.1</version>
        <configuration>
          <filesets>
            <fileset>
              <directory>bundle</directory>
            </fileset>
          </filesets>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.2</version>
        <executions>
          <execution>
            <id>copy</id>
            <phase>generate-resources</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>org.apache.felix</groupId>
                  <artifactId>org.apache.felix.gogo.command</artifactId>
                  <version>${felix.gogo.version}</version>
                </artifactItem>
                <artifactItem>
                  <groupId>org.apache.felix</groupId>
                  <artifactId>org.apache.felix.gogo.runtime</artifactId>
                  <version>${felix.gogo.version}</version>
                </artifactItem>
                <artifactItem>
                  <groupId>org.apache.felix</groupId>
                  <artifactId>org.apache.felix.gogo.shell</artifactId>
                  <version>${felix.gogo.version}</version>
                </artifactItem>
                <artifactItem>
                  <groupId>org.osgi</groupId>
                  <artifactId>org.osgi.compendium</artifactId>
                  <version>4.2.0</version>
                </artifactItem>
              </artifactItems>
              <outputDirectory>bundle</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.apache.felix</groupId>
      <artifactId>org.apache.felix.main</artifactId>
      <version>${felix.framework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.ops4j.pax.url</groupId>
      <artifactId>pax-url-assembly</artifactId>
      <version>1.3.3</version>
    </dependency>
  </dependencies>
</project>

Next, we need to create a config.properties file, because it is mandatory for Felix. There is a way to have own location for it, but to make things simpler, we will create it in the location, where Felix expects it by default. In the "felixLauncher" project create conf folder. Then create a file config.properties with the following content:

felix.auto.deploy.action=install,start
felix.log.level=1

org.osgi.framework.storage.clean=onFirstInit

You can read about options available on Apache Felix website.

Now we have to create an Eclipse launcher. In Eclipse go to "Run - Run Configurations...". In the left menu right-click on "Java Application" and click "New". In "Name" specify "Felix Launcher". In "Project" specify "felixLauncher" (if you do not see this project, that means the project is not understood by Eclipse as "Java" project. So it is important that it has "jar" packaging type). Then click on "Search..." in the "Main class" field. Search for "org.apache.felix.main.Main". Click "OK". Lastly, switch to "Arguments" tab and in "VM arguments" specify "-Djava.protocol.handler.pkgs=org.ops4j.pax.url". Click "Apply" and "Run". You will see something like:

____________________________
Welcome to Apache Felix Gogo

g!

Now Apache Felix can be launched correctly.

Next, let's create some test project. Create a Maven project "test.bundle". Create a package test.bundle.internal in src/main/java. And create "Activator.java" class there with the following content (do not worry about compilation problems for now):

package test.bundle.internal;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

  public void start(BundleContext arg0) throws Exception {
    System.out.println("Hello");
  }

  public void stop(BundleContext arg0) throws Exception {
    System.out.println("Bye");
  }
}

Now, the pom.xml file for the project. As you know, OSGi bundles need to have manifest files. But instead of writing them by hand, we can generate them. There is an excellent Apache Felix Maven Bundle Plugin, which we will use. We will tell Maven Jar Plugin to take that generated MANIFEST.MF file. So pom.xml will look like:

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>dk.sorokin.maksim</groupId>
  <artifactId>test.bundle</artifactId>
  <version>1.0.0-SNAPSHOT</version>

  <name>Test Bundle</name>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <executions>
          <execution>
            <id>generate-resources</id>
            <goals>
              <goal>manifest</goal>
            </goals>

            <configuration>
              <instructions>
                <Bundle-Name>${project.name}</Bundle-Name>
                <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                <Bundle-Activator>test.bundle.internal.Activator</Bundle-Activator>
              </instructions>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.3.1</version>
        <configuration>
          <archive>
            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.apache.felix</groupId>
      <artifactId>org.osgi.core</artifactId>
      <version>1.4.0</version>
    </dependency>
  </dependencies>
</project>

Then you can simply run mvn clean install on the project. Actually, Eclipse will do that for you. But you need to run install goal in order to have correct MANIFEST.MF file generated.

Last thing which is left to do is to inform Apache Felix about the project. Modify config.properties and add the following:

felix.auto.start.1 = \
 assembly:/C:/projects/test.bundle/target/classes

Path to the project may be different on your machine. You should see "Hello" message in the output.

Here is the zipped version of these two projects: zip file

Comments (1) Trackbacks (0)
  1. great explanation about the maven lifecycle… really help me out!!


Leave a comment


Trackbacks are disabled.