Note: This manual is already outdated - the eclipse plugin itself can pack eclipse bundles as Maven 2 dependencies, and gained support to build the bundles itself.
This howto describes how to build a full-blown eclipse plugin using Maven2. The howto strives to keep the plugin able to be executed and debugged directly in the Eclipse IDE while using Maven2 repository for dependencies.
Before we drop it on, you have to decide a few things:
platform is one of:
There already is an Eclipse bundle project built with Maven2. You may download the project EuroMath2 (you have to grab the 1.4.x version - this tutorial relates to 1.4.0-alpha version, later versions may have fixed some issues stated in this text). This tutorial is not perfect, some things could be done in a better way, but I'm simply too lazy and I wanted to show bad paths aswell :-)
All EM2's bundles were created to be compatible with Eclipse 3.2 and OSGi - I don't care for Equinox or whatever that is. This tutorial merely describes the build system of EuroMath2 so you're on your own when building Eclipse bundles with Maven2.
Okay, let's get started. Download sources distribution, go to sk.uniba.euromath.pom directory, issue
mvn install
and grab the RCP application at sk.uniba.euromath.rcp's target directory. In this howto I'll describe how I managed to build EuroMath2 - please grab and modify those poms any way you see fit for your application.
EM2 consists of the following Maven2 projects (artifact ids are listed):
We'll start with sk.uniba.euromath.pom's pom.xml. It is pretty straightforward, except that the bundle plugin must extend the sk.baka.eclipse:plugin-parent-pom POM (located here) - it defines versions of bundles that comes with Eclipse distribution (we are going to use bundles from Eclipse 3.2).
<parent> <groupId>sk.baka.eclipse</groupId> <artifactId>plugin-parent-pom</artifactId> <version>3.2</version> </parent>
Let's continue with sk.uniba.euromath's pom.xml. It extends sk.uniba.euromath.pom of course. Please note that Eclipse bundle dependencies are defined like regular dependencies. This of course causes some problems with assembly plugin and eclipse plugin - more on this later.
<!-- eclipse plugins dependency --> <dependency> <groupId>eclipse.bundles</groupId> <artifactId>org.eclipse.core.runtime</artifactId> </dependency> <dependency> <groupId>eclipse.bundles</groupId> <artifactId>org.eclipse.equinox.common</artifactId> </dependency>
sk.uniba.euromath.fop's pom.xml demonstrates a remedy to assembly plugin problem - it simply declares some dependencies as provided. While this will work OK with commons-lang dependency (it is provided by the sk.baka.eclipse bundle after all), it causes Eclipse bundles to be absent when RCP assembly includes all runtime dependencies.
Note: I was planning to develop maven-eclipse-plugin to complement standard maven-eclipse-plugin with the functionality required to develop Eclipse bundles, but I don't have time for such work anymore. So please consider it as a starting point for developing your own m2 plugin or the like.
First we have to configure the workspace to add the M2_REPO classpath variable. Execute:
mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo
Now .classpath and .project files must be generated. Just execute:
mvn eclipse:eclipse
Note that the plugin nature is already present in the .project file - this is defined in the plugin-parent-pom maven2 plugin.
Dependent eclipse plugins are registered in the plugin classpath, like common libraries - this is because maven-eclipse-plugin does not recognize between a regular library and a plugin dependency. We have to move those dependencies into the META-INF/MANIFEST.MF file, to register them as plugin dependencies. Delete all Eclipse-Bundles dependencies from your .classpath file and move them to the META-INF/MANIFEST.MF.
Now the .classpath file contains 'var' referencies directly to the Maven2 repository. While this isn't bad for a regular Eclipse project, it breaks some things in Eclipse-bundle project (for example you cannot export classes from such dependencies). Moreover, we need to mimic runtime bundle environment. So, we'll first create symlinks to libraries, and place them into the lib/ directory. Look into sk.uniba.euromath/.project for details:
<linkedResources> <link> <name>lib/msv-20050913.jar</name> <type>1</type> <locationURI>M2_REPO/msv/msv/20050913/msv-20050913.jar</locationURI> </link> <link> <name>lib/src/msv-20050913-sources.jar</name> <type>1</type> <locationURI>M2_REPO/msv/msv/20050913/msv-20050913-sources.jar</locationURI> </link> <link> <name>lib/stax-api-1.0.jar</name> <type>1</type> <locationURI>M2_REPO/stax/stax-api/1.0/stax-api-1.0.jar</locationURI> </link> <link> <name>lib/src/stax-api-1.0-sources.jar</name> <type>1</type> <locationURI>M2_REPO/stax/stax-api/1.0/stax-api-1.0-sources.jar</locationURI> </link> ...
Note the 'sources' links. We cannot use any variables when attaching sources to the 'lib' .classpath dependencies, thus we cannot link sources directly with Maven2 repository. We will use symlinks once more, to bring library sources into our project to the lib/src/ directory.
We have to modify .classpath sources to reference these linked libraries:
... <classpathentry exported="true" sourcepath="lib/src/commons-lang-2.1-sources.jar" kind="lib" path="lib/commons-lang-2.1.jar"/> <classpathentry exported="true" sourcepath="/sk.baka.xml.gene/src/main/java" kind="lib" path="lib/gene-0.3.jar"/> <classpathentry exported="true" kind="lib" path="lib/isorelax-20030108.jar"/> ...
Now you can export all these libraries from your bundle in MANIFEST.MF file by specifying packages
Let's look into sk.uniba.euromath.fop/pom.xml once more. It depends on sk.uniba.euromath plugin, which is marked 'provided'. sk.uniba.euromath plugin depends on commons-lang which should also be marked 'provided' - why did we then introduced that commons-lang dependency in sk.uniba.euromath.fop/pom.xml? It is because sk.uniba.euromath.fop depends on gene-fop library (marked 'compile') which in turn depends on commons-lang, which is thus also marked 'compile', regardless of the sk.uniba.euromath dependency.
Finally we'll describe all assemblies. Each project (except sk.uniba.euromath.pom) uses assembly to build its bundle. Let's look on sk.uniba.euromath/src/main/assembly/bin.xml. First thing: we need to copy regular dependencies to lib/ directory and omit the eclipse.bundles dependencies completely. Assembly plugin does not allow to use wildcards like eclipse.bundles:* (sigh), so we need to exclude all eclipse.bundles manually. This can be remedied by declaring these bundles as 'provided' instead of 'compile' in pom.xml in the dependency section, but you'd have to manually include all these dependencies later in the sk.uniba.euromath.rcp plugin.
This assembly produces a zip file. I could simply produce a jar file but the maven-assembly-plugin refuses to use our META-INF/MANIFEST.MF file and uses one generated by itself. Note that the assembly generates the zip file without the 'bin' classifier. I had to remove the classifier because Eclipse uses its own bundle name mappings (see sk.uniba.euromath.rcp/src/main/assembly/rcp.xml):
<outputFileNameMapping>${artifactId}_1.4.0.jar</outputFileNameMapping>
The problem is that the classifier is always added - even when you specify this filename mapping. Thus RCP would include bundles such as sk.uniba.euromath.fop_1.4.0-bin.jar.
Okay, let's divide that mess into steps:
Ah, the dreaded ClassNotFoundException / NoClassDefFoundError. They can meet you anytime when developing Eclipse bundles and they are often thrown for no apparent reason. So:
If you use Subclipse use the newest version (1.1.4) when dealing with symlinks in Eclipse 3.2.