2

I'm used to using the E4 Eclipse framework to build desktop applications and now I would like to migrate to a simple maven project.

In the Eclipse platform with OSGi, there is a notion of bundle, feature and product.

When I want to build my project for client A, I have a file A.product describing all the dependencies. For client B, I have B.product and so on.

Of course, my software shares the same base, but if a client wants a new feature (like a plugin) I have to add it to my product file, and the new feature will be discovered at runtime and present to my software.

In maven, I don't find a good way to do the same things, because there is only one pom.xml describing the whole project. How can I introduce modularisation for plugin discovered at runtime?
Should I have multiple POM for each client? Should I use the profile to do that? I tried but I was not easy to manage.

Is there another maven good way to do it, and to manage the variability easily?

Deepak Kumar
  • 1,246
  • 14
  • 38
jojal
  • 67
  • 5
  • Have you seen [Tycho](https://www.eclipse.org/tycho/) already? – Gerold Broser Aug 10 '20 at 19:51
  • Yes I saw tycho but I would like to leave the e4 world and come in the more normal maven way. My need are not about desktop app, so I’m using quarkus with cdi for injection. I would just like to variabilize my Pom.xml. One for client A with N plugins discovered at runtime. And (maybe) another Pom.xml (or profile ?) for client B with N’ Plug-ins discoverer at runtime. – jojal Aug 10 '20 at 22:40
  • You tagged your question with [osgi]. The Tycho main page reads: „_Tycho is a set of Maven plugins and extensions for building [...] OSGi bundles with Maven._“. Maybe there's some other way to build (web or backend or local, not Eclipse) applications based on OSGi with Maven but I haven't seen any other so far. – Gerold Broser Aug 11 '20 at 11:59
  • You're right. I just removed the [osgi] tag, before actually, what i'm looking for is to remove the osgi way. Basically, the question is just : how can create a basic deployment with just A.jar. For example A.jar declare an interface Plugin and i have one implementation of this interface in B.jar and another implementation in C.jar. At the end, i would like to create 2 products. One with A.jar and B.jar, and another one for example with A.jar and C.jar, or A.jar with B.jar and C.jar. Should i create one pom.xml for each deployment ? Or is there a better maven way to do that ? – jojal Aug 11 '20 at 12:17

1 Answers1

1

Re „And (maybe) another Pom.xml (or profile ?)“ in one of your comments to the question:

One of Maven's principles is: one project (declared in a POM), one resulting (main) artifact (JAR, WAR, ...). („main“ since there can be accompanying artifacts like ...-sources.jar, ...-javadoc.jar, ...-jar-with-dependencies.jar, ....zip, ...)

Maven POMs are of declarative nature. That means, there are no (imperative) ifs to skip declarations on occasion and you also can't add/remove declaration (XML) elements during build (you "just" can add/change element text contents via properties). (There are plugins with a <skip>false|true parameter, which can be set/overridden with a property, but that's not a general rule and therefore there are not many of them.)

Profiles are a way to overcome this no-if-principle. With them you can activate ("inject") declarations which set or override existing declarations at build time via various profile activation methods.

Regarding your comment after removing the osgi tag, I'm going to update this answer later. In the meantime you can have a look at my answer to Maven: Lifecycle vs. Phase vs. Plugin vs. Goal.

UPDATE

+- jojal-main
   +- pom.xml   ... contains declarations common for all of your projects
   +- base-main
      +- pom.xml   ... contains declarations common for all base projects
      +- A
         +- src/main/java/your/package/Plugin.java
         +- pom.xml
      +- B
         +- src/main/java/your/package/ClassA.java   ... implements Plugin
         +- pom.xml
      +- C
         +- src/main/java/your/package/ClassB.java   ... implements Plugin
         +- pom.xml
   +- product-main
      +- pom.xml   ... contains declarations common for all product projects
      +- product1
         +- src/main/java/your/package/Product1.java   ... references A & B
         + pom.xml
      +- product2
         +- src/main/java/your/package/Product2.java   ... references A & C
         +- pom.xml
      +- product3
         +- src/main/java/your/package/Product3.java  ... references A & B & C
         +- pom.xml

jojal main POM

<project ...>
  ...

  <groupId>name.jojal</groupId>
  <artifactId>jojal-main</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>  <!-- different to the default 'jar'[1] -->

  <modules>  <!-- to build projects in sub-dirs at once[2] -->
    <module>base-main</module>
    <module>product-main</module>
  </modules>

  ... declarations common for all of your projects like dependencies for unit testing, logging etc. ..

<project>

[1] POM Reference, Packaging
[2] POM Reference, Aggregation

Base main POM

<project ...>
  ...

  <parent>   <!-- declarations are inherited from this parent POM[3] -->
    <groupId>name.jojal</groupId>
    <artifactId>jojal-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>jojal-base-main</artifactId>  <!-- <groupId>, <version> can be omitted if the same as in parent -->
  <packaging>pom</packaging>

  <modules>
    <module>A</module>
    <module>B</module>
    <module>C</module>
  </modules>

  ... declarations common for all base projects ...

<project>

[3] POM Reference, Inheritance

A POM

<project ...>
  ...

  <parent>
    <groupId>name.jojal.base</groupId>
    <artifactId>jojal-base-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
 
  <artifactId>project-a</artifactId>

<project>

B POM

<project ...>
  ...

  <parent>
    <groupId>name.jojal.base</groupId>
    <artifactId>jojal-base-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>project-b</artifactId>

  <dependencies>
    <dependency>
      <groupId>name.jojal.base</groupId>
      <artifactId>project-a</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

<project>

C POM

<project ...>
  ...

  <parent>
    <groupId>name.jojal.base</groupId>
    <artifactId>jojal-base-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
 
  <artifactId>project-c</artifactId>

  <dependencies>
    <dependency>
      <groupId>name.jojal.base</groupId>
      <artifactId>project-a</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

<project>

Product main POM

<project ...>
  ...

  <parent>
    <groupId>name.jojal</groupId>
    <artifactId>jojal-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>jojal-product-main</artifactId>
  <packaging>pom</packaging>

  <modules>
    <module>product1</module>
    <module>product2</module>
    <module>product3</module>
  </modules>

  ... declarations common for all product projects ...

<project>

Product 1 POM

<project ...>
  ...

  <parent>
    <groupId>name.jojal.product</groupId>
    <artifactId>jojal-product-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>product-1</artifactId>

  <dependencies>
    <dependency>
      <groupId>name.jojal.base</groupId>
      <artifactId>project-b</artifactId>  <!-- project-a is resolved automatically by Maven
                                               as a transitive dependency[4] -->
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

<project>

[4] POM Reference, Dependencies

Product 2 POM

<project ...>
  ...

  <parent>
    <groupId>name.jojal.product</groupId>
    <artifactId>jojal-product-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>product-2</artifactId>

  <dependencies>
    <dependency>
      <groupId>name.jojal.base</groupId>
      <artifactId>project-c</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>

<project>

Product 3 POM

<project ...>
  ...

  <parent>
    <groupId>name.jojal.product</groupId>
    <artifactId>jojal-product-main</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>product-3</artifactId>

  <dependencies>

    <dependency>
      <groupId>name.jojal.base</groupId>
      <artifactId>project-b</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
      <groupId>name.jojal.base</groupId>
      <artifactId>project-c</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>

  </dependencies>

<project>

[Please note: Not tested in real, typos possible]

Gerold Broser
  • 14,080
  • 5
  • 48
  • 107
  • 1
    Wow great answer ! It is exactly what i would like to achieve. Thank you for this great answer with a lot of details and references. – jojal Aug 12 '20 at 11:12
  • Is there a way to skip the build of all the products when we do "mvn clean package" at the jojal-main ? If i ask this question it's to avoid to rebuild all client project each time. Maybe another idea would be to split in different repository ? – jojal Aug 12 '20 at 11:26
  • You're welcome. Change into the dir `/base-main` and run `mvn ...` there. Only the modules declared in POM `jojal-base-main` will be built then. And this also applies to "leaf" projects, generally every project, in the tree: Change to dir `B`, run `mvn ...` there and only `project-b` will be built. An alternative is [`mvn -f /path/to/pom.xml`](https://books.sonatype.com/mvnref-book/reference/running-sect-options.html) from anywhere. – Gerold Broser Aug 12 '20 at 12:29
  • 1
    Great, everything works perfectly now. Thank you for your help. My last problem with maven is to share my application.properties which is in the base-main in all products to share a global configuration, but i think it's out of scope of the initial problem :) Thank you again. Very helpful. – jojal Aug 12 '20 at 12:53