Search code examples
mavenwarmaven-tomcat-plugin

tomcat-maven-plugin with multi module and war overlay


I have a maven war project (call it projectA) that depends on another maven war (call it projectB). They get integrated using an overlay with the maven-war-plugin. Both projects have the same parent and the same aggregator (different from the parent). I can package the final war successfully without any issue. This is the command I'm running to do that (I'm at the aggregator level when running mvn):

mvn -am -pl projectA package

The reactor build order is parentprojectBprojectA and all is fine.

I'm now trying to use the tomcat-maven-plugin in this build. So I added the tomcat-maven-plugin in the parent pom pluginManagement section and used it in the projectA pom. I'm launching tomcat with:

mvn -am -pl projectA tomcat:run

The reactor build order remains the same. But the tomcat execution is run on projectB (which is also a war) and not on projectA. Actually, projectA build is not even reached.

I've tried with both the org.codehaus.mojo.tomcat-maven-plugin v1.1 and org.apache.tomcat.maven.tomcat6-maven-plugin v2.1, I've found the same behavior.

How can I make tomcat run the final projectA?

Note: The project dependencies are in fact a bit more complicated and there are other sub-projects involved (jars), that's why I'm calling maven with -am (also make).


Solution

  • Ok, so I found a solution. It is to disable the maven-tomcat-plugin for the pojectB, this answer is based on this other question.

    Linking the plugin to a specific phase

    First I had to link the maven-tomcat-plugin to a phase of my build cycle, so that it is called even if I don't call the plugin directly from the CLI, obviously I choose the integration-test phase. I can now run mvn integration-test -pl projectA to have tomcat being launched with the just build war.

    This is how the plugin is declared in the parent:

    <pluginManagement>
    <plugins>
    <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat6-maven-plugin</artifactId>
        <version>2.1</version>
        <executions>
           <execution>
               <id>run-war</id>
               <!-- We link this plugin to some non default phase so that we can disable it in some modules. -->
               <phase>integration-test</phase>
               <goals>
                   <goal>run-war</goal>
               </goals>
           </execution>
        </executions>
    </plugin>
    </plugins>
    </pluginManagement>
    

    and in projectA I just make use of it as declared in the parent:

    <build>
    <plugins>
    <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat6-maven-plugin</artifactId>
    </plugin>
    </plugin>
    </build>
    

    Deactivating the plugin in projectB

    Then, in projectB, I link the same plugin (with the same id) to a null/void/empty phase, which ends up disabling the plugin for this project when built for this integration-test phase:

    <build>
    <plugins>
    <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat6-maven-plugin</artifactId>
        <executions>
            <execution>
                <id>run-war</id>
                <!-- We don't want this plugin to be called from another module build -->
                <phase/>
            </execution>
        </executions>
    </plugin>
    </plugins>
    </build>
    

    With that setup, I can now do a complete build (both projectB, projectA and other dependencies) and launch tomcat with the resulting war in a single run:

    mvn -am -pl projectA clean integration-test