0

I have a project with the following conceptual structure:

-- Core project: Contains the main() function
---- Feature A
---- Feature B
---- Feature C
---- etc.

I am looking for a way to tell maven the following:

mvn package core--with--featureA--and--featureC

This example would create an executable JAR file starting from the Core's main, and having features A and C also packaged/assembled, but not feature B and others.

While the JAR is launched, the main method should be able to know what features are installed and bootstrap them all, for eg.:

main() {
  for(Runnable featureStarter : FeatureList.getFeatures()) { // Gets all features assembled by maven, which are now present in runtime
     featureStarter.run(); // Starts each feature
  }
}

or, a more rustic/hard-coded example (less preferred):

main() {
  if(isInstalled("FeatureA"))
     FeatureA.start();

  if(isInstalled("FeatureB"))
     FeatureB.start();

  if(isInstalled("FeatureC"))
     FeatureC.start();

}

Is this somehow possible?

Thanks!

PedroD
  • 5,670
  • 12
  • 46
  • 84
  • Are you looking for jars that run under different environments or just a single jar that will detect a missing dependency and disable a certain feature – Narrim Dec 08 '16 at 01:13
  • Maven has projects and then modules..so you could create 2 release modules that depend on the base project. Each would assemble differently it would be up to your main function to check for the missing classes in a feature and disable or enable the feature – Narrim Dec 08 '16 at 01:14
  • It has nothing to do with the environment, it is more like dependency. I think we can see features as dependencies. I don't know, would it be the best way to achieve this with maven? – PedroD Dec 08 '16 at 01:16
  • I see. I will try to find an example working with release modules. – PedroD Dec 08 '16 at 01:20
  • This question may provide some additional light to the how maven works when you want to filter http://stackoverflow.com/questions/2424015/maven-best-practice-for-generating-multiple-jars-with-different-filtered-classes?rq=1 – Narrim Dec 08 '16 at 01:50

3 Answers3

1

Maven has projects and then modules..so you could create 2 release modules that depend on the base project. They can release a different jar.

The module below has only configuration files in its source. It builds the app based around the inclusion of dependencies. It also extract other properties from those dependencies to use in its build.

The problem you will have with this is that you will need to use reflection to avoid build problems in your main app. ie it wont compile if it cant resolve an inclusion.

Ie FeatureA.start()

public void Start(){
try {
            clazz = Class.forName("org.group.ComponentA");
        } catch (ClassNotFoundException e) {
            if (fallbackOk) {
                clazz = Class.forName("org.group.Component");
            } else {
                throw e;
            }
        }

}

POM below

 <?xml version="1.0" encoding="UTF-8"?>   
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>parent-artifact</artifactId>
        <groupId>com.group</groupId>
        <version>1.9</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>child-artifact</artifactId>
    <packaging>war</packaging>

    <name>Child Jar</name>
    <build>
        <finalName>Child</finalName>
        <resources>
            <resource>
                <directory>${basedir}/src/conf/log4j</directory>
                <includes>
                    <include>log4j.properties</include>
                </includes>
            </resource>
            <resource>
                <directory>${basedir}/src/conf/hibernate</directory>
                <includes>
                    <include>hibernate.properties</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <!-- extracts the messages*.properties files from to a staging area -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>com.group</groupId>
                                    <artifactId>componentA</artifactId>
                                    <version>${project.version}</version>
                                    <type>jar</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}/localisation</outputDirectory>
                                    <includes>**/messages*.properties</includes>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>com.group</groupId>
                                    <artifactId>componentB</artifactId>
                                    <version>${project.version}</version>
                                    <type>war</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}/webapp/webstart</outputDirectory>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <!-- copies the messages*.properties files to classes/localisation -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/classes/localisation</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${basedir}/target/localisation/org/group/web/resource/localisation/
                                    </directory>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                    <execution>
                        <!-- copy webapp for tomcat plugin -->
                        <id>webapp</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/webapp</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${basedir}/src/webapp/</directory>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <warSourceDirectory>
                        ${basedir}/src/webapp
                    </warSourceDirectory>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                    <overlays>
                        <overlay>
                            <groupId>org.group</groupId>
                            <artifactId>componentC</artifactId>
                            <targetPath>webstart</targetPath>
                        </overlay>
                    </overlays>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-source-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat6-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <server>app-tomcat</server>
                    <!--port>${maven.tomcat.port}</port-->
                    <path>/${project.build.finalName}</path>
                    <warSourceDirectory>${basedir}/target/webapp</warSourceDirectory>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>${jdbc.groupId}</groupId>
                        <artifactId>${jdbc.artifactId}</artifactId>
                        <version>${jdbc.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <server>app-tomcat</server>
                    <!--port>${maven.tomcat.port}</port-->
                    <path>/${project.build.finalName}</path>
                    <warSourceDirectory>${basedir}/target/webapp</warSourceDirectory>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>${jdbc.groupId}</groupId>
                        <artifactId>${jdbc.artifactId}</artifactId>
                        <version>${jdbc.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <!-- for jetty plugin dependencies -->
            <id>java.net</id>
            <url>http://download.java.net/maven/2/</url>
            <snapshots>
                <enabled>false</enabled>
                <checksumPolicy>fail</checksumPolicy>
                <updatePolicy>never</updatePolicy>
            </snapshots>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>org.group</groupId>
            <artifactId>componentA</artifactId>
        </dependency>
        <dependency>
            <groupId>org.group</groupId>
            <artifactId>componentB</artifactId>
        </dependency>
    </dependencies>

    <properties>
    </properties>

</project>
Narrim
  • 567
  • 8
  • 22
1

Is it possible for Maven to assembly executable JARs with different configurations?

Yes it is. One relatively simple way to do this is by using maven-assembly-plugin

While the JAR is launched, the main method should be able to know what features are installed

This has nothing to do with Maven. It seams you are trying to build your own module system. While it is not strictly wrong to do so, you may want to consider an existing solutions that already do that:

  • Java's service loader can be one way to approach that (in relatively simple cases).
  • OSGi is de facto standart for modular Java applications. I know a lot of people will argue (due to outdated knowledge perhaps) it's too heavy/complex, but that is really no longer the case. In case you want to go that way and benefit from the power of real modularity, you could check this base tutorial which bulds multi-module application. The example uses bndtools but you could do the same with Maven.
Milen Dyankov
  • 2,972
  • 14
  • 25
  • I have used osgi for years and quit this year because of the dependency hell issue and all the overhead of managing bundles. – PedroD Dec 08 '16 at 09:02
1

Why make it complicated when you can make it simple !

Pom Core project:

<profile>
            <id>active-Feature-A</id>
         ...
         ...            
</profile>          

<profile>
            <id>active-Feature-B</id>
         ...
         ...            
</profile>  

<profile>
            <id>active-Feature-C</id>
         ...
         ...            
</profile>  

Then:

mvn package -Pactive-Feature-A,active-Feature-B
halfer
  • 19,824
  • 17
  • 99
  • 186
question_maven_com
  • 2,457
  • 16
  • 21