Creating OSGi bundles of your Maven dependencies
Working with Maven and OSGi is very straightforward. You add your dependencies in the pom.xml and then the maven-bundle-plugin does the dirty work, creating the correct headers for the OSGi descriptor and of course adding them to your compile classpath for your developing phase.
But then you add your fantastic new OSGi bundle to the container and it doesn't work........ops, what went wrong ???
The problem is in the dependencies into the OSGi container, here the Maven dependencies can be unavailable and therefore our Bundle is unable to start.
The answer to this problem is easy: "Add those missing bundles !!!!". Yes, easy to say, long and boring to do. Most libraries are not OSGi bundles and we should repackage all them with OGSi headers to be loaded into the container.
maven-bundle-plugin to the rescue !!!
But there is a smarter way to do things: looking at maven-bundle-plugin documentation there are goals that repackage our Maven dependencies as OSGi Bundles, with very few configurations.
The best thing to do is to create a profile inside our bundle pom with the bundle plugin configured with the goal options and lifecycle configuration:
<profile>
<id>create-osgi-bundles-from-dependencies</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.0.1</version>
<extensions>true</extensions>
<executions>
<execution>
<id>wrap-my-dependency</id>
<goals>
<goal>wrap</goal>
</goals>
<configuration>
<wrapImportPackage>;</wrapImportPackage>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Here we can notice some things about configuration:
Version is 2.0.1, but the goal is also in some oldest versions, like 1.4.1.
The goal is wrap, that is like running the bundleall goal with depth parameter configured to 1, enough to take direct dependencies but not transitive ones.
The wrapImportPackage must be configured, because not configured or empty means everything, so that the plugin explores the jar classes and try to understand what packages to import. This can lead to a non working Bundle if the jar contains features that you don't use and as such you don't want to install in your OSGi Container. A value of ";" means that nothing will be imported (it's an hack....).
Now we can launch Maven to let the plugin do the dirty work:
mvn -Pcreate-osgi-bundles-from-dependencies bundle:wrap
Once finished you can find your bundles inside the target/classes folder, but this can be personalized changing the outputDirectory of the Maven build:
<build>
<directory>${basedir}/bundles</directory>
…
…
This can be done easily and with no negative implications thank to the custom profile for this build.
Maven scope to the rescue
Now that we know how to create those bundles, the next question is "how can I choose which bundles ???"
Let's make an example, suppose I have three dependencies:
libraryA: needed to compile and at runtime, yet deployed as OSGi Bundle in the container
libraryB: needed at compile time, not deployed
libraryC: needed at runtime, not deployed
In this caso I could declare those dependencies this way (pseudo-pom):
<dependency>
<artifactId>libraryA</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<artifactId>libraryB</artifactId>
</dependency>
<dependency>
<artifactId>libraryC</artifactId>
<scope>runtime</scope>
</dependency>
The bundleall/wrap Mojo uses only dependencies at compile/runtime scope, this way we can be sure that only needed dependencies will be OSGified.