Building iDempiere Plug-ins with Maven
This tutorial was contributed by Luis Amesty from Amerpsoft Consulting.
From iDempiere version 6.1 onward, Maven (with Tycho) replaced Buckminster as the build system. This guide explains how to structure a Maven-based plug-in project set.
The sample projects referenced below are available at: Amerpsoft iDempiere Community
Project structure
A Maven-based iDempiere plug-in set uses the following layout:
MyPlugins/
org.myplugin.feature/ ← Feature project
org.myplugin.editors/ ← Plugin project
org.myplugin.themes/ ← Fragment project
org.myplugin.p2.site/ ← P2 repository project
org.myplugin.p2.targetplatform/ ← Target platform project
pom.xml ← Root Maven POM
Keep the plug-in directory alongside (not inside) the iDempiere source tree so it can be built independently and upgraded without merge conflicts.
Feature project
The feature project lists which plug-ins are included in the feature. P2 projects are not included in the feature XML.
pom.xml:
<project ...>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.myplugin.feature</artifactId>
<parent>
<groupId>org.idempiere</groupId>
<artifactId>org.idempiere.parent</artifactId>
<version>7.1.0-SNAPSHOT</version>
<relativePath>../../myexperiment/org.idempiere.parent/pom.xml</relativePath>
</parent>
<packaging>eclipse-feature</packaging>
</project>
feature.xml:
<feature id="org.myplugin.feature" label="My Plugin" version="7.1.0.qualifier">
<plugin id="org.myplugin.editors" download-size="0" install-size="0"
version="0.0.0" unpack="false"/>
<plugin id="org.myplugin.themes" download-size="0" install-size="0"
version="0.0.0" fragment="true" unpack="false"/>
</feature>
- Do not add a
<groupId>to the feature project POM. - The
<artifactId>in the POM must match theidattribute infeature.xml. - Use
eclipse-featureas the packaging type.
Plugin project
pom.xml:
<project ...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.idempiere</groupId>
<artifactId>org.idempiere.parent</artifactId>
<version>7.1.0-SNAPSHOT</version>
<relativePath>../../myexperiment/org.idempiere.parent/pom.xml</relativePath>
</parent>
<artifactId>org.myplugin.editors</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
MANIFEST.MF (key entries):
Bundle-SymbolicName: org.myplugin.editors;singleton:=true
Bundle-Version: 7.1.0.qualifier
Require-Bundle: org.adempiere.base;bundle-version="7.1.0", ...
Service-Component: OSGI-INF/*.xml
- The
<artifactId>in the POM must matchBundle-SymbolicNameinMANIFEST.MF. - Use
eclipse-pluginas the packaging type.
Fragment project
pom.xml:
<project ...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.idempiere</groupId>
<artifactId>org.idempiere.parent</artifactId>
<version>7.1.0-SNAPSHOT</version>
<relativePath>../../myexperiment/org.idempiere.parent/pom.xml</relativePath>
</parent>
<artifactId>org.myplugin.themes</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
MANIFEST.MF (key entries):
Fragment-Host: org.adempiere.ui.zk;bundle-version="7.1.0"
Jetty-WarFragmentFolderPath: /
Fragments use eclipse-plugin as packaging (not eclipse-fragment). The Fragment-Host entry in MANIFEST.MF is what makes it a fragment.
P2 site project
The P2 site project creates a deployable P2 repository from the feature.
pom.xml:
<project ...>
<artifactId>org.myplugin.p2.site</artifactId>
<parent>
<groupId>org.idempiere</groupId>
<artifactId>org.idempiere.parent</artifactId>
<version>7.1.0-SNAPSHOT</version>
<relativePath>../../myexperiment/org.idempiere.parent/pom.xml</relativePath>
</parent>
<packaging>eclipse-repository</packaging>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-p2-repository-plugin</artifactId>
<executions>
<execution>
<id>build-site-p2</id>
<goals><goal>assemble-repository</goal></goals>
</execution>
</executions>
<configuration>
<includeAllDependencies>false</includeAllDependencies>
<xzCompress>false</xzCompress>
</configuration>
</plugin>
</plugins>
</build>
</project>
category.xml:
<site>
<feature url="features/org.myplugin.feature_7.1.0.qualifier.jar"
id="org.myplugin.feature" version="7.1.0.qualifier">
<category name="org.myplugin"/>
</feature>
</site>
Use eclipse-repository as the packaging type. The feature id in category.xml must match the feature project artifact ID.
Target platform project
The target platform project points to the local iDempiere P2 repository so Maven can resolve dependencies.
pom.xml:
<project ...>
<artifactId>org.myplugin.p2.targetplatform</artifactId>
<parent>
<groupId>org.idempiere</groupId>
<artifactId>org.idempiere.parent</artifactId>
<version>7.1.0-SNAPSHOT</version>
<relativePath>../../myexperiment/org.idempiere.parent/pom.xml</relativePath>
</parent>
<packaging>eclipse-target-definition</packaging>
</project>
org.myplugin.p2.targetplatform.target (adjust the repository path):
<target name="idempiere-7.1">
<locations>
<location ... type="InstallableUnit">
<unit id="org.adempiere.base.feature.feature.group"/>
<!-- Add other required feature IDs -->
<repository location="file:///path/to/myexperiment/org.idempiere.p2/target/repository"/>
</location>
</locations>
</target>
Root POM
The root POM at the top of your plug-in directory lists all modules:
<project ...>
<artifactId>myplugin-root</artifactId>
<version>7.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<groupId>org.idempiere</groupId>
<modules>
<module>org.myplugin.feature</module>
<module>org.myplugin.editors</module>
<module>org.myplugin.themes</module>
<module>org.myplugin.p2.site</module>
<module>org.myplugin.p2.targetplatform</module>
</modules>
</project>
Building
From the root directory of your plug-in set, run:
mvn verify -Didempiere.target=org.myplugin.p2.targetplatform
The generated JAR files will be in:
org.myplugin.p2.site/target/repository/plugins/ ← plugin JARs
org.myplugin.p2.site/target/repository/features/ ← feature JARs
Install using the distributing plug-ins guide, pointing to the generated P2 repository.