Skip to main content

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>
tip
  • Do not add a <groupId> to the feature project POM.
  • The <artifactId> in the POM must match the id attribute in feature.xml.
  • Use eclipse-feature as 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
tip
  • The <artifactId> in the POM must match Bundle-SymbolicName in MANIFEST.MF.
  • Use eclipse-plugin as 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: /
tip

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>
tip

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.