Recently I started working with a team on an Eclipse plugin. The team had developed an awesome plugin that does the intended purpose. Thus I checked out the source and tried building it. The project source contained all the required libraries and it could only be build in Eclipse. In today’s world of continuous delivery, this is a major impediment as such a project can not be built on Jenkins. The project not only contained the required libraries, but the complete eclipse settings were kept as part of source, so I thought of improving this first. I created a POM.xml in the Project and deleted the settings and libs. The build worked fine but as soon as I opened the project in eclipse it was a mess. Nothing worked there!
It took sometime to realize that Eclipse and Maven are two different worlds that do not converge easily. Even the smallest of the things like the artifact-version and Bundle version do not converge easily. In maven anything can be the version e.g. 21-snapshot. But in eclipse there are standards, it has to be named [number].[number].[number].qualifier e.g. 1.1.21.qualifier.
In order to bridge the gap between the two worlds Sonatype have contributed Tycho to the Eclipse ecosystem. Add the plugin with the eclipse repository :
<repository> <id>juno</id> <layout>p2</layout> <url>http://download.eclipse.org/releases/juno</url> </repository> <plugin> <groupId>org.eclipse.tycho</groupId> <artifactId>tycho-versions-plugin</artifactId> <version>0.18.1</version> </plugin> <plugin> <groupId>org.eclipse.tycho</groupId> <artifactId>target-platform-configuration</artifactId> <version>0.18.1</version> <configuration> <pomDependencies>consider</pomDependencies> <environments> <environment> <os>linux</os> <ws>gtk</ws> <arch>x86_64</arch> </environment> </environments> </configuration> </plugin>
There are few points to note here:
- If the plugin is for a specific eclipse platform, the repository of the same should be added.
- The plugin could use dependencies from POM or MANIFEST.MF. If the dependencies are used from POM, then set pomDependencies
The Tycho plugin also brings along a set of plugins for version update, surefire tests etc. The plugins can be invoked individually to perform different goals e.g. the versions plugin can be used in the following manner to set versions:
mvn tycho-versions:set-version -DnewVersion=1.1.1-SNAPSHOT
This will set the 1.1.1-SNAPSHOT version in POM and 1.1.1.qualifier in the MANIFEST.MF
While the plugins offer a lot, there are a few limitations as well. The plugin can not generate proper eclipse settings for PDE. Thus if we do not keep these settings we need to generate these again. Few other limitations are listed on the plugin page.
After this now we were able to bridge the two worlds in some sense. Maven builds which generate Eclipse plugin were possible.
In eclipse PDE, there are plugins and fragments. Plugins are complete modules that offer a functionality and fragments is a module which attaches itself to a parent plugin then enhancing its capability. Thus a plugin can attach n number of fragments, enhancing it during runtime.
We had a base plugin, which offered some basic features and a fragment was built on top to use Hadoop 1.x in the plugin. After sometime the requirement came to support Hadoop 2.x as well. Now the two libraries are not compatible with each other. Thus some workaround was required to enable this
Fortunately Eclipse being OSGI based has a different mechanism of loading class as compared to other java applications. Usually there is a single/hierarchy classloader(s) which load the complete application. Now in such a case if two incompatible jars are bundled, only one will be loaded. But in eclipse each plugin has its own classloader which can load its own classes. Now this offers couple of opportunities like supporting different versions of the same library. This feature is extended to plugin only and not fragments. Fragments do not have their own classloaders and use the parent plugin classloaders.
We could have used plugin classloader support but the hadoop libs were loaded by fragment instead of plugin. We converted the fragment into a plugin, which required a complete task of refactoring the existing codebase. After the hadoop 1.x based plugin was formed. We could make more plugins for hadoop 2.x. Each plugin loads its own set of classes. Now the only requirement is to have more PermGem space as the complete plugin can not be loaded into the default PermGem space.