Developing and Managing Multiple Modules: Eclipse OSGI and Maven

Eclipse and maven do not play nicely with each other. They try, but there are some fundamental differences that make it tricky. I will first describe some of those differences. Then I will discus how I have gone about developing an managing Eclipse/OSGI bundles using maven and Eclipse.

Differences

Version numbers

  • Eclipse versions are numbered X.Y.Z.qualifier. The qualifier is optional and adds a timestamp.
  • Maven versions are also typically X.Y.Z-SNAPSHOT. The SNAPSHOT is optional and adds a timestamp.
  • These seem similar, the only difference being the use of a ‘.’ or a ‘-‘ to separate the main version number form the timestamp.
  • The problem occurs with respect to the interpretation of a qualifier/SNAPSHOT variant of a version.
    • In eclipse a qualified version is considered to be newer than a version without the qualifier.
    • In maven the SNAPSHOT version is considered a precursor, i.e. an earlier (development) version.

Dependency Scope

  • Eclipse/OSGI dependencies (defined in the MANIFEST.MF file) are not, by default, transitive.
    • I.e. if A depends on B which depends on C, then A does not, by default, have access to the definitions in C.
    • If B ‘reexports’ C, then A has access to it.
  • Maven dependencies (defined in the pom.xml file) are, by default, transitive.
    • I.e. if A depends on B which depends on C, then A does have access to the definitions in C.
    • If B makes the dependency on C ‘scope=provided’ then A will not have access to C, but to execute A, a runtime dependency on C will be needed.

Dependencies – which Version

  • Both Eclipse/OSGI and maven allow the version number of a dependency to be defined. In fact it is to be encouraged. However the class path may not be what you expect.
    • The OSGI framework/container/runtime allows for different versions of the same bundle/jar to coexist and hence  multiple different versions of the same code may be executed. I.e. Each bundle will use the version of the bundle it references at compile and runtime.
    • In maven, the class path will determined by its Dependency Mediation rules, meaning that you get the “nearest definition”. This means that at compile time you can force dependency on a particular version (by explicitly including a dependency on that version), however at runtime the class path may provide a different version of the jar.

Development

I am a big fan of Eclipse as a Java IDE. I find it works well for me. Except, when I want to use maven to build the modules.

One easy option is to use Tycho. This solution means that a developer can essentially avoid having to understand maven. Tycho takes over maven almost completely and in my opinion using Tycho cannot be said to be ‘using maven’. Tycho-on-maven and native/original-maven are best considered to be separate things.

Tycho has many advantages, but I find that it is slow to build, and releasing/deploying p2 repositories does not seem to be as simple as the nexus/maven approach. Hence my investigation into an alternative.

One thing I particularly like about maven is its directory layout. In particular, a maven module contains the source code for the modules alongside the tests for that module, and those tests are, by default, executed as part of the build. It actively encourages module-based unit testing. The deployed jar (sensibly) does not  include the test code.

The Eclipse m2e project goes along way towards making the use of Eclipse for the development of maven modules nice and easy. Except, when those maven modules are also developed as OSGI-bundles/eclipse-plugins.

My approach to building OSGI/Eclipse bundles using maven is as follows:

Code Layout

Use the standard maven folder and file layout structure.

MANEFEST.MF

    • Use the org.apache.felix:maven-bundle-plugin to generate a manefest file
    • or, put a hand written manefest file in src/resources and tell maven to include it in the built jar. Using the maven-jar-plugin

In either case, tell the eclipse IDE where to find the MANEFEST.MF file using the file .settings/org.eclipse.pde.core, for each project as shown below,

BUNDLE_ROOT_PATH=target/classes
eclipse.preferences.version=1

(change the value of BUNDLE_ROOT_PATH to be the location of the MANEFEST.MF file)

Handling the Differences

Version numbering: This should not really be an issue provided you only release “proper” versions (i.e. non-SNAPSHOT).

Dependency Scope: Limit the scope of maven dependencies to ‘provided’ unless you want the depended on artefact to be included in the exported API of your artefact.

Dependencies – which Version: Yet to find a solution?

Dependencies to existing eclipse bundles

Eclipse has a large number of existing bundles which are usually found in the eclipse IDE installation, or via a p2 site referenced in a .target file. If we build with maven, how do we tell maven about these bundles?

Generate p2 Repository

To generate a p2 repository from maven artifacts you can use the org.reficio:p2-maven-plugin. The configuration in the pom file tells the (maven) plugin which artefacts to include in the p2 repository.

Useful Links

Thoughts about life: Practise Generosity

Why do we practise generosity? My answer is as follows,

In order that money and the acquisition of money does not become my primary goal in life. Practicing generosity reminds me that money is a means to enable me to bless others and that it serves as a tool to help me meet my purpose. Money is not important for its own sake. Be resourced so that you can make righteous use of the resources. Jesus had riches, and a treasurer, and used the money righteously. [Mat 6v24, John 12v6, Mat 2v11].