1

I am having issues deploying a web application on an embeded Tomcat 7 with the maven-cargo-plugin. I created a new maven profile in the webapps pom that creates a Tomcat container via the maven-cargo-plugin and then executes a soapui test case via the soapui-maven-plugin.

The webapp connects to some IBM WebSphere MQs therefore I have overwritten some of the containers config files:

  • added the MQs as Resources to server.xml for JNDI lookup
  • added my custom applicationContext.xml to the classpath by overriding the web.xml
  • added the needed Resources in the context.xml that are needed to connect to the MQs
  • added the path to the lib directory of a locally installed IBM Websphere MQClient to the containers common.loader so that its libs can be used by the container

Furthermore I copied the needed websphere.mq.*.jar files and j2ee-1.4.jar from a local WebsSphere Server installation to the Tomcat containers lib directory by adding them via cargos <file> tag.

Now when I startup Maven with this command (where runITs activates the created profile):

clean verify -U -Dhttps.protocols=TLSv1,SSLv3 -DrunITs -X

The deploy fails with:

INFO] [talledLocalContainer] org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/cargocpc]]
[INFO] [talledLocalContainer]   at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
[INFO] [talledLocalContainer]   at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
[INFO] [talledLocalContainer]   at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
[INFO] [talledLocalContainer]   at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
[INFO] [talledLocalContainer]   at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1081)
[INFO] [talledLocalContainer]   at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1877)
[INFO] [talledLocalContainer]   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
[INFO] [talledLocalContainer]   at java.util.concurrent.FutureTask.run(FutureTask.java:262)
[INFO] [talledLocalContainer]   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
[INFO] [talledLocalContainer]   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
[INFO] [talledLocalContainer]   at java.lang.Thread.run(Thread.java:745)
[INFO] [talledLocalContainer] Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getClassLoader()Ljava/lang/ClassLoader;
[INFO] [talledLocalContainer]   at org.apache.catalina.startup.WebappServiceLoader.load(WebappServiceLoader.java:90)
[INFO] [talledLocalContainer]   at org.apache.catalina.startup.ContextConfig.processServletContainerInitializers(ContextConfig.java:1577)
[INFO] [talledLocalContainer]   at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1281)
[INFO] [talledLocalContainer]   at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:889)
[INFO] [talledLocalContainer]   at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:386)
[INFO] [talledLocalContainer]   at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
[INFO] [talledLocalContainer]   at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
[INFO] [talledLocalContainer]   at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5412)
[INFO] [talledLocalContainer]   at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
[INFO] [talledLocalContainer]   ... 10 more

I already tried to search for possible solutions and f. e. tried the solution provided here: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String;

but I could rule out the possible causes because:

  • my container is Tomcat 7 and therefore supports Servlet API 2.5
  • the web.xml complies Servlet API 2.5
  • There are no j2ee.jar or servlet-api.jar files in WEB-INF/lib or JRE/lib

After making sure my setup complies these three points I still get the error mentioned above.

Does anyone know what else could cause this?

Community
  • 1
  • 1
  • I guess that the j2ee-1.4.jar which you copy, contains ServletContext class, which is incompatible with Tomcat7. Can you replace it with some other dependency, which would contain just classes you need? – Karel Suta Sep 14 '16 at 14:59
  • Thanks for putting me in the right direction. Seems like the Tomcat tries to use this method which exists only in servlert-api-3.0 or higher. I figured out a workaround – Fabian Brandes Sep 15 '16 at 12:16

2 Answers2

1

The first answer to the question bound the build to a concrete setup on a local machine. One may be able to replicate that on a build server but it will be clumsy and error prone. I personally prefer to configure build so it works without any external dependency. I also had to compromise on that when we needed to run database migration or when we wanted to test RabbitMQ and there was no embedded broker available but at least the app run was self-contained.

Hence, if I were you I would dig deeper and make a configuration that is able to handle your use case without such a local folder. I cannot provide working answer for you since I lack information (your cargo configuration). But I would point you to the org.apache.tomcat.maven.tomcat7-maven-plugin. It worked very well for us. I used Cargo on another project and I find the tomcat7 plugin easier to use.

You can provide your own server.xml: Run Tomcat and deploy project with own server.xml

You can specify (add/override) dependencies in the <dependencies> section - which should solve your servlet-api version problem.

You can add a custom configuration (say some properties files which we put in the lib folder to get them on classpath) by adding them as a dependency in a jar.

It's quite versatile and simple way to get embedded Tomcat up and running. Hope that can help you.

Maybe to give you some primer on the tomcat7 plugin config:

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <executions>
        <execution>
            <id>tomcat-run</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>run-war-only</goal>
            </goals>
            <configuration>
                <webapps>
                    <webapp>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>project-web</artifactId>
                        <version>${project.version}</version>
                        <type>war</type>
                        <asWebapp>true</asWebapp>
                        <contextPath>/project-path</contextPath>
                    </webapp>
                </webapps>
                <protocol>org.apache.coyote.http11.Http11NioProtocol</protocol>
                <port>${app.port}</port>
                <fork>true</fork>
            </configuration>
        </execution>
        <execution>
            <id>tomcat-shutdown</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>shutdown</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>project-test-config</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jacoco</groupId>
            <artifactId>org.jacoco.agent</artifactId>
            <version>${jacoco.version}</version>
            <classifier>runtime</classifier>
        </dependency>
        <dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>
</plugin>

To explain the above a bit. We used JaCoCo to collect integration test coverage for Sonar. We needed a specific Tomcat version (to test it works on the version provided by operations) and we have overridden some of the server.xml configuration directly by <port> and <protocol> directives.

Ondrej Burkert
  • 6,617
  • 2
  • 32
  • 27
0

Seems like the Tomcat tries to call this method which only exists in servlet-api-3.0 or later. As I could not exactly figure out where the container gets this wrong dependency from I solved my problem using a different approach.

Instead of creating a basic Tomcat via the maven-cargo-plugin and overriding the config files, I copied an already working local configuration and told cargo to use this configuration by adding

<configuration>
    <type>existing</type>
    <home>C:\path\to\tomcat\home</home>
</configuration>

to the plugin configuration