Getting the benefits of maven-bundle-plugin in other project types


Note: This information is partially available at http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html

The goal here is to be able to use a different packaging type than "bundle", say "war" packaging, and still get benefits of the maven-bundle-plugin. The major benefit is of course having the manifest being generated by the BND tool.

If your project is packaged as "war", you can still use the maven-bundle-plugin to generate the manifest if you add "war" to supportedProjectTypes:

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <configuration>
      <supportedProjectTypes>
        <supportedProjectType>jar</supportedProjectType>
        <supportedProjectType>bundle</supportedProjectType>
        <supportedProjectType>war</supportedProjectType>
      </supportedProjectTypes>

Here is a more complete configuration that I use for generating a manifest using BND and adding it to the WAR:

<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
  ...
  <properties>
    <bundle.symbolicName>myartifact</bundle.symbolicName>
    <bundle.namespace>myartifact</bundle.namespace>
  </properties>

  <modelVersion>4.0.0</modelVersion>
  <groupId>mygroup</groupId>
  <artifactId>myartifact</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>${bundle.symbolicName}</name>

  <packaging>war</packaging>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <archive>
            <!-- add the generated manifest to the war -->
            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <executions>
          <execution>
            <id>bundle-manifest</id>
            <phase>process-classes</phase>
            <goals>
              <goal>manifest</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <supportedProjectTypes>
            <supportedProjectType>jar</supportedProjectType>
            <supportedProjectType>bundle</supportedProjectType>
            <supportedProjectType>war</supportedProjectType>
          </supportedProjectTypes>
          <instructions>
            <Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName>
            <Bundle-Version>${pom.version}</Bundle-Version>
            <!--
               | assume public classes are in the top package, and private classes are under ".internal"
            -->
            <Export-Package>!${bundle.namespace}.internal.*,${bundle.namespace}.*;version="${pom.version}"</Export-Package>
            <Private-Package>${bundle.namespace}.internal.*</Private-Package>
            <!--
               | each module can override these defaults in their osgi.bnd file
            -->
            <_include>-osgi.bnd</_include>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>

Now we can get a bundle with a BND-generated manifest installed in the repo as a .war.

For JAR packaging, you'd replace appropriate parts of above with:

<plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <!-- add the generated manifest to the archive -->
            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
          </archive>
        </configuration>
      </plugin>

Embedding Dependencies

If you use at least maven-bundle-plugin version 1.4.3, it should apply the Embed-Dependency
instruction for both the bundle and manifest goals - however, because the manifest goal doesn't
actually end up building the final bundle then you might find some minor differences.

But you can definitely use this to generate the Bundle-ClassPath even with "war" packaging.

You can configure Embed-Dependency to match the location the WAR plugin uses.

For example perhaps something like:

<configuration>
  <supportedProjectTypes>
    <supportedProjectType>jar</supportedProjectType>
    <supportedProjectType>bundle</supportedProjectType>
    <supportedProjectType>war</supportedProjectType>
  </supportedProjectTypes>
  <instructions>
    <Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath>
    <Embed-Directory>WEB-INF/lib</Embed-Directory>
    <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
    <Embed-Transitive>true</Embed-Transitive>
    <Import-Package>*;resolution:=optional</Import-Package>
  </instructions>
</configuration>

Example

Hendy Irawan has created a project to demonstrate:

  • Apache CXF
  • OSGi
  • Pax Web Service
  • Pax Web Extender War
  • Maven
  • Maven Bundle Plugin
  • configuring it for WAR project
  • Maven Pax Plugin

Checkout from here: (Subversion)

https://scm.ops4j.org/repos/ops4j/laboratory/users/ceefour/cxf-osgi-sample

This might be helpful with regards to the above, or how to mix and match the combinations.

Note that this is not an official sample, just a contribution.