2

I'm using some off-the-shelf OSGi bundles in my application and would like to repackage them together with additional packages that are not yet OSGi compatible into a new bundle.

Case in point is EclipseLink, which is available as several OSGi bundles, most of which are optional, depending on what you want to do. I want to pick those bundles that are relevant for me, add database drivers (for example the MySQl JDBC connector) and repackage them into a new bundle that is easier to deploy.

I'm using the maven-bundle-plugin from Apache Felix. I set up a new Maven project without source code, added the four eclipselink and the mysql connector as dependencies and tried the following:

  • use the <Embed-Dependency> and <Embed-Transitive> instructions to include all dependencies in one bundle. Problem: Optional dependencies from the eclipselink bundles (for example, javax.mail.internet) become required as the plugin rewrites the manifest. The original bundles contain "resolution=optional" in the manifest and thus work well without.
  • use the manifest goal of the plugin and a jar-with-dependencies assembly, but that gives me basically the same result, only with more work.
  • used the bundleall goal of the plugin, which is not quite what I want, because it creates separate bundles again. Even worse, because now these bundles don't have their dependencies inside.

I'm going to face similar issues with Struts 2. I'm not going to be obsessive about this, and just go with a whole bunch of separate third-party bundles, but if I can package them more neatly, I would really like to. I'm aware that a point of OSGi is modularity, so creating big bundles kind of defeats that, but I feel that if your modules are tightly coupled anyway, you might as well put them into a single bundle.

Of course, I could manually tweak the manifests, but I definitely don't want to.

Hanno Fietz
  • 30,799
  • 47
  • 148
  • 234
  • To clarify, you want to merge the classes, resources, and manifest contents of a set of OSGi bundles and other jars into one? Do you need to expose the types from the non-OSGi jars as well? – Rich Seller Aug 12 '09 at 20:47
  • Isn't this against the general principles of OSGi? Why not OSGify the non-bundle jars (again, using bnd and maven) and use them as proper bundle dependencies rather than embedded dependencies. Basically, you convert everything to a bundle. – omerkudat Aug 12 '09 at 22:02
  • @Rich Seller: Yeah, that is correct. Actually, I need to expose a lot less than the original bundles, and I typically only need one package from the non-OSGi jars. For example, if I wrap eclipselink and my db drivers into one bundle, that would really only need to export org.eclipse.persistence.jpa, everything else will happen inside the bundle. – Hanno Fietz Aug 13 '09 at 07:41
  • @omerkudat: I'm aware of that, as I already wrote above. However, even if you're using OSGi to make everything modular, in a particular project, you might want to trade some of the modularity for a more compact and less confusing packaging. If you're not planning on changing the set of functionality you're using from eclipselink, you have no need to have all the separate bundles. Putting them into a single one then more appropriately reflects the actual modularity of your app, and therefore is easier to understand and easier to maintain. – Hanno Fietz Aug 13 '09 at 07:48

1 Answers1

2

As omerkudat says, this is probably not a good practice to encourage, but as you have your reasons, this is a way you could do a poor-man's merge.

Assuming you are handling the OSGi manifest yourself, you only really need to get all the classes from the bundles and jars into the target/classes directory before the package phase.

You can do this with either of the dependency plugin's unpack-dependencies or unpack goals. I'd use the unpack-dependencies if you want to process all the project dependencies (or those following a certain naming patter or in a certain groupId) and the unpack goal if you want to have fine control over the artifacts to be unpacked (at the expense of a verbose POM). I'll assume unpack in my example. Each unpack is output to the project's outputDirectory (i.e. target/classes).

Note this will overwrite duplicate artifacts from each package in the order they're downloaded, so the manifests will be clobbering each other. To ensure your artifacts are managed correctly, I would bind the unpack goal to an early phase so that your src/main/resources are copied on top of the unpacked contents and not overwritten. In the sample below this phase is generate-resources, so it will happen after your local compile. If you need to overwrite any of the classes, use an earlier phase to unpack the dependencies such as generate-sources

My sample below unpacks the contents of junit-3.8.1 and commons-io 1.4 (just the first two dependencies I had declarations for) into target/classes before the project's resources are copied there. Note that the versions are defined in my dependencies section. If you haven't got the bundles/jars declared as dependencies you'll need to declare the version in the artifactItem as well.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>unpack</id>
      <phase>generate-resources</phase>
      <goals>
        <goal>unpack</goal>
      </goals>
      <configuration>
        <artifactItems>
          <artifactItem>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <overWrite>false</overWrite>
            <outputDirectory>${project.build.outputDirectory}</outputDirectory>
          </artifactItem>
          <artifactItem>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <overWrite>false</overWrite>
            <outputDirectory>${project.build.outputDirectory}</outputDirectory>
          </artifactItem>
        </artifactItems>
        <overWriteReleases>false</overWriteReleases>
        <overWriteSnapshots>true</overWriteSnapshots>
      </configuration>
    </execution>
  </executions>
</plugin>
Rich Seller
  • 83,208
  • 23
  • 172
  • 177
  • Hm, OK, this could work. Thanks. Not exactly beautiful, but I guess that's what I asked for. – Hanno Fietz Aug 13 '09 at 14:04
  • If all of your dependencies need to be bundled you can use the unpack-dependencies goal instead (http://maven.apache.org/plugins/maven-dependency-plugin/examples/unpacking-project-dependencies.html). This involves less ugly configuration, but it's still a hack – Rich Seller Aug 13 '09 at 14:18