Cargo + Maven + Two Tomcats
Recently I've been struggling to make Maven execute two Tomcat instances (with different applications on different ports). I decided to put a solution here so you don't have to discover it by yourself.
Goal
The goal was to run two web applications on different ports before integration tests, and once the tests are finished, to stop them.
IMPORTANT If you do not need to run your webapps on different ports than this post is not for you. Simply put more then one webapp under <deployables>
of a single Tomcat instance.
Tools
Maven, Maven Cargo Plugin and Tomcat.
Solution
This is how the first application is started:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<executions>
<execution>
<id>start-first-app</id>
<phase>pre-integration-test</phase>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<zipUrlInstaller>
<url>file:resources/${tomcat.zip.file}</url>
<downloadDir>${project.basedir}/resources</downloadDir>
<extractDir>${project.build.directory}/extracts</extractDir>
</zipUrlInstaller>
<systemProperties>
...
</systemProperties>
<log>${project.build.directory}/first_app.log</log>
</container>
<configuration>
<properties>
<cargo.servlet.port>${first_app.server.port}</cargo.servlet.port>
<cargo.tomcat.ajp.port>${first_app.ajp.port}</cargo.tomcat.ajp.port>
<cargo.rmi.port>${first_app.rmi.port}</cargo.rmi.port>
</properties>
<home>${project.build.directory}/tomcat_first_app</home>
</configuration>
<deployables>
<deployable>
<properties>
<context>ROOT</context>
</properties>
</deployable>
</deployables>
</configuration>
<goals>
<goal>start</goal>
</goals>
</execution>
Things to notice:
containerId
must be equal to one of the containers supported by Cargo - see here for the full listzipUrlInstaller
- I keep zipped Tomcat in SVNsystemProperties
- yeah, you can pass some to the Tomcat if you wish (your application can make use of them)log
- optional. If not set all logs will go to standard output. In case of more than one web app running, it is sometimes more convenient to have separate logs.configuration properties
- this is crucial! Every instance of Tomcat you plan to start during your build must have uniquecargo.servlet.port
andcargo.rmi.port
. Not sure about thecargo.tomcat.ajp.port
but I added it just in case.home
- this is where your Tomcat will be installed.context
- this is how you make your application appear under e.g. http://localhost:8080 instead of http://localhost:8080/myappdeployable
- nogroupId
orartifactId
mentioned here because we deploy the application from this project (which is of typewar
)
Now the configuration for stopping of the first application
<execution>
<id>stop-first-app</id>
<phase>verify</phase>
<configuration>
<container>
<containerId>tomcat7x</containerId>
</container>
<configuration>
<properties>
<cargo.servlet.port>${first_app.server.port}</cargo.servlet.port>
</properties>
<home>${project.build.directory}/tomcat_first_app</home>
</configuration>
</configuration>
<goals>
<goal>stop</goal>
</goals>
</execution>
Three things are identical to the start configuration
containerId
cargo.servlet.port
home
Please notice the phases that were used so far: pre-integration-test
and verify
. For the second application we have to use different phases because Maven for some reasons does not allow the same plugin to be run twice during the same lifecycle phase.
Ok, let us start the second application:
<execution>
<id>start-second-app</id>
<phase>package</phase>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<zipUrlInstaller>
<url>file:resources/${tomcat.zip.file}</url>
<downloadDir>${project.basedir}/resources</downloadDir>
<extractDir>${project.build.directory}/extracts</extractDir>
</zipUrlInstaller>
<systemProperties>
...
</systemProperties>
<log>${project.build.directory}/second_app.log</log>
</container>
<configuration>
<properties>
<cargo.servlet.port>${second_app.server.port}</cargo.servlet.port>
<cargo.tomcat.ajp.port>${second_app.ajp.port}</cargo.tomcat.ajp.port>
<cargo.rmi.port>${second_app.rmi.port}</cargo.rmi.port>
</properties>
<home>${project.build.directory}/tomcat_second_app</home>
</configuration>
<deployer />
<deployables>
<deployable>
<groupId>some.groupId</groupId>
<artifactId>some.artifact</artifactId>
<type>war</type>
<properties>
<context>ROOT</context>
</properties>
</deployable>
</deployables>
</configuration>
<goals>
<goal>start</goal>
</goals>
</execution>
Nothing new here. Some elements are different though:
phase
- it ispacakge
this time - different than previouslylog
- if we specify log files it makes sense to make them different (but remember, this is optional)properties
- servlet, rmi and ajp ports - if they do not differ you will encounter errorshome
- yeah, definitely we need a different directory for this second Tomcatdeployer
- this one is tricky - if you do not specify it, cargo will deploy the current application! (provided that it is of type war or ear)deployable
- this is a different application (I haven't shown it but you also need to add a dependency for the same artifact - can be with thetest
scope.
And now stopping it. There is nothing new here. Notice the different phase (post-integration-test
)!
<execution>
<id>stop-second-app</id>
<phase>post-integration-test</phase>
<configuration>
<container>
<containerId>tomcat7x</containerId>
</container>
<configuration>
<properties>
<cargo.servlet.port>${second_app.server.port}</cargo.servlet.port>
</properties>
<home>${project.build.directory}/tomcat_second_app</home>
</configuration>
</configuration>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
Well, that is it. Good luck with your Maven/Cargo development.
P.S. If you have questions please ask them on appropriate mailing lists.
- Tomek Kaczanowski's blog
- Login to post comments
This used to be my blog. I moved to http://tomek.kaczanowscy.pl long time ago.