Giter Club home page Giter Club logo

gradle-tomcat-plugin's Introduction

Gradle Tomcat plugin Build Status

Tomcat Logo

‼️ This project reached end of life (EOL) status due to its incompatibility with Gradle 9.0 and the wide adoption of modern Java frameworks like Spring Boot, Micronaut, and Quarkus that can be executed without and directly by Tomcat. No more feature requests and bug fixes will be considered. Please fork the repository and publish your own releases if you want to continue maintaining the plugin.

The plugin provides deployment capabilities of web applications to an embedded Tomcat web container in any given Gradle build. It extends the War plugin. At the moment the Tomcat versions 6.0.x, 7.0.x, 8.0.x, 8.5.x and 9.0.x are supported.

The typical use case for this plugin is to support deployment during development. The plugin allows for rapid web application development due to the container's fast startup times. Gradle starts the embedded container in the same JVM. Currently, the container cannot be forked as a separate process. This plugin also can't deploy a WAR file to a remote container. If you are looking for this capability, please have a look at the Cargo plugin instead.

Usage

To use the plugin's functionality, you will need to add the its binary artifact to your build script's classpath and apply the plugin.

Adding the plugin binary to the build

The plugin JAR needs to be defined in the classpath of your build script. It is directly available on the Gradle plugin portal. The following code snippet shows an example on how to retrieve it:

buildscript {
    repositories {
        gradlePluginPortal()
    }

    dependencies {
        classpath 'com.bmuschko:gradle-tomcat-plugin:2.7.0'
    }
}

Provided plugins

The JAR file comes with two plugins:

Plugin Identifier Depends On Type Description
com.bmuschko.tomcat-base - TomcatBasePlugin Provides Tomcat custom task types, pre-configures classpath.
com.bmuschko.tomcat com.bmuschko.tomcat-base TomcatPlugin Provides tasks for starting and stopping an embedded Tomcat container and exposes extension named tomcat.

The com.bmuschko.tomcat plugin helps you get started quickly. If you are OK if the preconfigured tasks, this is the preferable option. Most plugin users will go with this option. To use the Tomcat plugin, include the following code snippet in your build script:

apply plugin: 'com.bmuschko.tomcat'

If you need full control over your tasks or don't want to go with the preconfigured tasks, you will want to use the com.bmuschko.tomcat-base plugin. That might be the case if you want to set up the container solely for functional testing. The downside is that each task has to be configured individually in your build script. To use the Tomcat base plugin, include the following code snippet in your build script:

apply plugin: 'com.bmuschko.tomcat-base'

Assigning the Tomcat libraries

Additionally, the Tomcat runtime libraries need to be added to the configuration tomcat. At the moment the Tomcat versions 6.0.x, 7.0.x, 8.0.x, 8.5.x and 9.0.x are supported by the plugin. Make sure you don't mix up Tomcat libraries of different versions.

Tomcat 6.0.x:

repositories {
    mavenCentral()
}

dependencies {
    def tomcatVersion = '6.0.51'
    tomcat "org.apache.tomcat:catalina:${tomcatVersion}",
           "org.apache.tomcat:coyote:${tomcatVersion}",
           "org.apache.tomcat:jasper:${tomcatVersion}"
}

Tomcat 7.0.x:

repositories {
    mavenCentral()
}

dependencies {
    def tomcatVersion = '7.0.76'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
           "org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
           "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}

Tomcat 8.0.x:

repositories {
    mavenCentral()
}

dependencies {
    def tomcatVersion = '8.0.42'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
           "org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
           "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}

Tomcat 8.5.x:

Please be aware that the dependency tomcat-embed-logging-juli is only required to enable container logging via Log4J 1.x (which is no longer support by the Log4J community). Log4J 2.x can be used for container logging without declaring any extra libraries.

repositories {
    mavenCentral()
}

dependencies {
    def tomcatVersion = '8.5.16'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
           "org.apache.tomcat.embed:tomcat-embed-logging-juli:8.5.2",
           "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}

tomcat {
    httpProtocol = 'org.apache.coyote.http11.Http11Nio2Protocol'
    ajpProtocol  = 'org.apache.coyote.ajp.AjpNio2Protocol'
}

Tomcat 9.0.x:

Please be aware that the dependency tomcat-embed-logging-juli is only required to enable container logging via Log4J 1.x (which is no longer support by the Log4J community). Log4J 2.x can be used for container logging without declaring any extra libraries.

repositories {
    mavenCentral()
}

dependencies {
    def tomcatVersion = '9.0.1'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
           "org.apache.tomcat.embed:tomcat-embed-logging-juli:9.0.0.M6",
           "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}

tomcat {
    httpProtocol = 'org.apache.coyote.http11.Http11Nio2Protocol'
    ajpProtocol  = 'org.apache.coyote.ajp.AjpNio2Protocol'
}

Tasks

The com.bmuschko.tomcat plugin pre-defines the following tasks out-of-the-box:

Task Name Depends On Type Description
tomcatRun - TomcatRun Starts a Tomcat instance and deploys the exploded web application to it.
tomcatRunWar - TomcatRunWar Starts a Tomcat instance and deploys the WAR to it.
tomcatStop - TomcatStop Stops the Tomcat instance.
tomcatJasper - TomcatJasper Runs the JSP compiler and turns JSP pages into Java source using Jasper.

Project layout

The Tomcat plugin uses the same layout as the War plugin.

Extension properties

The Tomcat plugin exposes the following properties through the extension named tomcat:

  • httpPort: The TCP port which Tomcat should listen for HTTP requests on (defaults to 8080).
  • httpsPort: The TCP port which Tomcat should listen for HTTPS requests on (defaults to 8443).
  • ajpPort: The TCP port which Tomcat should listen for AJP requests on (defaults to 8009).
  • stopPort: The TCP port which Tomcat should listen for admin requests on (defaults to 8081).
  • stopKey: The key to pass to Tomcat when requesting it to stop (defaults to null).
  • contextPath: The URL context path under which the web application will be registered (defaults to WAR name).
  • enableSSL: Determines whether the HTTPS connector should be created (defaults to false).
  • daemon: Specifies whether the Tomcat server should run in the background. When true, this task completes as soon as the server has started. When false, this task blocks until the Tomcat server is stopped (defaults to false).
  • keystoreFile: The keystore file to use for SSL, if enabled (by default, a keystore will be generated).
  • httpProtocol: The HTTP protocol handler class name to be used (defaults to org.apache.coyote.http11.Http11Protocol).
  • httpsProtocol: The HTTPS protocol handler class name to be used (defaults to org.apache.coyote.http11.Http11Protocol).
  • ajpProtocol: The AJP protocol handler class name to be used (defaults to org.apache.coyote.ajp.AjpProtocol).
  • users: List of users with username, password and roles. Used to configure tomcat with basic authentication with these users.

Example

The following example code shows how to change the default HTTP/HTTPS ports. To enable SSL we set the property enableSSL to true. The web application will be accessible under the context path sample-app.

tomcat {
    httpPort = 8090
    httpsPort = 8091
    enableSSL = true
    contextPath = 'sample-app'
    
    users {
        user {
            username = 'user1'
            password = '123456'
            roles = ['developers', 'admin']
        }

        user {
            username = 'user2'
            password = 'abcdef'
            roles = ['manager']
        }
    }
}

Task properties

Furthermore, you can set the following optional task properties:

  • contextPath: The URL context path your web application will be registered under (defaults to WAR name).
  • webDefaultXml: The default web.xml. If it doesn't get defined an instance of org.apache.catalina.servlets.DefaultServlet and org.apache.jasper.servlet.JspServlet will be set up.
  • additionalRuntimeResources: Defines additional runtime JARs or directories that are not provided by the web application.
  • URIEncoding: Specifies the character encoding used to decode the URI bytes by the HTTP Connector (defaults to UTF-8).
  • daemon: Specifies whether the Tomcat server should run in the background. When true, this task completes as soon as the server has started. When false, this task blocks until the Tomcat server is stopped (defaults to false).
  • configFile: The path to the Tomcat context XML file (defaults to src/main/webapp/META-INF/context.xml for tomcatRun, defaults to META-INF/context.xml within the WAR for tomcatRunWar).
  • outputFile: The file to write Tomcat log messages to. If the file already exists new messages will be appended.
  • reloadable: Forces context scanning if you don't use a context file (defaults to true).
  • keystorePass: The keystore password to use for SSL, if enabled.
  • truststoreFile: The truststore file to use for SSL, if enabled.
  • truststorePass: The truststore password to use for SSL, if enabled.
  • clientAuth: The clientAuth setting to use, values may be: true, false or want (defaults to false).

Note: keystoreFile and truststoreFile each require an instance of a File object e.g. file("/path/my.file")

Example

In the following example code, we declare a custom context file for the task tomcatRun.

tomcatRun.configFile = file('context.xml')

To configure the Jasper compiler task you can choose to set the following properties within the jasper closure of the tomcat extension:

  • validateXml: Determines whether web.xml should be validated (defaults to null).
  • validateTld: Determines whether web.xml should be validated (defaults to null).
  • uriroot: The web application root directory (defaults to src/main/webapp).
  • webXmlFragment: The generated web XML fragment file to be referenced by your web.xml file.
  • addWebXmlMappings: Automatically add the generated web XML fragment to the web.xml file. Caution: this will modify the web.xml file in the project, not the build directory.
  • outputDir: The output directory the compiled JSPs will end up in (defaults to build/jasper).
  • classdebuginfo: Should the class file be compiled with debugging information (defaults to true).
  • compiler: Which compiler Ant should use to compile JSP pages. See the Ant documentation for more information. If the value is not set, then the default Eclipse JDT Java compiler will be used instead of using Ant. No default value.
  • compilerSourceVM: What JDK version are the source files compatible with (defaults to 1.6).
  • compilerTargetVM: What JDK version are the generated files compatible with (defaults to 1.6).
  • poolingEnabled: Determines whether tag handler pooling is enabled. This is a compilation option. It will not alter the behaviour of JSPs that have already been compiled (defaults to true).
  • errorOnUseBeanInvalidClassAttribute: Should Jasper issue an error when the value of the class attribute in an useBean action is not a valid bean class (defaults to true).
  • genStringAsCharArray: Should text strings be generated as char arrays, to improve performance in some cases (defaults to false).
  • ieClassId: The class-id value to be sent to Internet Explorer when using <jsp:plugin> tags (defaults to clsid:8AD9C840-044E-11D1-B3E9-00805F499D93).
  • javaEncoding: Java file encoding to use for generating java source files (defaults to UTF8).
  • trimSpaces: Should white spaces in template text between actions or directives be trimmed (defaults to TrimSpaces.TRUE).
  • xpoweredBy: Determines whether X-Powered-By response header is added by generated servlet (defaults to false).

Example

tomcat {
    jasper {
        validateXml = true
        webXmlFragment = file("$webAppDir/WEB-INF/generated_web.xml")
        outputDir = file("$webAppDir/WEB-INF/src")
    }
}

FAQ

I get a compile exception when calling a JSP. Is there something I am missing?

The exception you might see is probably similar to this one: org.apache.jasper.JasperException: Unable to compile class for JSP. Tomcat 7.x and 8.x requires you to have Eclipse ECJ 3.6.x in your the classpath. However, this version of the dependency does not exist in Maven Central. You'll have to download that dependency and put it in your own repository or define a repository on your local disk where you can drop it in. Here's an example:

repositories {
     flatDir name: 'localRepository', dirs: 'lib'
}

Why do I get a java.lang.ClassCastException on javax.servlet.Servlet?

Tomcat is very sensitive to having multiple versions of the dependencies javax.servlet:servlet-api and javax.servlet:jsp-api in its classpath. By default they already get pulled in as transitive dependencies of the embedded Tomcat libraries. The exception you might see looks similar to this one:

java.lang.ClassCastException: org.springframework.web.servlet.DispatcherServlet cannot be cast to javax.servlet.Servlet
        at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1062)
        at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1010)
        at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4935)
        at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5262)
        at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5257)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

To fix this make sure you define your JSP and Servlet module dependencies with the scope providedCompile like this:

providedCompile 'javax.servlet:servlet-api:2.5',
                'javax.servlet:jsp-api:2.0'

How do I remote debug my Tomcat started up by the plugin?

If you want to be able to debug your application remotely you have to set the following JVM options in your GRADLE_OPTS environment variable before starting up the container. The port number you choose is up to you.

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

Tomcat will then listen on the specified port for incoming remote debugging connections. When starting up the container you should see the following message:

Listening for transport dt_socket at address: 5005

Check your IDE documentation on how to configure connecting to the remote debugging port.

My Tomcat container needs to use a JNDI datasource. How do I set up my project?

First of all you got to make sure to declare the connection pool dependency using the tomcat configuration.

Tomcat 6.0.x:

def tomcatVersion = '6.0.35'
tomcat "org.apache.tomcat:dbcp:${tomcatVersion}"

See coordinates on Maven Central for details.

Later versions:

def tomcatVersion = '9.0.8'
tomcat "org.apache.tomcat:tomcat-dbcp:${tomcatVersion}"

See coordinates on Maven Central for details.

If you decide to go with the default settings place your context.xml in the directory src/main/webapp/META-INF. To set a custom location you can use the convention property configFile. Here's an example on how to set it for the tasks tomcatRun and tomcatRunWar.

[tomcatRun, tomcatRunWar]*.configFile = file('context.xml')

Please refer to the Tomcat documentation for a list of context attributes. The following example shows how to set up a MySQL JNDI datasource.

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/mydatabase"
              auth="Container"
              type="javax.sql.DataSource"
              username="superuser"
              password="secretpasswd"
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/mydb"
              validationQuery="select 1"
              maxActive="10"
              maxIdle="4"/>
</Context>

How do I use hot code deployment with the plugin?

The plugin provides out-of-the-box support for swapping out byte code through the property reloadable. By default this option is turned out so you don't need any additional configuration changes. All you need to do is to have a running instance of the container initiated by tomcatRun. Fire up your favorite editor, change a production source file, save it and recompile your sources in another terminal via gradle compileJava. After a couple of seconds the context is reloaded and you should see the behavior reflected in the terminal window running the container:

Reloading Context with name [/myapp] has started
Reloading Context with name [/myapp] is completed

Alternatively, you can use other commericial byte code swap technologies. The configuration is usually product-specific. Please refer to the product's documentation on how to set it up for your project. The following section describes how to set up Gradle and the plugin with JRebel. First of all download JRebel, install it on your machine and set up the license. To tell JRebel which directory to scan for changed byte code you need to create a rebel.xml file. In your web module place the file under build/classes/main so it can be loaded by the Tomcat plugin. For creating the configuration of the file the Gradle JRebel plugin comes in handy. It's not required to use the plugin. You can also decide to create the configuration by hand. Keep in mind that gradle clean will delete the file. For setting up JRebel in a multi-module project scenario please refer to the documentation. The following code snippet shows an example rebel.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com"
            xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
    <classpath>
        <dir name="/Users/ben/dev/projects/mywebproject/build/classes/main">
        </dir>
    </classpath>

    <web>
        <link target="/">
            <dir name="/Users/ben/dev/projects/mywebproject/src/main/webapp">
            </dir>
        </link>
    </web>
</application>

Edit your Gradle startup script and add the following line to it to tell Gradle to use the JRebel agent. Please make sure to set the environment variable REBEL_HOME that points to your JRebel installation directory.

JAVA_OPTS="-javaagent:$REBEL_HOME/jrebel.jar $JAVA_OPTS"

On startup of your web module using gradle tomcatRun you should see information about the JRebel license being used and the directories being scanned for changes. For our example rebel.xml file it would look like this:

JRebel: Directory '/Users/ben/dev/projects/mywebproject/build/classes/main' will be monitored for changes.
JRebel: Directory '/Users/ben/dev/projects/mywebproject/src/main/webapp' will be monitored for changes.

If a file has been recompiled JRebel indicates this by writing it to the console like this:

JRebel: Reloading class 'de.muschko.web.controller.TestController'.

In need to run in-container integration tests as part of my build. What needs to be done?

Usually unit and integration tests are kept separate by convention. One convention could be to name the test source files differently e.g. integration tests always end with the suffix IntegrationTest, unit test files end with Test. By doing that you can run them separately. For running the integration tests you will want to run the Tomcat task as daemon thread and shut it down once your tests are done. The following example demonstrates how to set up a Gradle task that provides this functionality. Of course this is only one way of doing it. The following example requires Gradle >= 1.7:

apply plugin: 'com.bmuschko.tomcat-base'

ext {
    tomcatStopPort = 8081
    tomcatStopKey = 'stopKey'
}

task integrationTomcatRun(type: com.bmuschko.gradle.tomcat.tasks.TomcatRun) {
    stopPort = tomcatStopPort
    stopKey = tomcatStopKey
    daemon = true
}

task integrationTomcatStop(type: com.bmuschko.gradle.tomcat.tasks.TomcatStop) {
    stopPort = tomcatStopPort
    stopKey = tomcatStopKey
}

task integrationTest(type: Test) {
    include '**/*IntegrationTest.*'
    dependsOn integrationTomcatRun
    finalizedBy integrationTomcatStop
}

test {
    exclude '**/*IntegrationTest.*'
}

How do I add JAR files or directories that are not part of my web application source code?

Every task of type AbstractTomcatRun exposes a property named additionalRuntimeResources that is used to mixed in with the web application runtime classpath.

[tomcatRun, tomcatRunWar].each { task ->
    task.additionalRuntimeResources << file('/Users/bmuschko/config/props')
    task.additionalRuntimeResources << file('/Users/bmuschko/ext/jars/my.jar')
}

gradle-tomcat-plugin's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gradle-tomcat-plugin's Issues

Address already in use

I am trying to get the Tomcat Plugin working with a simple webapp, my output with the --info flag when launching is:

Creating SSL certificate
Created SSL certificate
Initializing ProtocolHandler ["http-bio-8080"]
Initializing ProtocolHandler ["http-bio-8091"]
Starting service Tomcat
Starting Servlet Engine: Apache Tomcat/7.0.11
No global web.xml found
Starting ProtocolHandler ["http-bio-8080"]
Starting ProtocolHandler ["http-bio-8091"]
Started Tomcat Server
The Server is running at http://localhost:8080/WebService

But then it fails with the following error when calling tomcatRun.execute():

* What went wrong:
Execution failed for task ':tomcatRun'.
> An error occurred starting the Tomcat server.

* Try:
Run with --debug option to get more log output.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':tomcatRun'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:68)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:34)
    at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter$1.run(CacheLockHandlingTaskExecuter.java:34)
    at org.gradle.cache.internal.DefaultCacheAccess$2.create(DefaultCacheAccess.java:200)
    at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:172)
    at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:198)
    at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunningOperation(DefaultPersistentDirectoryStore.java:111)
    at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.longRunningOperation(DefaultTaskArtifactStateCacheAccess.java:83)
    at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter.execute(CacheLockHandlingTaskExecuter.java:32)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:57)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:41)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:42)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:247)
    at org.gradle.api.internal.AbstractTask.execute(AbstractTask.java:242)
    at org.gradle.api.internal.TaskInternal$execute.call(Unknown Source)
    at tomcat_6kk78qru2rag4hjnc9esuc9blm$_run_closure4.doCall(/home/matt/Projects/Fragility/FragilityWebService/tomcat.gradle:35)
    at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(AbstractTask.java:452)
    at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(AbstractTask.java:436)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:60)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:34)
    at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter$1.run(CacheLockHandlingTaskExecuter.java:34)
    at org.gradle.cache.internal.DefaultCacheAccess$2.create(DefaultCacheAccess.java:200)
    at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:172)
    at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:198)
    at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunningOperation(DefaultPersistentDirectoryStore.java:111)
    at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.longRunningOperation(DefaultTaskArtifactStateCacheAccess.java:83)
    at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter.execute(CacheLockHandlingTaskExecuter.java:32)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:57)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:41)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:42)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:247)
    at org.gradle.execution.DefaultTaskGraphExecuter.executeTask(DefaultTaskGraphExecuter.java:192)
    at org.gradle.execution.DefaultTaskGraphExecuter.doExecute(DefaultTaskGraphExecuter.java:177)
    at org.gradle.execution.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:83)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:36)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
    at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)
    at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter$1.run(TaskCacheLockHandlingBuildExecuter.java:31)
    at org.gradle.cache.internal.DefaultCacheAccess$1.create(DefaultCacheAccess.java:111)
    at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:126)
    at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:109)
    at org.gradle.cache.internal.DefaultPersistentDirectoryStore.useCache(DefaultPersistentDirectoryStore.java:103)
    at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.useCache(DefaultTaskArtifactStateCacheAccess.java:79)
    at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter.execute(TaskCacheLockHandlingBuildExecuter.java:29)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
    at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:54)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:155)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:110)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:78)
    at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:42)
    at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:28)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:201)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:174)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:170)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:139)
    at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:31)
    at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:20)
    at org.gradle.launcher.Main.doAction(Main.java:48)
    at org.gradle.launcher.exec.EntryPoint.run(EntryPoint.java:45)
    at org.gradle.launcher.Main.main(Main.java:39)
    at org.gradle.launcher.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
    at org.gradle.launcher.ProcessBootstrap.run(ProcessBootstrap.java:32)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:24)
Caused by: org.gradle.api.GradleException: An error occurred starting the Tomcat server.
    at org.gradle.api.plugins.tomcat.AbstractTomcatRunTask.startTomcat(AbstractTomcatRunTask.groovy:205)
    at org.gradle.api.plugins.tomcat.AbstractTomcatRunTask.validateConfigurationAndStartTomcat(AbstractTomcatRunTask.groovy:109)
    at org.gradle.api.plugins.tomcat.AbstractTomcatRunTask.start(AbstractTomcatRunTask.groovy:72)
    at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:196)
    at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:102)
    at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:99)
    at org.gradle.api.plugins.tomcat.TomcatRun_Decorated.invokeMethod(Unknown Source)
    at org.gradle.util.ReflectionUtil.invoke(ReflectionUtil.groovy:23)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:150)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:145)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:477)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:466)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:60)
    ... 75 more
Caused by: java.net.BindException: Address already in use
    at org.gradle.api.plugins.tomcat.internal.ShutdownMonitor.<init>(ShutdownMonitor.groovy:49)
    at org.gradle.api.plugins.tomcat.AbstractTomcatRunTask.startTomcat(AbstractTomcatRunTask.groovy:197)
    ... 87 more

My setup code is:

dependencies {
    providedCompile 'javax.servlet:servlet-api:2.5',
                    'javax.servlet:jsp-api:2.0'

    def tomcatVersion = '7.0.11'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
           "org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
    tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
        exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
    }
}

tomcatRun {
    httpPort = 8080
    httpsPort = 8091
    enableSSL = true
}

[tomcatRun, tomcatStop]*.stopPort = 8080
[tomcatRun, tomcatStop]*.stopKey = 'stopKey'

task integrationTest(type: Test) << {
   include '**/*Start.*'
}

integrationTest.doFirst {
    println 'Starting the embedded tomcat server'
    tomcatRun.daemon = true
    tomcatRun.execute()
}

integrationTest.doLast {
    println 'Stopping the embedded tomcat server'
    tomcatStop.execute()
}

To also validate my ports are not being used:

telnet localhost 8080
Trying ::1...
Trying 127.0.1.1...
telnet: Unable to connect to remote host: Connection refused

telnet localhost 8091
Trying ::1...
Trying 127.0.1.1...
telnet: Unable to connect to remote host: Connection refused

I tried this with the Cargo plugin with success on the same ports, is there something wrong with the Tomcat plugin? Any thoughts?

TomcatInstrumentableClassLoader causes classpath to break

If i use a basic context.xml, defined as follows:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />
</Context>

The plugin no longer works, reporting that it cannot find org.apache.jasper.servlet.JspServlet I've added the dependency "org.springframework:spring-instrument-tomcat:3.1.2.RELEASE" to the tomcat configuration in my build.gradle, and as far as I can tell, embedded tomcat is finding this class. However, something seems to be broken with classpath delegation, because it can't find the other classes defined by the tomcat configuration.

Any ideas?

tomcatRun and Spring's @RequestMapping

First of all, great plugin!

I thought you should know of a problem I'm having with the tomcatRun task and a Spring based Controller annotated with @RequestMapping that doesn't seem to get spun up right.

I'm playing with this spring-backbone example which had a maven build. I converted it over to a gradle build and everything works nice with gradle war and deploying the war manually to tomcat. It's a very simple todo app. When using your plugin, tomcatRun does run the main webapp under localhost:8080/todo, but there's another config in the TodoController that gets configured like this:

public class TodoController {

So this should be available at http://localhost:8080/todo/api/todo but it doesn't get wired up properly when using gradle tomcatRun. Like I said it does work with gradle war and deploying it to tomcat manually. Would be nice for tomcatRun to work though

FYI I run it with --info and --stacktrace but there's no exception. Running it with --debug has crazy neverending amounts of output in the console. That would take longer :)

java.lang.ClassCastException (SpringServlet)

We are using a Jersey web service in tomcat. When I start up "gradle tomcatRun" we always get this:

java.lang.ClassCastException: com.sun.jersey.spi.spring.container.servlet.SpringServlet cannot be cast to javax.servlet.Servlet

The problem appears to be this dependency:

        compile(group: 'com.sun.jersey', name: 'jersey-spring', version: '1.11'),

I am not sure how to solve this one....I saw a similar issue in the FAQ, however the solution suggested doesn't solve the cast exception.

thanks for any thoughts.

phil

setting webAppSourceDirectory in tomcatRun conf

I wanted to run tomcat with a test context but setting configFile would not be enough. Could you please add webAppSourceDirectory = file('test.xml') configuration item to the documentation? thank you

Task to validate JSP

Hello, since plugin fetches all tomcat dependencies is it possible to consider adding task to plugin that will validate/compile JSPs ?
At least as potential addition for future.

JSPs from separate projects aren't reloading

I've got a set up like this:

module1/
  src/
    main/
      java/
        META-INF/
          resources/
            module1.jsp

webmodule/
  src/
    main/
      webapp/
        ....

Tomcat7 supports loading JSPs from JAR files as long as they're placed in the JAR at META-INF/resources, like module1.jsp above. When I cd into the webmodule/ directory and do "gradle tomcatRun", module1.jsp is accessible at localhost:8080/module1.jsp, just as expected.

However, I can't get the JSP to reload any changes without restarting Tomcat. Obviously this slows down development a lot. It'd be great if the Tomcat plugin could support reloading changed JSPs from other projects without requiring a restart.

BTW, I've been using this plugin for a while now and have had great success with it thus far. Thanks for all of the effort you've put into it.

Running Tomcat in daemon mode creates log lock file

Gradle version: 1.6
Tomcat version: 7.0.40
Tomcat plugin version: 0.9.8

config:

tomcatRun {
daemon = true
outputFile = 'tomcat.log'
}

When this task is run, it creates both a tomcat.log and a tomcat.log.lck file. After running the tomcatStop task, when tomcatRun task is run again, it fails to append to tomcat.log and creates a new file instead called tomcat.log.1 and a new lock file called tomcat.log.1.lck.

I think an extra command in tomcatStop needs to be added to delete the lck file.

NoClassDefinitionFound exception: org.gradle.api.plugins.JavaPluginConvention

From what I can see, this plugin should be included in gradle, so I'm not sure where the problem is coming from. I've followed all the instructions on the main page for setting up; this is a blocking issue, I can't run tomcatRun or tomcatRunWar. Everything works until I apply the tomcat plugin so I'm posting here first. Thanks in advance :)

Full stack trace:

org.gradle.api.LocationAwareGradleScriptException: Build file 'C:\git\code\build.gradle' line: 33
A problem occurred evaluating root project 'code'.
at org.gradle.groovy.scripts.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:51)
at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:127)
at org.gradle.configuration.BuildScriptProcessor.evaluate(BuildScriptProcessor.java:38)
at org.gradle.configuration.DefaultProjectEvaluator.evaluate(DefaultProjectEvaluator.java:38)
at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:506)
at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:71)
at org.gradle.configuration.ProjectEvaluationConfigurer.execute(ProjectEvaluationConfigurer.java:23)
at org.gradle.configuration.ProjectEvaluationConfigurer.execute(ProjectEvaluationConfigurer.java:21)
at org.gradle.configuration.DefaultBuildConfigurer$1.execute(DefaultBuildConfigurer.java:38)
at org.gradle.configuration.DefaultBuildConfigurer$1.execute(DefaultBuildConfigurer.java:35)
at org.gradle.api.internal.project.AbstractProject.configure(AbstractProject.java:482)
at org.gradle.api.internal.project.AbstractProject.allprojects(AbstractProject.java:477)
at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:35)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:136)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:107)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:75)
at org.gradle.launcher.RunBuildAction.execute(RunBuildAction.java:41)
at org.gradle.launcher.RunBuildAction.execute(RunBuildAction.java:27)
at org.gradle.launcher.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:209)
at org.gradle.launcher.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:193)
at org.gradle.launcher.Main.execute(Main.java:55)
at org.gradle.launcher.Main.main(Main.java:40)
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:592)
at org.gradle.launcher.ProcessBootstrap.runNoExit(ProcessBootstrap.java:46)
at org.gradle.launcher.ProcessBootstrap.run(ProcessBootstrap.java:28)
at org.gradle.launcher.GradleMain.main(GradleMain.java:24)
Caused by: java.lang.NoClassDefFoundError: org/gradle/api/plugins/JavaPluginConvention
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2395)
at java.lang.Class.getDeclaredMethods(Class.java:1763)
at org.codehaus.groovy.reflection.CachedClass$3$1.run(CachedClass.java:83)
at java.security.AccessController.doPrivileged(Native Method)
at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:80)
at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:78)
at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46)
at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33)
at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:249)
at groovy.lang.MetaClassImpl.populateMethods(MetaClassImpl.java:341)
at groovy.lang.MetaClassImpl.fillMethodIndex(MetaClassImpl.java:291)
at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:2920)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:166)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:182)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:210)
at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:751)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.initMetaClass(ScriptBytecodeAdapter.java:782)
at org.gradle.api.plugins.tomcat.TomcatPlugin.$getStaticMetaClass(TomcatPlugin.groovy)
at org.gradle.api.plugins.tomcat.TomcatPlugin.(TomcatPlugin.groovy:30)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:501)
at java.lang.Class.newInstance0(Class.java:350)
at java.lang.Class.newInstance(Class.java:303)
at org.gradle.api.internal.plugins.DefaultPluginRegistry.loadPlugin(DefaultPluginRegistry.java:63)
at org.gradle.api.internal.plugins.DefaultPluginRegistry.loadPlugin(DefaultPluginRegistry.java:54)
at org.gradle.api.internal.plugins.DefaultProjectsPluginContainer.providePlugin(DefaultProjectsPluginContainer.java:102)
at org.gradle.api.internal.plugins.DefaultProjectsPluginContainer.addPluginInternal(DefaultProjectsPluginContainer.java:67)
at org.gradle.api.internal.plugins.DefaultProjectsPluginContainer.apply(DefaultProjectsPluginContainer.java:37)
at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.applyPlugin(DefaultObjectConfigurationAction.java:101)
at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.access$200(DefaultObjectConfigurationAction.java:32)
at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction$3.run(DefaultObjectConfigurationAction.java:72)
at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.execute(DefaultObjectConfigurationAction.java:114)
at org.gradle.api.internal.project.AbstractProject.apply(AbstractProject.java:873)
at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:592)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:362)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at build_gradle_e46c1bf75a2191e2bd98aba8c162c634$_run_closure2.doCall(C:\git\code\build.gradle:33)
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:592)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:273)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
at groovy.lang.Closure.call(Closure.java:276)
at groovy.lang.Closure.call(Closure.java:289)
at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:61)
at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:31)
at org.gradle.api.internal.project.AbstractProject.project(AbstractProject.java:889)
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:592)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:158)
at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:93)
at org.gradle.api.internal.project.DefaultProject_Decorated.invokeMethod(Unknown Source)
at groovy.lang.GroovyObject$invokeMethod.call(Unknown Source)
at org.gradle.groovy.scripts.BasicScript.methodMissing(BasicScript.groovy:68)
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:592)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:813)
at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1107)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1060)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:153)
at build_gradle_e46c1bf75a2191e2bd98aba8c162c634.run(C:\git\code\build.gradle:31)
at org.gradle.groovy.scripts.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:49)
... 28 more

Groovy runtime err

There is a exception when I use this plugin:

Execution failed for task ':server:tomcatRunWar'.
Cause: org/codehaus/groovy/runtime/BytecodeInterface8

Gradle version: 1.0-milestone-5

configFile not taken correctly if its path contains spaces with Tomcat 6

If the file you pass to configFile is within a path that contains spaces, it isn't passed correctly to Tomcat 6.
It works correctly with Tomcat 7.

Looking at the source code I see that you pass configFile.path to the Tomcat 6 API. I don't know what it's expecting in there, but maybe using configFile.toURI().toString() could help to solve this issue.

With Tomcat 7, instead, configFile is passed as an URL, and hence there's no problem.

Tomcat doesn't seem to shutdown gracefully when exiting after tomcatRun

Spring offers the ability to subscribe to context lifecycle events including contact start and stop. These events are often used in development and testing and a typical example is to develop a class that creates data on start and deletes it on exit.

When stopping tomcat following tomcatRun by pressing Ctrl+C on the console, tomcat seems to be just exit immediately rather than stopping the application gracefully giving Spring the chance to close the context cleanly.

The sample app I created for #20 also demonstrates this problem. The app can be downloaded from here:

https://www.strongspace.com/rdavidson/public/sample-app.tar

The console outputs the various Spring context events as they occur. Quitting jettyRun and tomcatRun shows the difference. The jettyRun task shows that the app is shutdown cleanly by allowing ContextClosedEvents to be handled.

allow tomcat protocol handler class to be set

There doesn't currently seem to be a way to set the connector protocol handler. I'd like to be able to set the protocol handler class for the http and https connectors, for instance to org.apache.coyote.http11.Http11NioProtocol.

I imagine this would be exposed with new convention properties (httpProtocol and httpsProtocol)

ClassNotFoundException on Tomcat6xServer

I have the buildscript repositories and dependencies configured as on the main github page, but I'm getting the following when I try to use the tomcatRun task:

Caused by: java.lang.ClassNotFoundException: org.gradle.api.plugins.tomcat.embedded.Tomcat6xServer
        at java_lang_ClassLoader$loadClass.call(Unknown Source)
        at org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory.resolveTomcatServerImpl(TomcatServerFactory.groovy:51)
        at org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory.this$2$resolveTomcatServerImpl(TomcatServerFactory.groovy)
        at org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory$this$2$resolveTomcatServerImpl.callCurrent(Unknown Source)
        at org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory.getTomcatServer(TomcatServerFactory.groovy:36)
        at org.gradle.api.plugins.tomcat.AbstractTomcatRunTask.createServer(AbstractTomcatRunTask.groovy:194)
        at org.gradle.api.plugins.tomcat.AbstractTomcatRunTask$createServer.callCurrent(Unknown Source)
        at org.gradle.api.plugins.tomcat.AbstractTomcatRunTask.startTomcat(AbstractTomcatRunTask.groovy:158)
        ... 43 more

I've done a local build, and that class is in every instance of the gradle-tomcat-plugin-0.7.jar file I can find, including the one in the Gradle download cache.

I've locally added some debug logging code to the TomcatServerFactory to help figure this out:

def getTomcatServer() {
    ClassLoader classLoader = Thread.currentThread().contextClassLoader
    debugClassLoader(classLoader)
    Class appClass = resolveTomcatServerImpl(classLoader)
    appClass.newInstance()
}

def debugClassLoader(ClassLoader classLoader) {
    while (classLoader != null) {
        LOGGER.debug 'classLoader: {}', classLoader
        if (classLoader instanceof java.net.URLClassLoader) {
            LOGGER.debug 'urls: {}', classLoader.URLs
        }
        classLoader = classLoader.parent
    }
}

I can see that the contextClassLoader and its parents don't have the gradle-tomcat-plugin-0.7.jar file on the path.

11:34:23.749 [DEBUG] [org.gradle.api.plugins.tomcat.AbstractTomcatRunTask] Starting Tomcat Server ...
11:34:23.770 [DEBUG] [org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory] classLoader: java.net.URLClassLoader@1890c67
11:34:23.781 [DEBUG] [org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory] urls: []
11:34:23.792 [DEBUG] [org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory] classLoader: java.net.URLClassLoader@8d5485
11:34:23.812 [DEBUG] [org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory] urls: [file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/ant-1.8.2.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/ant-launcher-1.8.2.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/asm-all-3.3.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/commons-cli-1.2.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/commons-codec-1.2.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/commons-collections-3.2.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/commons-httpclient-3.0.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/commons-io-1.4.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/commons-lang-2.6.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/core-impl/, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/dom4j-1.6.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/gradle-core-1.0-milestone-3.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/gradle-launcher-1.0-milestone-3.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/gradle-open-api-1.0-milestone-3.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/gradle-tooling-api-1.0-milestone-3.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/gradle-ui-1.0-milestone-3.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/gradle-wrapper-1.0-milestone-3.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/groovy-all-1.7.10.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/guava-r08.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/ivy-2.2.0.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jansi-1.2.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jaxen-1.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jcl-over-slf4j-1.6.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jna-3.2.2.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jna-posix-1.0.3.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jsch-0.1.42.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jul-to-slf4j-1.6.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/jzlib-1.0.7.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/log4j-over-slf4j-1.6.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/logback-classic-0.9.28.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/logback-core-0.9.28.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/plugins/, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/slf4j-api-1.6.1.jar, file:/C:/Users/akrueger/.gradle/wrapper/dists/gradle-1.0-milestone-3/lib/webdavlib-2.0.jar]
11:34:23.827 [DEBUG] [org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory] classLoader: sun.misc.Launcher$ExtClassLoader@35ce36
11:34:23.842 [DEBUG] [org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory] urls: [file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/dnsns.jar, file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/j3dcore.jar, file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/j3dutils.jar, file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/localedata.jar, file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/sunjce_provider.jar, file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/sunmscapi.jar, file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/sunpkcs11.jar, file:/C:/Program%20Files%20(x86)/Java/jdk1.6.0_21/jre/lib/ext/vecmath.jar]
11:34:23.862 [INFO] [org.gradle.api.plugins.tomcat.embedded.TomcatServerFactory] Resolved Tomcat 6x server implementation in classpath

As you might guess from the paths above, I'm using Gradle 1.0-milestone-3. The project I'm using this with has multiple subprojects under a top-level build script.

tomcatRun fails when classesDirectory does not exist

I get this error when I use tomcatRun task

A problem was found with the configuration of task ':client-webapp:tomcatRun'.

Directory '/source/client-webapp/build/classes/main' specified for property 'classesDirectory' does not exist.

It only works if I put tomcatRun.classesDirectory.mkdirs() in build.gradle

The reason I have no classesDirectory is my project has no compiled source, it merely bundles everything from the other projects into the war file. Maybe warn instead of error?

tomcatRun doesn't do anything

When building our application and doing a tomcatRun the server responds with a message that it is available however the application isn't started (the Spring DispatcherServlet is not being started no logging etc.).

Doing a tomcatRunWar however seems to start the application but when entering the URL we are greeted with a nice 404, we also don't see any logging that the request is being received by the dispatcher servlet.

Tomcat 7.0.26, plugin 0.9, gradle m8a. We are building a Servlet 3.0 XMLless application so only annotations.

XXXServlet is not a servlet error for tomcatRun but tomcatRunWar runs fine

Hi All,

I've built a sample project and used tomcat gradle plugin.

tomcatRunWar works perfectly fine however running tomcatRun causes the following error

type Exception report

message Class org.travel.TestServlet is not a Servlet

description The server encountered an internal error that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: Class org.travel.TestServlet is not a Servlet
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
java.lang.Thread.run(Thread.java:722)
root cause

java.lang.ClassCastException: org.travel.TestServlet cannot be cast to javax.servlet.Servlet
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
java.lang.Thread.run(Thread.java:722)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.35 logs.

Any suggestions?

Thanks

Nilesh

tomcat stop fails

I get this on tomcat stop:

Zoso:eventstore pswenson$ gradle tomcatStop
Note: the Gradle build daemon is an experimental feature.
As such, you may experience unexpected build failures. You may need to occasionally stop the daemon.
:tomcatStop

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':tomcatStop'.
    Cause: Please specify a valid stopKey
  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Multiple slf4j bindings.

Gradle has it's own slf4j binding. Even though my version and the gradle version are the same they are both in the classpath for some reason.

Why does the gradle run time has to be in the class-loader path?

Any thoughts about it?

SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/home/vlad/Downloads/gradle-1.5/lib/logback-classic-1.0.9.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/home/vlad/.gradle/caches/artifacts-23/filestore/ch.qos.logback/logback-classic/1.0.9/jar/258c3d8f956e7c8723f13fdea6b81e3d74201f68/logback-classic-1.0.9.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

Add support for compiling the Java source obtained by the JSPs

Hi there,
your Tomcat plugin is great! I could enhance my Gradle project to translate JSPs to Java source files within minutes.

However, now I'm missing the next (natural?) step: to compile that source code into bytecode, so that I can be sure that my JSPs are correct.

Is there any easy way to do that even right now? Or can your plugin be enhanced to do that?

Thanks in advance.

Is debugging supported?

I typically launch a Tomcat instance for remote debugging using an Ant task like this:

    <target name="tomcat.debug">
        <java jar="${tomcat.home}/bin/bootstrap.jar" fork="true">
            <jvmarg value="-Dcatalina.home=${tomcat.home}" />
            <jvmarg value="-XX:MaxPermSize=256m" />
            <jvmarg value="-Xdebug" />
            <jvmarg value="-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n" />
        </java>
    </target>

Does the Tomcat plugin support remote debugging?

Cheers,
Jon

Using contextPath of '/' and c:url tags produces links that start with '//'

Hi Ben,

I have come across this issue with 0.8.2 of your gradle-tomcat-plugin.

Specifying a contextPath of '/' means that creating links using the standard c:url JSP tags produces links that start with '//'.

As an example:

<script type="text/javascript" src="<c:url value="/javascripts/yui-min.js"/>"></script>

this gets translated to

<script type="text/javascript" src="//javascripts/yui-min.js"></script>

and the file is not found due to the '//'.

The same configuration produces the correct result when using 'gradle jettyRun'.

plugin with id 'tomcat' not found in subprojects

i have a multi subprojects project. each subprojects need plugin 'tomcat'
the build script i want is like this:
..........................

allprojects {
apply plugin: 'idea'
}

subprojects {
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'tomcat'

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        tomcatPluginVersion = "0.9.8"
        classpath "org.gradle.api.plugins:gradle-tomcat-plugin:$tomcatPluginVersion"
    }
}

project.ext {
    tomcatVersion = "7.0.11"

}

dependencies {
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:$tomcatVersion",
            "org.apache.tomcat.embed:tomcat-embed-logging-juli:$tomcatVersion"
    tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:$tomcatVersion") {
        exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
    }
}

}
.........................
when i execute
gradle idea
it failed for:

A problem occurred evaluating root project.

Plugin with id 'tomcat' not found.

but if i put the tomcat plugin declartion in root project. it works well. So what;s wrong?

Create facility for adding external directories to the runtime classpath

Tomcat and Jetty both support the ability to add directories, external to the WAR, to their runtime classpath. This allows us to adopt the best practice of building the WAR once and adapting it to environments through environment-specific configuration.

See stackoverflow.com/questions/15130617/how-can-i-use-externalized-configuration-files-with-the-gradle-tomcat-plugin/15138491 for more information.

I was able to find a workaround that involves adding the external directory to the entire build script, which is fine by me, but probably the Tomcat plugin ought to support some way to target the plugin specifically.

Thanks for the help and for the useful plugin.

Setting additional jvmArgs in config

I need to define some app specific properties for running the app. When running normally, I define them as jvmArgs, and using the Maven tomcat plugin, I define systemProperties.

Thus far I haven't figured out how to do this with the tomcat plugin, and would appreciate any assistance. I'd like to do it in my gradle.build file, and not have to pass -D parms to the gradle command (although that does work).

ClassNotFoundException using Tomcat 6 version

Hi,
I can run my web app with the Tomcat 7 version without any errors but not with the Tomcat 6 version.

Stacktrace snippet:

Could not get url for /javax/servlet/jsp/resources/jsp_2_0.xsd
Could not get url for /javax/servlet/jsp/resources/jsp_2_1.xsd
...
org.apache.jasper.servlet.JspServlet
java.lang.ClassNotFoundException: org.apache.jasper.servlet.JspServlet

The web app seems to work anyway but I would like to know what could be the cause.
I'm not providing a context.xml, could it be the cause?

build.gradle snippet:

dependencies {
    providedCompile group: 'javax.servlet', name: 'servlet-api', version: '2.5'
    providedCompile group: 'javax.servlet', name: 'jsp-api', version: '2.0'
    ...
}

Thanks

Hot Code Replacement

It's a great plugin. Thanks.

It would be great if classes are hot replaced in running tomcat.

Extend to use tomcat manager to deploy to installed instance

It would be nice if this plugin were extended to be able to use the tomcat manager to deploy either via xml or war to an installed instance of tomcat (or better yet, have the option of doing either one). Not urgent but would make life easier :)

Root context path '/' not supported

The gradle tomcat plugin does not support the following:
tomcatRun.contextPath = '/'

When running the project with "gradle tomcatRun", the log output looks like this (note
the url's last slash):

[...]
Initializing Coyote HTTP/1.1 on http-8080
Starting Coyote HTTP/1.1 on http-8080
Started Tomcat Server
The Server is running at http://localhost:8080///

The web application is not loaded correctly.

No need for Gradle run-time on Tomcat classpath...

I think it sould be optional whether or not Gradle run-time should be included in the Tomcat classpath.

In my case there are conflicting dependencies between Gradle runtime and my WebApp dependencies.

Additional runtime Jars

Hi,

I like to use a "javax.mail.Session" provided by a JNDI lookup which works fine in a standalone setup but fails when using "tomcatRun".

The main things I've done are:

  1. configured JNDI in src\main\webapp\META-INF\context.xml file like this:
<Resource name="mail/Session" auth="Container"
         type = "javax.mail.Session"
...
    />
  1. created a new configuration:
configurations {
  mail
}
  1. dependency setup:
mail ('javax.mail:javax.mail-api:1.4.5')
  1. used the mail configuration to setup the additionalRuntimeJars property:
[tomcatRun, tomcatRunWar]*.additionalRuntimeJars = configurations.mail.files


configurations.mail.files.each {
  println it.toURI().toURL().toString()
}

I'll always end-up with the following exception

Caused by: java.lang.ClassNotFoundException: javax.mail.Authenticator
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 98 more

So it's seem the JAR is not available to the classloader. Do you have any idea?

thx in advance,

regards Moritz

btw: I'm using JDK 7, Tomcat 7.0.29 and version 0.9.3 of your plugin.

Running tomcat as daemon is not supported

JettyRun and jettyRunWar can be run as daemons ([jettyRun, jettyRunWar]*.daemon = true). This is very useful when starting jetty automatically before running integrationtests. Would be great if the tomcat plugin supported this.

OutOfMemoryError: PermGen space - Intermittent Error

Hi,

I'm using embedded tomcat plugin in my gradle build script. I'm often facing the following error in my local environment. Is it possible to change the embedded tomcat's VM args?

Exception in thread "http-bio-8080-exec-1" java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.apache.catalina.connector.Response.setConnector(Response.java:154)
at org.apache.catalina.connector.Connector.createResponse(Connector.java:899)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:373)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Exception in thread "http-bio-8080-exec-2" java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)

tomcatRunWar does not take over changes

When I run tomcatRunWar for the first time, the WAR File is extracted to a folder named like my webapp in my project folder. However, when I change some classes and run tomcatRunWar again these changes are not taken over. I can see my changes only if I delete the created folder. I usually stop the running tomcat by hitting Crtl + C, but the mentioned behaviour is the same when I stop it with tomcatStop. The created WAR file however contains the current class files.

configFile not used?

Take a look at this: https://github.com/wujek-srujek/gradle-web. The last commit uses the tomcat plugin and I created a simple context.xml which defines the context path, which is not used - tomcat still uses the default. Is this supposed to work this way? I must say I've never used such context.xml files so maybe it is wrong?

unknown classpath 'GRADLE_RUNTIME' requested.

Gradle version 1.0-milestone-5

Error:

$ gradle tomcatRun
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:tomcatRun

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':tomcatRun'.
Cause: unknown classpath 'GRADLE_RUNTIME' requested.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 5.149 secs

Detail:

11:47:03.170 [ERROR] [org.gradle.BuildExceptionReporter] 
11:47:03.172 [ERROR] [org.gradle.BuildExceptionReporter] FAILURE: Build failed with an exception.
11:47:03.173 [ERROR] [org.gradle.BuildExceptionReporter] 
11:47:03.173 [ERROR] [org.gradle.BuildExceptionReporter] * What went wrong:
11:47:03.174 [ERROR] [org.gradle.BuildExceptionReporter] Execution failed for task ':tomcatRun'.
11:47:03.177 [ERROR] [org.gradle.BuildExceptionReporter] Cause: unknown classpath 'GRADLE_RUNTIME' requested.
11:47:03.178 [ERROR] [org.gradle.BuildExceptionReporter] 
11:47:03.178 [ERROR] [org.gradle.BuildExceptionReporter] * Exception is:
11:47:03.181 [ERROR] [org.gradle.BuildExceptionReporter] org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':tomcatRun'.
11:47:03.181 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:71)

Add monitor for modified classes/resources

byte swap technologies like JRebel, fakereplace, Javeleon ... etc, can be integrated to make development easier and faster. From my experience with maven-jetty, the whole server can be restarted when modification occurs. This is a bit slow and time consuming. A nice feature can be introduced here, to allow modified resources to be rebuilt. Another interesting project and related is http://gradle.codehaus.org/Gradle+Build+Daemon. I am not sure about the status, but if it's completed it can be used with different plugins as well, making it easy for programers to run application and see changes regardless of the IDE they are using.

Tomcat not running when using daemon mode

I am migrating a project to Gradle and trying this Tomcat plugin.

The tomcatRunWar task runs correctly in process, but I want to run it in daemon mode. However, when running it, I can see the application starting, the servlets initialized, but after Gradle finishes Tomcat is not running.

I can't see any error or exception even when using --debug.

I don't know what can I try to see what is happening.

PS: I'm not using the Gradle daemon mode.

Provide support for running the container with a given context.xml

The context.xml file is an optional file which contains a tag (Context Fragment) for a single Tomcat web application. This can be used to define certain behaviours for your application, JNDI resources and other settings. The context.xml file has to be assigned via a convention property.

slf4j issue while doing tomcatRunWar for gradle tomcat plugin

Hi Ben,

This is Santanu. I am creating the issue as you have suggested. But I could not find how to attach the gradle build file and the embedded tomcat log here.

Here is the issue detail

For my recent project I am using Gradle tomcat plugin. My gradle version is 1.0. When I run gradle clean build the war file is getting generated perfectly and when I deploy the war in my server running tomcat I can see the web application throwing up pages as expected. But when I am trying to run the war during gradle build using tomcat plugin I am getting a LinkageError due to slf4j version mismatch in classloader for tomcat and gradle. As a result the application fails to start. I am using the gradle command line - gradle clean build tomcatRunWar.

Thanks and regards
Santanu

Support Tomcat 7

Now that Tomcat 7 is stable, support for it in the gradle tomcat plugin would be a great thing.

Docs to be updated regarding JNDI datasources

Hello
We're working with some old fashioned project that are declaring database connection using JNDI via Resource section in context.xml.
Example is below. In this case we need additional tomcat dependency since for declaring DB connection tomcat using its internal connection pool implementation. It could be great if this issue will be mentioned in docs. Hope it could help some people like me to not waste their time on investigating :) Solution is to add one line to dependencies.

def tomcatVersion = '6.0.35'
tomcat "org.apache.tomcat:catalina:${tomcatVersion}",
        "org.apache.tomcat:coyote:${tomcatVersion}",
        "org.apache.tomcat:jasper:${tomcatVersion}",
        "org.apache.tomcat:dbcp:${tomcatVersion}"  <------------ ADD THIS :)

-- here's example of declaration of JNDI database connection

Tomcat 7 cannot start up twice if there are any JARs on the classpath

Hi,

FIrst of all, great plugin, and thanks for building this.

We are having an issue where we run two sets of integration tests - one for each "mode" - in a single Gradle build, and that is causing the following problem when Tomcat tries to startup the second time:

:integration-tests:mode-b:test
A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[/mode-b]]
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
    at java.util.concurrent.FutureTask.get(FutureTask.java:83)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:800)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[/mode-b]]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
    ... 7 more
Caused by: java.lang.IllegalStateException: Illegal class loader binding
    at org.apache.naming.resources.DirContextURLStreamHandler.get(DirContextURLStreamHandler.java:229)
    at org.apache.naming.resources.DirContextURLStreamHandler.openConnection(DirContextURLStreamHandler.java:91)
    at java.net.URL.openConnection(URL.java:945)
    at sun.net.www.protocol.jar.JarURLConnection.<init>(JarURLConnection.java:66)
    at sun.net.www.protocol.jar.Handler.openConnection(Handler.java:24)
    at java.net.URL.openConnection(URL.java:945)
    at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:258)
    at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:178)
    at org.apache.catalina.startup.ContextConfig.processJarsForWebFragments(ContextConfig.java:1938)
    at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1268)
    at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:878)
    at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:369)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5269)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    ... 7 more

I've created a little Git repo to reproduce the issue:

https://github.com/davidnortonjr/gradle-tomcat-plugin-run-tomcat-twice-issue

  • This only seems to happen on Tomcat 7 -- Tomcat 6 was OK.
  • It works OK if I remove the dependency from the 'web' project.

tomcatRun has error but tomcatRunWar work fine

tomcatRun task appear below message and tomcat does not work with spring request mapping annotation project
My project has web.xml in /src/main/webapp/WEB-INF/web.xml
I think may be tomcat plugin does not detected it

Jun 12, 2013 5:00:31 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.41
Jun 12, 2013 5:00:31 PM org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment
INFO: No global web.xml found

but tomcatRunWar task work fine.

tomcatRunWar has some problem with slf4j and logback logging project

:tomcatRunWar
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/Java/gradle-1.6/lib/logback-classic-1.0.9.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/gradleProjects/HomzWeb/build/tmp/tomcatRunWar/work/Tomcat/localhost/_/WEB-INF/lib/logback-classic-1.0.13.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

gradle's logback library and project's logback library conflict.

may be two logback jar exist in one classpath

Setting additional jvmArgs in config

I would like to add arguments (and not only properties) to Tomcat but with dynamic values (therefore I can't use GRADLE_OPTS).
For example: set the debug port dynamically.

It's a mix of issue #33 and documentation question 'How do I remote debug my Tomcat started up by the plugin?'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.