How to automatically create specific files via Maven to deploy each container?

I am working on a very complex JEE project, which involves the possibility of deploying the application to each client in a different container.

In my development environment I use JBoss, but the production environment can use both JBoss and GlasFish, or even just Tomcat.

I am updating on the subject because it is around 5 years that I do not Program for JEE, in addition to the mentioned, I know that there are others that do not remember the name now.

How can I parameterize Maven to create the proprietary deployment files like jboss-web.xml. Beyond context.xml for Tomcat type containers?

Remembering that there are two types of application, purely WEB (client), EAR (client+agents).

Author: Bruno César, 2015-06-01

1 answers

There are several ways to organize your project with maven modules to do what you need. As already in the comments, you can use filters, profiles , move specific files by profile, etc. I will use a mixture of filters and profiles in a project without any behavior, just to demonstrate this organization.

However there is something (so far I have not found any) that creates specific descriptors by container, such as jboss-web.xml or glassfish-web.xml. So, since there is nothing like this, we will make the changes by modifying properties and copying specific files according to the chosen profile , using only the plugin maven-resources-plugin and the resources of the build itself.

I will divide the answer / suggestion into two parts:

  1. creating the modules, including an EAR that will have both war;
  2. creation of profiles and filters . O profiles will be in the parent module, not because it has to be like this, but because it is personal taste.

Then we will have the following project structure:

Project structure

Below is the summary of each module, with its respective pom.xml containing strictly what is needed at this time. I will assume the following premises:

  • jar-project will be dependent on the two projects of package war;
  • ear-project contains the two projects of package war;

Parent-project :

<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.brunocesar</groupId>
    <version>0.0.1-SNAPSHOT</version>
    <artifactId>parent-project</artifactId>
    <packaging>pom</packaging>

    <build>
        <finalName>${project.artifactId}</finalName>
    </build>

    <modules>
        <module>jar-project</module>
        <module>web-project-1</module>
        <module>web-project-2</module>
    </modules>
</project>

Jar-project :

<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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.brunocesar</groupId>
        <artifactId>parent-project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>jar-project</artifactId>
</project>

Web-project-1:

<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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.brunocesar</groupId>
        <artifactId>parent-project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>web-project-1</artifactId>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>jar-project</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

Web-project-2:

<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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.brunocesar</groupId>
        <artifactId>parent-project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>web-project-2</artifactId>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>jar-project</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

Ear-project :

<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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.brunocesar</groupId>
        <artifactId>parent-project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <packaging>ear</packaging>
    <artifactId>ear-project</artifactId>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.10</version>
                <configuration>
                    <version>7</version>
                    <defaultLibBundleDir>lib</defaultLibBundleDir>
                    <outputDirectory>${project.build.directory}/dist</outputDirectory>
                    <modules>
                        <webModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>web-project-1</artifactId>
                        </webModule>
                        <webModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>web-project-2</artifactId>
                        </webModule>
                    </modules>
                    <fileNameMapping>no-version</fileNameMapping>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>web-project-1</artifactId>
            <version>${project.version}</version>
            <type>war</type>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>web-project-2</artifactId>
            <version>${project.version}</version>
            <type>war</type>
        </dependency>
    </dependencies>
</project>

Now let's build the profilesand filters, you can use only profiles with the properties, but I use both only as an exercise. As we are considering three containers we will have 3 profiles and assume the following:

  • jboss-web.xml will only appear in build when profiles is jboss;
  • glassfish-web.xml will only appear in build when profiles is glassfish;
  • context.xml will only appear in build when profiles is tomcat;
  • tomcat is the default profile ;

As said before, the profiles are all in the pom.xml of the Pooling Project, below are only the snippets of.

Profile jboss :

<profile>
    <id>jboss</id>
    <properties>
        <container>jboss</container>
    </properties>
    <build>
         <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>**/context.xml</exclude>
                    <exclude>**/*-web.xml</exclude>
                </excludes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <overwrite>true</overwrite>
                            <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/</outputDirectory>
                            <resources>
                                <resource>
                                    <filtering>true</filtering>
                                    <directory>${project.basedir}/src/main/resources/WEB-INF</directory>
                                    <excludes>
                                        <exclude>**/glassfish*</exclude>
                                    </excludes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <modules>
        <module>ear-project</module>
    </modules>
</profile>

Profile glassfish :

<profile>
    <id>glassfish</id>
    <properties>
        <container>glassfish</container>
    </properties>
    <build>
        <!-- esta é a parte que iremos dizer para o maven em quais arquivos ele deve usar as propriedades que estão nos filters -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>**/context.xml</exclude>
                    <exclude>**/*-web.xml</exclude>
                </excludes>
            </resource>
        </resources>
        <plugins>
            <!-- usaremos este plugin para incluir os arquivos *-web.xml no lugar correto -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <overwrite>true</overwrite>
                            <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/</outputDirectory>
                            <resources>
                                <resource>
                                    <filtering>true</filtering>
                                    <directory>${project.basedir}/src/main/resources/WEB-INF</directory>
                                    <excludes>
                                        <exclude>**/jboss*</exclude>
                                    </excludes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <modules>
        <module>ear-project</module>
    </modules>
</profile>

Profile tomcat :

<profile>
    <id>tomcat</id>
    <properties>
        <container>tomcat</container>
    </properties>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <build>
        <!-- esta é a parte que iremos dizer para o maven em quais arquivos ele deve usar as propriedades que estão nos filters -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>**/*-web.xml</exclude>
                </excludes>
                <includes>
                    <include>**/context.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</profile>

I haven't exemplified any project with package of type ejb, but you can do this (you probably won't use it, because you're considering tomcat too), i.e. you can package, for example, the package jar in ejb and deploy it along with EAR, as said at the beginning, there are N ways to organize the project.

The build part of pom.xml should also be changed, to something like this:

<build>
    <!-- a construção terá um nome específico por container (ex.: web-project-1-tomcat) -->
    <finalName>${project.artifactId}-${container}</finalName>

    <!-- execução padrão, por isto basta mvn para o tomcat -->
    <defaultGoal>clean package</defaultGoal>

    <!-- aqui é onde estão os filters com as propriedades que serão substituidas nos arquivos xml -->
    <filters>
        <filter>${filter.path}/src/filters/filter-${container}.properties</filter>
    </filters>
    <pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.7</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

Another thing is a property to reference our filter , so include this in the pom.xml of the project-parant:

<properties>
    <filter.path>${project.basedir}</filter.path>
</properties>

And this in the rest pom.xml:

<properties>
    <filter.path>${project.basedir}/..</filter.path>
</properties>

This is an example of filter. They should call themselvesfilter-glassfish.properties, filter-jboss.properties e filter-tomcat.properties:

webapp-1-context=app-1
webapp-2-context=app-2

For the example all have the same content, you can customize as necessary.

Another thing is that you can customize the configuration files the way you want, from using filters, to properties in profiles, by the command line, it is at your discretion.

To run you must do something like the following:

  • for tomcat: mvn
  • for jboss: mvn clean install -P jboss
  • for glassfish: mvn clean install -P glassfish

One last observation is: there is nothing to go the *-web.xml in the other constructions, for the others containers would not even understand it and this service for all other descriptors specific to each container.

Other ways to be done is by using the maven-antrun-plugin(this is pretty cool, personally I like it more because it is less "verbose"), the maven-assembly-plugin or even develop your own plugin , you may decide to write one for you in order to create the specific files by container.

No I know if I was able to answer your question exactly, but I hope I helped=)

 1
Author: Bruno César, 2015-06-02 18:50:01