Search code examples
mavenweb-applicationstomcat7maven-tomcat-plugin

Tomcat - Maven plugin: run webapps but not current project


The tomcat7-maven-plugin allows running the current project as a Web application and additional <webapps> can be specified that will be simultaneously loaded into tomcat.

My project is not a Web application, but it accesses services that are provided by webapps. So how is it possible to deploy a number of webapps without running the project itself as a webapp? The following Maven snippet results in FileNotFoundExceptions because a context.xml cannot be found.

<plugin>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.0</version>
  <executions>
    <execution>
      <id>run-tomcat</id>
      <phase>${tomcat.run.phase}</phase>
      <goals><goal>run-war-only</goal></goals>
      <configuration>
        <webapps>
          <webapp>
            <contextPath>/my/app1</contextPath>
            <groupId>...</groupId> 
            <artifactId>...</artifactId>
            <version>...</version>
            <type>war</type>    
            <asWebapp>true</asWebapp>
          </webapp>
          ... possibly more webapps ...
        </webapps> 
      </configuration>
    </execution>
    <execution>
      <id>tomcat-shutdown</id>
      <phase>${tomcat.shutdown.phase}</phase>
      <goals><goal>shutdown</goal></goals>
    </execution>
  </executions>
</plugin>

Workaround:

Even though your application itself is not a webapp, you need to configure a path and a contextFile for it:

<configuration>
    <path>/my/non/existing/webapp</path>
    <contextFile>src/test/resources/context.xml</contextFile>
    <webapps>
    ...

The specified context.xml file must exist. The following worked for me, even though the web.xml file does not exist:

<?xml version="1.0" encoding="utf-8"?>
<Context path="/my/non/existing/webapp">
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>

Solution

  • This is probably abusing the tomcat maven plugin but here is a solution I found. BTW your fake context file solution didn't work for me because I needed to run a different webapp and my app is also a webapp.

    There is a jira out there that would provide a better solution to our problem. See https://issues.apache.org/jira/browse/MTOMCAT-228. Now on to my solution...

    First, you need to copy the war to a directory. I suggest the target directory so it can be easily cleaned. Depending on whether you want to support the run or the run-war goals depends on whether you just copy the war or copy the war and unpack it.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <version>${maven-dependency-plugin.version}</version>
      <executions>
        <execution>
          <id>copy-war</id>
          <goals>
            <goal>copy</goal>
          </goals>
          <configuration>
            <artifactItems>
              <artifactItem>
                <groupId>org.foo</groupId>
                <artifactId>bar</artifactId>
                <version>${bar.version}</version>
                <type>war</type>
                <overWrite>true</overWrite>
                <outputDirectory>${project.build.directory}/bar/</outputDirectory>
              </artifactItem>
            </artifactItems>
            <stripVersion>true</stripVersion>
          </configuration>
        </execution>
        <execution>
          <id>copy-war-unpack</id>
          <goals>
            <goal>unpack</goal>
          </goals>
          <configuration>
            <artifactItems>
              <artifactItem>
                <groupId>org.foo</groupId>
                <artifactId>bar</artifactId>
                <version>${bar.version}</version>
                <type>war</type>
                <overWrite>true</overWrite>
                <outputDirectory>${project.build.directory}/bar/bar</outputDirectory>
              </artifactItem>
            </artifactItems>
          </configuration>
        </execution>
      </executions>
    </plugin>
    

    Next, you need to configure the tomcat plugins to look at the directory or war that you just copied to in the above step. The following shows a configuration for tomcat 6 & 7 which is identical other than the artifact id.

    <plugin>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat6-maven-plugin</artifactId>
      <version>${tomcat6-maven-plugin.version}</version>
      <configuration>
        <port>8090</port>
        <path>${default.rice.context.path}</path>
        <warDirectory>${project.build.directory}/bar/bar.war</warDirectory>
        <warSourceDirectory>${project.build.directory}/bar/bar</warSourceDirectory>
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat7-maven-plugin</artifactId>
      <version>${tomcat7-maven-plugin.version}</version>
      <configuration>
        <port>8090</port>
        <path>${default.rice.context.path}</path>
        <warDirectory>${project.build.directory}/bar/bar.war</warDirectory>
        <warSourceDirectory>${project.build.directory}/bar/bar</warSourceDirectory>
      </configuration>
    </plugin>
    

    To be clear you don't need to configure warDirectory or need copy-war execution if you only want to support tomcat:run. Conversely, you don't need to configure warSourceDirectory or need copy-war-unpack execution if you only want to support tomcat:run-war.

    One final note, this dependency copy workaround also works well with the Jetty Maven plugin so if you wanted to support both tomcat & jetty this might be a good way to do it.