Search code examples
mavenosgiosgi-bundle

Maven + OSGi bundle build complication


I'm currently developing an OSGi based application (using Felix). In this project, there are bundles depending on other bundles. In the past we were using Ant script to compile and build everything, and now we want to mavenize this, however the task is not trivial at all.

Here is the folder structure I have:

+-shared
 -- pom.xml 
 -- someProject
  --- pom.xml
 -- org.apache.felix
  --- pom.xml
 -- org.apache.activemq
  --- pom.xml
 -- org.apache.log4j
  --- pom.xml
 -- org.snake.yaml
  --- pom.xml
 -- ...

Obviously, the root POM is supposed to build everything here, and the individual POMs simply describe the bundles. I also have MANIFEST.MF files in each bundle (not auto-generated). I must say that we don't want to get the stuff from the common repository, but rather to have our own local one.

Right now, I am not using any plugin like maven-bundle-plugin and I am trying to do this myself. However I get a lot of errors, which are mostly package does not exist errors. Therefore I suspect I am doing something wrong. After looking around in the forum, I noticed that a lot of people have been using the maven-bundle-plugin, so I also started to consider to do so. However, the official website could help me only until a certain point, then I got stuck.

So long story short, I'd like to have a functional pom.xml which can at least compile. It may also generate the MANIFEST.MF automatically, would be nice, however, I am not sure how should I proceed.

So far I came up with this pom.xml (of someProject1):

<?xml version="1.0" encoding="UTF-8"?>
<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>
   <parent>
      <groupId>shared</groupId>
      <artifactId>shared.master</artifactId>
      <relativePath>../pom.xml</relativePath>
      <version>1.0.0-SNAPSHOT</version>
   </parent>
   <groupId>shared</groupId>
   <artifactId>shared.cmd.felix</artifactId>
   <name>shared.cmd.felix</name>
   <version>1.0.0</version>
   <packaging>jar</packaging>
   <dependencies>
      <dependency>
         <groupId>shared</groupId>
         <artifactId>org.apache.felix</artifactId>
         <version>1.0.0</version>
         <scope>system</scope>
         <systemPath>${project.basedir}/../org.apache.felix/felix.jar</systemPath>
      </dependency>
      <dependency>
         <groupId>shared</groupId>
         <artifactId>org.apache.log4j</artifactId>
         <version>1.0.0</version>
         <scope>system</scope>
         <systemPath>${project.basedir}/../org.apache.log4j/log4j-1.2.17.jar</systemPath>
      </dependency>
   </dependencies>
   <build>
      <sourceDirectory>src/</sourceDirectory>
      <plugins>
         <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.2</version>
            <configuration>
               <source>${jdk.version}</source>
               <target>${jdk.version}</target>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.1</version>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                     <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                  </manifest>
                  <manifestEntries>
                     <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                     <Bundle-Version>${project.version}</Bundle-Version>
                     <Bundle-ClassPath>.</Bundle-ClassPath>
                     <Export-Package>shared.cmd.felix</Export-Package>
                  </manifestEntries>
               </archive>
            </configuration>
         </plugin>
      </plugins>
   </build>
</project>

and pom.xml of org.apache.felix:

<?xml version="1.0" encoding="UTF-8"?>
<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>
   <parent>
      <groupId>shared</groupId>
      <artifactId>shared.master</artifactId>
      <relativePath>../pom.xml</relativePath>
      <version>1.0.0-SNAPSHOT</version>
   </parent>
   <groupId>shared</groupId>
   <artifactId>org.apache.felix</artifactId>
   <name>org.apache.felix</name>
   <version>1.0.0</version>
</project>

and the MANIFEST.MF I have is:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Shared Felix Console Extension
Bundle-SymbolicName: shared.cmd.felix
Bundle-Version: 1.0.0
Fragment-Host: shared.mw;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ClassPath: .,
 bundle/system/org.apache.felix.gogo.runtime-0.10.0.jar
Export-Package: shared.cmd.ext
Import-Package: shared,
 shared.cmd,
 shared.comp,
 shared.mw,
 shared.sched,
 shared.service,
 org.apache.felix.service.command,
 org.apache.log4j,
 org.osgi.framework
Require-Bundle: org.apache.felix;bundle-version="1.0.0",
 org.apache.activemq

however, I get errors like:

[ERROR] /shared/shared.cmd.felix/src/shared/cmd/ext/ListScheduledTasks.java:[11,40] package org.apache.felix.service.command does not exist
[ERROR] /shared/shared.cmd.felix/src/shared/cmd/ext/ListScheduledTasks.java:[15,19] cannot find symbol

Now, if I want to change this to a state which can utilize maven-bundle-plugin, how could it be? I came up with this, but don't know if this corresponds to the one I have above:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>shared</groupId>
  <artifactId>shared.cmd.felix</artifactId>
  <packaging>bundle</packaging>
  <name>shared.cmd.felix</name>
  <version>1.0.0-SNAPSHOT</version>
  <dependencies>
    <dependency>
      <groupId>${pom.groupId}</groupId>
      <artifactId>org.apache.felix</artifactId>
      <version>1.0.0</version>
    </dependency>
    <dependency>
      <groupId>${pom.groupId}</groupId>
      <artifactId>org.apache.log4j</artifactId>
       <version>1.0.0</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>${pom.groupId}</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Export-Package>--WHAT TO PUT HERE?--</Export-Package>
            <Private-Package>--WHAT TO PUT HERE?-</Private-Package>
            <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
            <Bundle-Activator>--WHAT TO PUT HERE?-</Bundle-Activator>
            <Export-Service>--WHAT TO PUT HERE?-</Export-Service>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

and more importantly, do I need to insert everything there? Can't I skip some of those, such as Export-Service? And what happened to the local paths that I was entering above, why doesn't the plugin have these? Does it automatically find them or?

Could someone help me out with this? I would appreciate any contribution.

Thanks in advance.


Solution

  • It is very difficult to do all the package imports and exports by hand. Even if you achieve it the code will be very brittle as you would have to adapt to all refactorings. If you then also want to do the package uses clauses by hand you are totally screwed.

    I have used the maven-bundle-plugin as well as the bnd-maven-plugin. Both work great. If you project is designed well then you will not need much config at all.

    The tasklist-ds example shows how to apply this to a complete tree of bundles.

    I configure the maven-bundle-plugin only in the parent pom. The actual config is done in bnd.bnd files that are imported.

    You can start by keeping them empty. Then look at the bundles that are generated. You can then tune the imports and export but try to keep those special configs to a minimum.