Prometheus

Maven + Cargo + Tomcat = Auto-deployment

Posted in technical by dpillay on April 12, 2009

I’ve been using Maven as the build / dependency management tool for a project I’ve been working on. After tweaking the initial maven setup and finally getting all my dependencies in place, I had a nifty build system for my project.

As I kept working on the project, the frustration of having to build the webapp and deploy it to Tomcat manually was getting on my nerves. It was easy enough to build a small script that took my latest war snapshot and deployed it to Tomcat. This eased some of my pain but then I started wondering whether Maven had any plugin to do exactly this. And voila, I found two! Namely – the Tomcat Maven plugin and the Cargo plugin.

I first test drove the Tomcat Maven plugin not knowing that it actually deploys its own instance of Tomcat. This was not what I needed. My local Tomcat instance was tweaked to exactly how I wanted it and I didn’t want a new instance hence I just gave up. I’m sure I could have made changes to the embedded instance of the plugin but I just wasn’t in the mood.

That’s when I turned to Cargo. After going through their site a bit, I realized that it was exactly what I was searching for. But boy, was I in for a tough time. With all due credit to Cargo, their documentation is really bad. One shouldn’t document with the intent of just ‘covering’ a particular feature. The incomplete xml’s on the site were really annoying. I think they could learn a thing or two from the Spring community whose documentation is one of the most brilliant I have worked with. I know they are just starting out with the plugin but if they don’t document, people will just turn away.

My use case was simple. One of the modules in my project needed to be deployed to a ‘local’ instance of Tomcat and consequently I needed to launch Tomcat. Though Cargo seemed to be able to handle this, getting it to work properly took me through 10 odd articles and numerous pages of half baked documentation on the Cargo site.

Eventually though, I got it working which is exactly what I want to share here.

Lets start with the project structure:-

  • <project_ root>
    • pom.xml 1
    • <module1-core>
      • pom.xml 2
    • <module2-webapp>
      • pom.xml 3
    • <module3-deployer>
      • pom.xml 4

1 – This is the parent / root pom. It basically contains the fact that the project consists of 3 modules (basic maven terminology, nothing to do with Cargo yet)
2 – This pom contains the description and dependencies for the core service module. Again normal maven structure
3 – This pom contains the description and dependencies for the webapp module. This module depends on the core module.
4 – This pom is where our Cargo related details go which is the focus of this article.

Let me now begin to detail the module3-deploy’s pom.xml. First off, since we need to deploy the snapshot of module2-webapp, we need to add that as a dependency for moduel3-deploy. Dependencies form a core part of the maven system and are achieved using the <dependencies> tag detailed as below:-

<dependencies>
	<dependency>
		<groupId>com.example</groupId>
		<artifactId>module2-webapp</artifactId>
		<version>1.0-SNAPSHOT</version>
		<type>war</type>
	</dependency>
</dependencies>

Next come’s the <build> tag which contains the meat of the Cargo configuration:-

<!-- Configuration for the Maven build -->
<build>
	<!-- The plugins tag as mandated by maven -->
	<plugins>
		<!-- Start's the plugin tag for Cargo! -->
		<plugin>
			<!-- Cargo Group Id -->
			<groupId>org.codehaus.cargo</groupId>
			<!-- Cargo's Artifact Id -->
			<artifactId>cargo-maven2-plugin</artifactId>
			<!-- This the most important part of the setup -->
			<configuration>
				<!--
					When Cargo starts the container, the following tag instructs it to
					wait for you to kill the session with Crtl-C
				-->
				<wait>true</wait>
				<!--
					The following tag details the container you want to
					deploy to.
				-->
				<container>
					<!--
						Specifying "tomcat6x" is very important! This one tripped me up
						for quite a while. The issue is that instead of being an
						identifier for you, "tomcat6x" is an identifier for Cargo that
						you want to deploy your webapp in Tomcat 6.x. I had initially
						thought otherwise and hence just dropped the 'x', making it
						"tomcat6", but that never worked.
					-->
					<containerId>tomcat6x</containerId>
					<!--
						Type == Installed means that you want to deploy to a container
						that's installed on your computer
					-->
					<type>installed</type>
					<!-- The home folder for your local Tomcat -->
					<home>${catalina.home}</home>
				</container>
				<configuration>
					<!--
						This is another one that confused me for long. Its not enough to
						specify 'installed' in the container tag. You have to now specify
						another configuration with type == existing and re-issue the home
						path
					-->
					<type>existing</type>
					<home>${catalina.home}</home>
				</configuration>
				<!--
					Cargo has the notion of a 'deployer' in which you specify
					'deployables'
				-->
				<deployer>
					<!-- You have to again specify that the type for the deployer -->
					<type>installed</type>
					<deployables>
						<!-- This deployable specifies the webapp you want to deploy -->
						<deployable>
							<groupId>com.dpillay.oworld</groupId>
							<artifactId>oworld-webapp</artifactId>
							<type>war</type>
						</deployable>
					</deployables>
				</deployer>
			</configuration>
			<!--
				Executions specify the targets that you want to run during build
			-->
			<executions>
				<!--
					Maven has the concept of a 'phase' which can be thought of a
					collection of goals. Hence here we are specifying that during the
					'install' phase first deploy the webapp to the container specific
					folder and then start the container. Both 'deployer-deploy' and
					'start' are cargo specific goals.
				-->
				<execution>
					<id>verify-deploy</id>
					<phase>install</phase>
					<goals>
						<goal>deployer-deploy</goal>
						<goal>start</goal>
					</goals>
				</execution>
				<!--
					Specifying that during the 'pre-clean' phase, Cargo should first
					stop the container.
				-->
				<execution>
					<id>clean-undeploy</id>
					<phase>pre-clean</phase>
					<goals>
						<goal>stop</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

And that’s it! You can now issue a ‘mvn install’ from the project root which will deploy your latest webapp snaphot and start the container!

Cargo is still in the initial phases of its development but I’m sure more good things will come out. For one thing, the <wait> is an irritation. I haven’t been able to tell Cargo to fork the tomcat process and then return to the command prompt. Instead if you specify <wait>true</wait>, it loads tomcat as part of the maven process and expects a ‘Ctrl-C’ to get back to the prompt or if you specify wait as false, it just shuts down the maven process which in turn brings down the container.

Cargo’s Maven documentation keeps throwing an error when I try to access any of the tag’s documentation. Fortunately I found the same documentation over here.

You can get download the entire XML here.

Tagged with: , , , ,

25 Responses

Subscribe to comments with RSS.

  1. Pedro said, on April 13, 2009 at 22:52

    Have you considered the maven jetty plugin? Jetty is a lightweight web/jsp/servlet server that does autoreloading when the code in your war changes. It makes it much faster to develop than cargo.

    I have been using it actively for the past 3 years and I find it quite useful🙂

  2. kati said, on August 13, 2009 at 18:42

    hello dpillay,

    thanks for this blog but I cannot get running cargo + maven2 + tomcat6. I still (also after your method has been applied) get following error:

    [INFO] Failed to create configuration for the parameters (container [id = [tomcat6x], type = [installed]], configuration type [existing]).
    The configuration home parameter must be specified for existing configurations
    [INFO] ————————————————————————
    [INFO] Trace
    org.codehaus.cargo.container.ContainerException: Failed to create configuration for the parameters (container [id = [tomcat6x], type = [inst
    alled]], configuration type [existing]).
    at org.codehaus.cargo.generic.spi.AbstractGenericHintFactory.createImplementation(AbstractGenericHintFactory.java:157)
    at org.codehaus.cargo.generic.spi.AbstractIntrospectionGenericHintFactory.createImplementation(AbstractIntrospectionGenericHintFacto
    ry.java:86)

    more exception rows ….

    Caused by: org.codehaus.cargo.container.ContainerException: The configuration home parameter must be specified for existing configurations
    at org.codehaus.cargo.generic.configuration.DefaultConfigurationFactory.createInstance(DefaultConfigurationFactory.java:438)
    at org.codehaus.cargo.generic.spi.AbstractGenericHintFactory.createImplementation(AbstractGenericHintFactory.java:153)
    … 28 more
    org.codehaus.cargo.container.ContainerException: The configuration home parameter must be specified for existing configurations
    at org.codehaus.cargo.generic.configuration.DefaultConfigurationFactory.createInstance(DefaultConfigurationFactory.java:438)
    at org.codehaus.cargo.generic.spi.AbstractGenericHintFactory.createImplementation(AbstractGenericHintFactory.java:153)
    at org.codehaus.cargo.generic.spi.AbstractIntrospectionGenericHintFactory.createImplementation(AbstractIntrospectionGenericHintFacto
    ry.java:86)

    more exception rows ….

    Do you have any idea?
    thank you very much
    kati

  3. kati said, on August 13, 2009 at 18:45

    @pedro:
    do you know how to use jetty for web applications? I need support regarding tomcat applications using tomcat-specific context.xml. See also:

    http://dev.eclipse.org/mhonarc/lists/jetty-dev/msg00246.html

    The main issue is that the servlets cannot access the Context object (you know … Context appCtx = (Context)(new InitialContext()).lookup(“java:comp/env”);) properly because this seems to be not handled by jetty.

    do you know how to solve this issue?
    kati

  4. Innar said, on August 19, 2009 at 10:57

    Thanks for this post! I found the configuration very useful and comprehensible with your comments.

  5. Jose Maria said, on September 2, 2009 at 15:33

    Hey, I’m trying to do this using an installed Tomcat on my computer. Whenever I try to execute one of the cargo goals, this is what I get:

    Cannot create configuration. The pair (container id [tomcat6x], configuration type [existing]) has not been registered.

    Do you know what the reason could be? It’s driving me nuts! I wish that I could use jetty, but I’m using a modified version of Tomcat, so that’s not possible.

    Thanks!

  6. Seshu said, on October 30, 2009 at 22:00

    This article is of great help to me i was just looking to deploy my war to a local tomcat instance for development environments. One thing i wanted to know was how to deploy to another folder besides \tomcat\webapps cause we have a context in server.xml which points to a docBase and we want the plugin to deploy to this location in exploded format. Currently this deploys the war into \tomcat\webapps and doesn’t explode it.

  7. Andreas Westh said, on November 18, 2009 at 08:55

    Is it possible to copy the war-file to another directory without starting or restarting the server?
    I would prefer to manage the tomcat server in Eclipse

  8. John Cheng said, on November 25, 2009 at 02:49

    I just want to say thank you so much for sharing your configuration! I had a real difficult time following the Maven documentation on Cargo’s site.

    The nested “configuration/home” element was a doozy! I found that if you do this, you do not need a “” element under the container element.

    cargo-maven2-plugin:1.0

  9. Milin Shah said, on February 22, 2010 at 09:58

    Hi,

    Good job!
    The post is very useful and thanks a lot for it.
    Currently I have given it static like “D:/Tomcat6”.
    But I want to give it as parameter when run the “mvn install”.
    How can i achieve it?

    • Milin Shah said, on February 22, 2010 at 10:39

      I got the solution.
      ${tomcat_path}

      and while running maven provide parameter mvn -Dtomcat_path=D:/Tomcat6

      Thanks!

  10. mochisoft said, on March 8, 2010 at 15:38

    Thanks, This was very helpful.

  11. Amit Pugalia said, on March 25, 2010 at 11:58

    Thanks a ton. Yes the Cargo documentation isn’t at all helpful. They should link to this documentation of yours in their “Getting Started” section.

  12. Amit Pugalia said, on March 25, 2010 at 13:22

    I get the following error on executing, mvn install -e -Dtomcat_path=”C:\Program Files\Apache Software Foundation\Tomcat 6.0″

    INFO] ————————————————————————
    ERROR] BUILD ERROR
    INFO] ————————————————————————
    INFO] Failed to configure plugin parameters for: org.codehaus.cargo:cargo-maven2-plugin:1.0.1-alpha-2

    Cause: Cannot find setter nor field in org.codehaus.cargo.maven2.configuration.Deployable for ‘packaging’
    INFO] ————————————————————————
    INFO] Trace
    rg.apache.maven.lifecycle.LifecycleExecutionException: Error configuring: org.codehaus.cargo:cargo-maven2-plugin. Reason: Unable to parse the created DOM for plugin configuration
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:723)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:535)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
    at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
    at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
    at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
    aused by: org.apache.maven.plugin.PluginConfigurationException: Error configuring: org.codehaus.cargo:cargo-maven2-plugin. Reason: Unable to parse the created DOM for plugin configuration
    at org.apache.maven.plugin.DefaultPluginManager.populatePluginFields(DefaultPluginManager.java:1363)
    at org.apache.maven.plugin.DefaultPluginManager.getConfiguredMojo(DefaultPluginManager.java:724)
    at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:468)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
    … 17 more
    aused by: org.codehaus.plexus.component.configurator.ComponentConfigurationException: Cannot find setter nor field in org.codehaus.cargo.maven2.configuration.Deployable for ‘packaging’
    at org.codehaus.plexus.component.configurator.converters.ComponentValueSetter.(ComponentValueSetter.java:68)
    at org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter.processConfiguration(ObjectWithFieldsConverter.java:134)
    at org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter.fromConfiguration(ObjectWithFieldsConverter.java:90)
    at org.codehaus.plexus.component.configurator.converters.composite.ArrayConverter.fromConfiguration(ArrayConverter.java:135)
    at org.codehaus.plexus.component.configurator.converters.ComponentValueSetter.configure(ComponentValueSetter.java:247)
    at org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter.processConfiguration(ObjectWithFieldsConverter.java:137)
    at org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter.fromConfiguration(ObjectWithFieldsConverter.java:90)
    at org.codehaus.plexus.component.configurator.converters.ComponentValueSetter.configure(ComponentValueSetter.java:247)
    at org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter.processConfiguration(ObjectWithFieldsConverter.java:137)
    at org.codehaus.plexus.component.configurator.BasicComponentConfigurator.configureComponent(BasicComponentConfigurator.java:56)
    at org.apache.maven.plugin.DefaultPluginManager.populatePluginFields(DefaultPluginManager.java:1357)
    … 20 more
    INFO] ————————————————————————

  13. Stephen said, on June 8, 2010 at 16:53

    This is an AWESOME write up! Thank you so much!

    A trick I picked up on a different site is to set tomcat.home in settings.xml.
    e.g.

    /path/to/tomcat

    That way each developer can have tomcat installed wherever they would like to have it.

  14. sten17 said, on August 9, 2010 at 16:43

    Thank you for very useful post. Have you any idea how to run exploded directory instead war? Documentation is terrible and I don’t know what do. Thank you.

  15. Mike said, on October 14, 2010 at 11:31

    Fantastic post. worked for me straight away (well after I specified catalina.home with:

    <properties>
    <catalina.home>/usr/local/tomcat
    </properties>

    so thank you

  16. Mike said, on January 16, 2011 at 05:24

    Awesome tutorial, it got me going…love your work.

    Only one issue, cargo doesn’t seem to clean the target directory. That is if I stop the process, and run mvn clean install. It doesn’t redeploy the webapp, because the old one is still there.

    so how do I get it to clean the old web app out?

    • dpillay said, on January 21, 2011 at 08:40

      Mike, please add the “deployer-undeploy” goal to the pre-clean phase (execution id “clean-undeploy”) before the “stop” goal.

      That should do it🙂

      • jpfguerra said, on February 16, 2011 at 18:59

        Hello, and thank you for the great tutorial.

        For some reason, the “deployer-undeploy” only deletes the .war file… The exploded directory created by tomcat remains there.

        This is a problem because tomcat doesn’t realize that there’s a new .war and doesn’t replace the exploded directory with the .war new content.

        Do you know how I can solve this?

    • Kalle Tjärnlund said, on September 25, 2012 at 22:51

      Now I’m just one and a half year late but maybe someone runs into the same problem…. Since cargo does not delete the exploded war you can either configure tomcat not to explode the war or you can add a plugin wich delete the exploded directories like:

      org.codehaus.mojo
      exec-maven-plugin
      1.2.1

      clean-tomcat-webapps
      pre-clean

      rm

      -R
      ${catalina.home}/webapps/ROOT
      ${catalina.home}/webapps/ws

      exec


      ${catalina.home} points to my tomcat installation dir.

  17. sundaypink said, on April 26, 2011 at 16:23

    Hi,

    I have a little question about the mvn cargo:start.
    if I am not mistaken when we type the mvn install it will also trigger the mvn cargo:start.
    But then in my case, the build is successfull but my tomcat is not started. Everytime I go to the url such as localhost:8080/somewebapp then it will return

    The requested resource () is not available.

  18. HeatoN said, on October 24, 2011 at 15:34

    Great tutorial, really helpful !!

    Thanks a lot🙂

  19. zonesecretsanta said, on December 15, 2011 at 12:55

    With all due credit to Cargo, their documentation is really bad. One shouldn’t document with the intent of just ‘covering’ a particular feature. The incomplete xml’s on the site were really annoying.

    True, I was in the same position as u r until I found ur this post. Thanks, its very helpful

  20. sree said, on May 21, 2012 at 20:03

    Very good article, but i am unable to configure tomcat7. Followed all the steps .. but still running into issues. If anyone of you configured for tomcat7. can you pl post configuration parameters.
    Error is ” No container defined, using a default [jetty6x, embedded] container” , starts jetty.
    Here is my configuration

    i didn’t define deployer/executions as i i hv configured tomcat to point to my app directory..
    I also noticed following warning..
    Failed to retrieve plugin descriptor for org.codehaus.mojo:cargo-maven2-plugin:1.2.1-SNAPSHOT: Plugin org.codehaus.mojo:cargo-maven2-plugin:1.2.1-SNAPSHOT or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.codehaus.mojo:cargo-maven2-plugin:jar:1.2.1-SNAPSHOT

    org.codehaus.mojo
    cargo-maven2-plugin

    1.2.1-SNAPSHOT

    true

    tomcat7x
    installed
    /Library/Tomcat/apache-tomcat-7.0.26

    existing
    /Library/Tomcat/apache-tomcat-7.0.26

    Thanks for your help

  21. Ravi said, on October 30, 2013 at 09:45

    One change to be made in the pom.xml (I am using version 1.4.5). The deployables node cannot come under deployer node. Move it outside to come under configuration node


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: