diff --git a/pom.xml b/pom.xml index 4e6697e4..1082cd53 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,9 @@ 1.7 2.2.1 + 3.6.0 + false 2.22.1 @@ -55,7 +57,6 @@ 2000 false false - \ https://repository.apache.org/service/local/staging/deploy/maven2 https://repository.apache.org/content/repositories/snapshots @@ -73,8 +74,8 @@ 2001 2008 - 7.0.59 - 8.0.14 + 7.0.109 + 8.5.100 @@ -324,6 +325,8 @@ tomcat7-maven-plugin tomcat8-war-runner tomcat8-maven-plugin + tomcat9-war-runner + tomcat9-maven-plugin tomcat-maven-archetype @@ -678,7 +681,7 @@ maven-compiler-plugin - 3.8.0 + 3.8.1 ${project.build.sourceEncoding} ${maven.compiler.source} @@ -747,7 +750,10 @@ org.apache.maven.plugins maven-resources-plugin - 3.1.0 + 3.3.1 + + \ + org.apache.maven.plugins @@ -774,6 +780,7 @@ DEPENDENCIES README.txt *.sh + *.log .git/** .idea/** out/** diff --git a/tomcat-maven-archetype/pom.xml b/tomcat-maven-archetype/pom.xml index 128680b0..b1f406f2 100644 --- a/tomcat-maven-archetype/pom.xml +++ b/tomcat-maven-archetype/pom.xml @@ -36,7 +36,7 @@ Apache Tomcat Maven Plugin :: Archetype - 2.2 + 3.1.2 ${project.version} clean,pre-integration-test clean,install diff --git a/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-api-impl/pom.xml b/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-api-impl/pom.xml index 39f79ed1..330e773c 100644 --- a/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-api-impl/pom.xml +++ b/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-api-impl/pom.xml @@ -99,7 +99,17 @@ tomcat-jsp-api test - - - + + jakarta.xml.bind + jakarta.xml.bind-api + 2.3.3 + test + + + org.glassfish.jaxb + jaxb-runtime + 2.3.3 + test + + diff --git a/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-webapp-it/src/test/context.xml b/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-webapp-it/src/test/context.xml index d9b3ac84..65496ef2 100644 --- a/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-webapp-it/src/test/context.xml +++ b/tomcat-maven-archetype/src/main/resources/archetype-resources/__rootArtifactId__-webapp-it/src/test/context.xml @@ -17,4 +17,4 @@ specific language governing permissions and limitations under the License. --> - + diff --git a/tomcat-maven-archetype/src/main/resources/archetype-resources/pom.xml b/tomcat-maven-archetype/src/main/resources/archetype-resources/pom.xml index 9ae412cb..fa10ce83 100644 --- a/tomcat-maven-archetype/src/main/resources/archetype-resources/pom.xml +++ b/tomcat-maven-archetype/src/main/resources/archetype-resources/pom.xml @@ -37,10 +37,10 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.8.1 - 1.5 - 1.5 + 1.7 + 1.7 diff --git a/tomcat-maven-plugin-it/pom.xml b/tomcat-maven-plugin-it/pom.xml index 7569339b..e3fff180 100644 --- a/tomcat-maven-plugin-it/pom.xml +++ b/tomcat-maven-plugin-it/pom.xml @@ -34,7 +34,6 @@ 2000 - \ diff --git a/tomcat7-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat7/run/AbstractRunMojo.java b/tomcat7-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat7/run/AbstractRunMojo.java index fff9cb53..092900c6 100644 --- a/tomcat7-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat7/run/AbstractRunMojo.java +++ b/tomcat7-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat7/run/AbstractRunMojo.java @@ -725,11 +725,11 @@ else if ( defaultContextFile.exists() ) } // https://issues.apache.org/jira/browse/MTOMCAT-255 - if(context instanceof StandardContext) + if(context instanceof StandardContext && new File(project.getBuild().getOutputDirectory()).exists()) { - ((StandardContext) context).setAddWebinfClassesResources(true); - ((StandardContext) context).setAliases( "/WEB-INF/classes=" + project.getBuild().getOutputDirectory()); - } + ((StandardContext) context).setAddWebinfClassesResources(true); + ((StandardContext) context).setAliases("/WEB-INF/classes=" + project.getBuild().getOutputDirectory()); + } return context; diff --git a/tomcat8-maven-plugin/pom.xml b/tomcat8-maven-plugin/pom.xml index 6bb68859..083efe07 100644 --- a/tomcat8-maven-plugin/pom.xml +++ b/tomcat8-maven-plugin/pom.xml @@ -131,18 +131,18 @@ org.apache.tomcat tomcat-juli - ${tomcat8Version} + 8.5.57 org.apache.tomcat.embed tomcat-embed-logging-juli - ${tomcat8Version} + 8.0.14 org.apache.tomcat.embed tomcat-embed-logging-log4j - ${tomcat8Version} + 8.0.14 diff --git a/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java b/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java index 225b3f76..94c1ead1 100644 --- a/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java +++ b/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java @@ -813,13 +813,13 @@ public WebResource getResource( String path ) log.debug( "MyDirContext#getResource: " + path ); if ( "/WEB-INF/classes".equals( path ) ) { - return new FileResource( this, this.webAppPath, new File( this.buildOutputDirectory ), true ); + return new FileResource( this, this.webAppPath, new File( this.buildOutputDirectory ), true, null ); } File file = new File( path ); if ( file.exists() ) { - return new FileResource( this, this.webAppPath, file, true ); + return new FileResource( this, this.webAppPath, file, true, null ); } WebResource webResource = super.getResource( path ); return webResource; diff --git a/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/RunMojo.java b/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/RunMojo.java index e4e40404..dc5cab8f 100644 --- a/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/RunMojo.java +++ b/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/RunMojo.java @@ -20,14 +20,13 @@ import org.apache.catalina.Context; import org.apache.catalina.WebResource; -import org.apache.catalina.WebResourceRoot; import org.apache.catalina.WebResourceSet; -import org.apache.catalina.loader.WebappClassLoaderBase; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.webresources.EmptyResource; import org.apache.catalina.webresources.FileResource; import org.apache.catalina.webresources.FileResourceSet; import org.apache.catalina.webresources.JarResource; +import org.apache.catalina.webresources.JarResourceSet; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; @@ -479,18 +478,16 @@ private WebResource urlToWebResource( URL url, String path ) jarFile = new JarFile( filePath ); JarEntry jarEntry = jarFile.getJarEntry( StringUtils.removeStart( path, "/" ) ); + final JarResourceSet jarResourceSet = new JarResourceSet(this, getPath(), jarFile.getName(), path); - return new JarResource( this, // + return new JarResource( jarResourceSet, // getPath(), // - filePath, // url.getPath().substring( 0, idx ), // - jarEntry, // - "", // - null ); + jarEntry); } else { - return new FileResource( this, webAppPath, new File( url.getFile() ), true ); + return new FileResource( this, webAppPath, new File( url.getFile() ), true, null ); } } @@ -537,18 +534,18 @@ public WebResource getResource( String path ) if ( StringUtils.startsWithIgnoreCase( path, "/WEB-INF/LIB" ) ) { File file = new File( StringUtils.removeStartIgnoreCase( path, "/WEB-INF/LIB" ) ); - return new FileResource( context.getResources(), getPath(), file, true ); + return new FileResource( context.getResources(), getPath(), file, true, null ); } if ( StringUtils.equalsIgnoreCase( path, "/WEB-INF/classes" ) ) { return new FileResource( context.getResources(), getPath(), - new File( project.getBuild().getOutputDirectory() ), true ); + new File( project.getBuild().getOutputDirectory() ), true, null ); } File file = new File( project.getBuild().getOutputDirectory(), path ); if ( file.exists() ) { - return new FileResource( context.getResources(), getPath(), file, true ); + return new FileResource( context.getResources(), getPath(), file, true, null ); } //if ( StringUtils.endsWith( path, ".class" ) ) @@ -569,13 +566,11 @@ public WebResource getResource( String path ) (JarEntry) jarFile.getEntry( StringUtils.removeStart( path, "/" ) ); if ( jarEntry != null ) { - return new JarResource( context.getResources(), // + final JarResourceSet jarResourceSet = new JarResourceSet(context.getResources(), getPath(), jarFile.getName(), path); + return new JarResource( jarResourceSet, // getPath(), // - jarFile.getName(), // jar.toURI().toString(), // - jarEntry, // - path, // - jarFile.getManifest() ); + jarEntry); } } catch ( IOException e ) diff --git a/tomcat8-maven-plugin/src/site/apt/adjust-embedded-tomcat-version.apt.vm b/tomcat8-maven-plugin/src/site/apt/adjust-embedded-tomcat-version.apt.vm index 02f0e8b8..b3bb308d 100644 --- a/tomcat8-maven-plugin/src/site/apt/adjust-embedded-tomcat-version.apt.vm +++ b/tomcat8-maven-plugin/src/site/apt/adjust-embedded-tomcat-version.apt.vm @@ -35,7 +35,7 @@ Adjust Tomcat Version [...] - 7.0.50 + 8.5.100 [...] [...] diff --git a/tomcat9-maven-plugin/pom.xml b/tomcat9-maven-plugin/pom.xml new file mode 100644 index 00000000..0142a4ca --- /dev/null +++ b/tomcat9-maven-plugin/pom.xml @@ -0,0 +1,378 @@ + + + + + 4.0.0 + + tomcat-maven-plugin + org.apache.tomcat.maven + 3.0-SNAPSHOT + + tomcat9-maven-plugin + maven-plugin + Apache Tomcat Maven Plugin :: Tomcat 9.x + The Tomcat Maven Plugin provides goals to manipulate WAR projects within the Tomcat 8.x servlet container. + + + + ${basedir}/target/ + ${basedir}/src/test/simple-war-project-1.0-SNAPSHOT.war + ${basedir}/src/test/keystore + 9.0.96 + + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat9Version} + + + org.apache.tomcat + tomcat-util + ${tomcat9Version} + + + org.apache.tomcat + tomcat-coyote + ${tomcat9Version} + + + org.apache.tomcat + tomcat-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jdbc + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-dbcp + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-servlet-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jsp-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jasper + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jasper-el + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-el-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-catalina + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-tribes + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-catalina-ha + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-annotations-api + ${tomcat9Version} + + + + + + + org.apache.tomcat + tomcat-juli + ${tomcat9Version} + + + + + org.eclipse.jdt.core.compiler + ecj + + + + + + + org.apache.tomcat.maven + common-tomcat-maven-plugin + + + org.apache.tomcat.maven + tomcat9-war-runner + ${project.version} + + + org.apache.maven + maven-plugin-api + + + org.apache.maven.plugin-tools + maven-plugin-annotations + provided + + + org.apache.maven + maven-archiver + + + org.codehaus.plexus + plexus-classworlds + + + + commons-io + commons-io + + + + commons-lang + commons-lang + + + + org.apache.commons + commons-compress + + + + org.codehaus.plexus + plexus-archiver + + + + org.codehaus.plexus + plexus-utils + + + + org.apache.maven.shared + maven-filtering + + + nekohtml + xercesMinimal + + + + + + org.apache.tomcat.maven + tomcat-maven-plugin-it + test + + + junit + junit + test + + + + org.slf4j + jcl-over-slf4j + + + org.apache.logging.log4j + log4j-core + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + + + + + src/test/resources + true + + + + + org.apache.maven.plugins + maven-plugin-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/**IT* + + + ${project.build.directory} + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + pre-integration-test + + run + + + + + + + + + + + + + + + run-its + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + integration-test + + integration-test + + + + ${project.version} + ${verifier.maven.debug} + ${verifier.debugJvm} + ${its.http.port} + ${its.https.port} + ${its.ajp.port} + ${project.build.directory} + + false + false + + + + verify + + verify + + + + + + + + + + diff --git a/tomcat9-maven-plugin/src/it/settings.xml b/tomcat9-maven-plugin/src/it/settings.xml new file mode 100644 index 00000000..b9b7e260 --- /dev/null +++ b/tomcat9-maven-plugin/src/it/settings.xml @@ -0,0 +1,75 @@ + + + + + + + + it-repo + + true + + + + local.central + @localRepositoryUrl@ + + true + + + true + + + + local.snapshots + @localRepositoryUrl@ + + false + + + true + + + + + + local.central + @localRepositoryUrl@ + + true + + + true + + + + local.snapshots + @localRepositoryUrl@ + + false + + + true + + + + + + diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractCatalinaMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractCatalinaMojo.java new file mode 100644 index 00000000..1d71f644 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractCatalinaMojo.java @@ -0,0 +1,273 @@ +package org.apache.tomcat.maven.plugin.tomcat9; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.artifact.manager.WagonManager; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.wagon.authentication.AuthenticationInfo; +import org.apache.tomcat.maven.common.deployer.TomcatManager; +import org.apache.tomcat.maven.common.deployer.TomcatManagerException; +import org.apache.tomcat.maven.plugin.tomcat9.AbstractTomcat9Mojo; +import org.codehaus.plexus.util.StringUtils; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.StringTokenizer; + +/** + * Abstract goal that provides common configuration for Catalina-based goals. + * + * @author Mark Hobson + */ +public abstract class AbstractCatalinaMojo + extends AbstractTomcat9Mojo +{ + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + /** + * The name of this Maven plugin. Used to produce the user agent when communicating with Tomcat manager. + */ + private String name = "Apache Tomcat Maven Plugin"; + + /** + * The default username to use when authenticating with Tomcat manager. + */ + private static final String DEFAULT_USERNAME = "admin"; + + /** + * The default password to use when authenticating with Tomcat manager. + */ + private static final String DEFAULT_PASSWORD = ""; + + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * The Maven Wagon manager to use when obtaining server authentication details. + */ + @Component + private WagonManager wagonManager; + + /** + * The full URL of the Tomcat manager instance to use. + */ + @Parameter( property = "maven.tomcat.url", defaultValue = "http://localhost:8080/manager/text", required = true ) + private URL url; + + /** + * The server id in settings.xml to use when authenticating with Tomcat manager, or null to use + * defaults of username admin and no password. + */ + @Parameter( property = "maven.tomcat.server" ) + private String server; + + /** + * The URL encoding charset to use when communicating with Tomcat manager. + */ + @Parameter( property = "maven.tomcat.charset", defaultValue = "ISO-8859-1", required = true ) + private String charset; + + /** + * The tomcat username to use for deployment + * + * @since 1.0-alpha-2 + */ + @Parameter( property = "tomcat.username" ) + private String username; + + /** + * The password to use for deployment + * + * @since 1.0-alpha-2 + */ + @Parameter( property = "tomcat.password" ) + private String password; + + @Parameter( defaultValue = "${plugin.version}", required = true, readonly = true ) + private String version; + + // ---------------------------------------------------------------------- + // Fields + // ---------------------------------------------------------------------- + + /** + * The Tomcat manager wrapper object. + */ + private TomcatManager manager; + + // ---------------------------------------------------------------------- + // Mojo Implementation + // ---------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + public void execute() + throws MojoExecutionException + { + try + { + invokeManager(); + } + catch ( TomcatManagerException exception ) + { + throw new MojoExecutionException( + messagesProvider.getMessage( "AbstractCatalinaMojo.managerError", exception.getMessage() ) ); + } + catch ( IOException exception ) + { + throw new MojoExecutionException( messagesProvider.getMessage( "AbstractCatalinaMojo.managerIOError" ), + exception ); + } + } + + // ---------------------------------------------------------------------- + // Protected Methods + // ---------------------------------------------------------------------- + + /** + * Invokes Tomcat manager when this Mojo is executed. + * + * @throws org.apache.maven.plugin.MojoExecutionException + * if there was a problem executing this goal + * @throws org.apache.tomcat.maven.common.deployer.TomcatManagerException + * if the Tomcat manager request fails + * @throws java.io.IOException if an i/o error occurs + */ + protected abstract void invokeManager() + throws MojoExecutionException, TomcatManagerException, IOException; + + /** + * Gets the Tomcat manager wrapper object configured for this goal. + * + * @return the Tomcat manager wrapper object + * @throws org.apache.maven.plugin.MojoExecutionException + * if there was a problem obtaining the authentication details + */ + protected TomcatManager getManager() + throws MojoExecutionException + { + // lazily instantiate when config values have been injected + if ( manager == null ) + { + String userName; + String password; + + if ( server == null ) + { + // no server set, use defaults + getLog().debug( messagesProvider.getMessage( "AbstractCatalinaMojo.defaultAuth" ) ); + userName = DEFAULT_USERNAME; + password = DEFAULT_PASSWORD; + } + else + { + // obtain authenication details for specified server from wagon + AuthenticationInfo info = wagonManager.getAuthenticationInfo( server ); + if ( info == null ) + { + throw new MojoExecutionException( + messagesProvider.getMessage( "AbstractCatalinaMojo.unknownServer", server ) ); + } + + // derive username + userName = info.getUserName(); + if ( userName == null ) + { + getLog().debug( messagesProvider.getMessage( "AbstractCatalinaMojo.defaultUserName" ) ); + userName = DEFAULT_USERNAME; + } + + // derive password + password = info.getPassword(); + if ( password == null ) + { + getLog().debug( messagesProvider.getMessage( "AbstractCatalinaMojo.defaultPassword" ) ); + password = DEFAULT_PASSWORD; + } + } + + // if userName/password are defined in the mojo or the cli they override + if ( !StringUtils.isEmpty( this.username ) ) + { + userName = this.username; + password = this.password == null ? "" : this.password; + } + + manager = new TomcatManager( url, userName, password, charset, settings.isInteractiveMode() ); + manager.setUserAgent( name + "/" + version ); + } + + return manager; + } + + /** + * Gets the full URL of the Tomcat manager instance. + * + * @return the full URL of the Tomcat manager instance to use + */ + protected URL getURL() + { + return url; + } + + /** + * Gets the webapp context path to use when communicating with Tomcat manager. + * + * @return the webapp context path to use + */ + protected String getPath() + { + return path; + } + + /** + * Gets the URL of the deployed webapp. + * + * @return the URL of the deployed webapp + * @throws java.net.MalformedURLException if the deployed webapp URL is invalid + */ + protected URL getDeployedURL() + throws MalformedURLException + { + return new URL( getURL(), getPath() ); + } + + /** + * Splits the given string into lines and writes each one separately to the log at info level. + * + * @param string the string to write + */ + protected void log( String string ) + { + StringTokenizer tokenizer = new StringTokenizer( string, "\n\r" ); + + while ( tokenizer.hasMoreTokens() ) + { + getLog().info( tokenizer.nextToken() ); + } + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractTomcat9Mojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractTomcat9Mojo.java new file mode 100644 index 00000000..401bacd4 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractTomcat9Mojo.java @@ -0,0 +1,82 @@ +package org.apache.tomcat.maven.plugin.tomcat9; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.settings.Settings; +import org.apache.tomcat.maven.common.deployer.TomcatManagerResponse; +import org.apache.tomcat.maven.common.messages.MessagesProvider; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +public abstract class AbstractTomcat9Mojo + extends AbstractMojo +{ + @Component + protected Settings settings; + + @Component + protected MessagesProvider messagesProvider; + + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * The webapp context path to use for the web application being run. This must always start with a forward-slash + * ('/'). + */ + @Parameter(defaultValue = "/${project.artifactId}", property = "maven.tomcat.path", required = true) + protected String path; + + + protected String getPath() + { + return path; + } + + /** + * Check response of Tomcat to know if ok or not. + * + * @param tomcatResponse response of tomcat return by TomcatManager class + * @throws org.apache.maven.plugin.MojoExecutionException + * if HTTP status code greater than 400 (included) + */ + protected void checkTomcatResponse( TomcatManagerResponse tomcatResponse ) + throws MojoExecutionException + { + int statusCode = tomcatResponse.getStatusCode(); + + if ( statusCode >= 400 ) + { + getLog().error( messagesProvider.getMessage( "tomcatHttpStatusError", statusCode, + tomcatResponse.getReasonPhrase() ) ); + + throw new MojoExecutionException( + messagesProvider.getMessage( "tomcatHttpStatusError", statusCode, + tomcatResponse.getReasonPhrase() ) + ": " + + tomcatResponse.getHttpResponseBody() ); + } + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractWarCatalinaMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractWarCatalinaMojo.java new file mode 100644 index 00000000..754b6d7f --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/AbstractWarCatalinaMojo.java @@ -0,0 +1,84 @@ +package org.apache.tomcat.maven.plugin.tomcat9; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; + +/** + * Abstract goal that provides common configuration for Catalina-based goals. + * + * @author Mark Hobson + */ +public abstract class AbstractWarCatalinaMojo + extends AbstractCatalinaMojo +{ + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * The packaging of the Maven project that this goal operates upon. + */ + @Parameter( defaultValue = "${project.packaging}", required = true, readonly = true ) + private String packaging; + + /** + * If set to true ignore if packaging of project is not 'war'. + * + * @since 1.1 + */ + @Parameter( property = "tomcat.ignorePackaging", defaultValue = "false" ) + private boolean ignorePackaging; + + // ---------------------------------------------------------------------- + // Mojo Implementation + // ---------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public void execute() + throws MojoExecutionException + { + if ( !isWar() ) + { + getLog().info( messagesProvider.getMessage( "AbstractWarCatalinaMojo.nonWar" ) ); + return; + } + + super.execute(); + } + + // ---------------------------------------------------------------------- + // Protected Methods + // ---------------------------------------------------------------------- + + /** + * Gets whether this project uses WAR packaging. + * + * @return whether this project uses WAR packaging + */ + protected boolean isWar() + { + return "war".equals( packaging ) || ignorePackaging; + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/AbstractDeployMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/AbstractDeployMojo.java new file mode 100644 index 00000000..de933ce4 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/AbstractDeployMojo.java @@ -0,0 +1,226 @@ +package org.apache.tomcat.maven.plugin.tomcat9.deploy; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.tomcat.maven.common.deployer.TomcatManagerException; +import org.apache.tomcat.maven.common.deployer.TomcatManagerResponse; +import org.apache.tomcat.maven.plugin.tomcat9.AbstractWarCatalinaMojo; + +import java.io.File; +import java.io.IOException; +import java.net.URL; + +/** + * Deploy a WAR to Tomcat. + * + * @author Mark Hobson + */ +public abstract class AbstractDeployMojo + extends AbstractWarCatalinaMojo +{ + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * The deployment mode to use. This must be either war to deploy the war, context to + * deploy the context XML file, or both to deploy the war with the context XML file. + */ + @Parameter( property = "maven.tomcat.mode", defaultValue = "war", required = true ) + private String mode; + + /** + * The path of the Tomcat context XML file. This is not used for war deployment mode. + */ + @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}/META-INF/context.xml" ) + private File contextFile; + + /** + * Whether Tomcat should automatically undeploy webapps that already exist when deploying. + */ + @Parameter( property = "maven.tomcat.update", defaultValue = "false", required = true ) + private boolean update; + + /** + * The Tomcat webapp tag name to use. + */ + @Parameter( property = "maven.tomcat.tag" ) + private String tag; + + // ---------------------------------------------------------------------- + // Protected Methods + // ---------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public void invokeManager() + throws MojoExecutionException, TomcatManagerException, IOException + { + if ( "war".equals( mode ) ) + { + deployWar(); + } + else if ( "context".equals( mode ) ) + { + deployContext(); + } + else if ( "both".equals( mode ) ) + { + deployWarAndContext(); + } + else + { + throw new MojoExecutionException( messagesProvider.getMessage( "AbstractDeployMojo.unknownMode", mode ) ); + } + } + + /** + * Gets the Tomcat WAR file. This may be a file or a directory depending on the deployment mode. + * + * @return the Tomcat WAR file. + */ + protected abstract File getWarFile(); + + /** + * Ensures that the Tomcat WAR file exists and is the correct type for the deployment mode. + * + * @throws org.apache.maven.plugin.MojoExecutionException + * if the WAR file does not exist or is not the correct type for the deployment mode + */ + protected abstract void validateWarFile() + throws MojoExecutionException; + + /** + * Gets the Tomcat context XML file. + * + * @return the Tomcat context XML file. + */ + protected File getContextFile() + { + return contextFile; + } + + /** + * Ensures that the Tomcat context XML file exists and is indeed a file. + * + * @throws org.apache.maven.plugin.MojoExecutionException + * if the context file does not exist or is not a file + */ + protected void validateContextFile() + throws MojoExecutionException + { + if ( !contextFile.exists() || !contextFile.isFile() ) + { + throw new MojoExecutionException( + messagesProvider.getMessage( "AbstractDeployMojo.missingContext", contextFile.getPath() ) ); + } + } + + /** + * Gets whether Tomcat should automatically undeploy webapps that already exist when deploying. + * + * @return whether Tomcat should automatically undeploy webapps that already exist when deploying + */ + protected boolean isUpdate() + { + return update; + } + + /** + * Gets the Tomcat webapp tag name to use. + * + * @return the Tomcat webapp tag name to use + */ + protected String getTag() + { + return tag; + } + + /** + * Deploys the WAR to Tomcat. + * + * @throws org.apache.maven.plugin.MojoExecutionException + * if there was a problem locating the WAR + * @throws org.apache.tomcat.maven.common.deployer.TomcatManagerException + * if the Tomcat manager request fails + * @throws java.io.IOException if an i/o error occurs + */ + protected void deployWar() + throws MojoExecutionException, TomcatManagerException, IOException + { + validateWarFile(); + + getLog().info( messagesProvider.getMessage( "AbstractDeployMojo.deployingWar", getDeployedURL() ) ); + + URL warURL = getWarFile().toURL(); + log( getManager().deploy( getPath(), warURL, isUpdate(), getTag() ).getHttpResponseBody() ); + } + + /** + * Deploys the context XML file to Tomcat. + * + * @throws org.apache.maven.plugin.MojoExecutionException + * if there was a problem locating the context XML file + * @throws org.apache.tomcat.maven.common.deployer.TomcatManagerException + * if the Tomcat manager request fails + * @throws java.io.IOException if an i/o error occurs + */ + protected void deployContext() + throws MojoExecutionException, TomcatManagerException, IOException + { + validateContextFile(); + + getLog().info( messagesProvider.getMessage( "AbstractDeployMojo.deployingContext", getDeployedURL() ) ); + + URL contextURL = getContextFile().toURL(); + log( getManager().deployContext( getPath(), contextURL, isUpdate(), getTag() ).getHttpResponseBody() ); + } + + /** + * Deploys the WAR and context XML file to Tomcat. + * + * @throws org.apache.maven.plugin.MojoExecutionException + * if there was a problem locating either the WAR or the context XML file + * @throws org.apache.tomcat.maven.common.deployer.TomcatManagerException + * if the Tomcat manager request fails + * @throws java.io.IOException if an i/o error occurs + */ + protected void deployWarAndContext() + throws MojoExecutionException, TomcatManagerException, IOException + { + validateWarFile(); + validateContextFile(); + + getLog().info( messagesProvider.getMessage( "AbstractDeployMojo.deployingWarContext", getDeployedURL() ) ); + + URL warURL = getWarFile().toURL(); + URL contextURL = getContextFile().toURL(); + + TomcatManagerResponse tomcatResponse = getManager().deployContext( getPath(), contextURL, warURL, isUpdate(), getTag() ); + + checkTomcatResponse( tomcatResponse ); + + log( tomcatResponse.getHttpResponseBody() ); + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/AbstractDeployWarMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/AbstractDeployWarMojo.java new file mode 100644 index 00000000..891ec496 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/AbstractDeployWarMojo.java @@ -0,0 +1,95 @@ +package org.apache.tomcat.maven.plugin.tomcat9.deploy; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.tomcat.maven.common.deployer.TomcatManagerException; +import org.apache.tomcat.maven.common.deployer.TomcatManagerResponse; + +import java.io.File; +import java.io.IOException; + +/** + * @author olamy + * @since 1.0-alpha-2 + */ +public class AbstractDeployWarMojo + extends AbstractDeployMojo +{ + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * The path of the WAR file to deploy. + */ + @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}.war", required = true ) + private File warFile; + + // ---------------------------------------------------------------------- + // Protected Methods + // ---------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + protected File getWarFile() + { + return warFile; + } + + /** + * {@inheritDoc} + */ + @Override + protected void validateWarFile() + throws MojoExecutionException + { + if ( !warFile.exists() || !warFile.isFile() ) + { + throw new MojoExecutionException( + messagesProvider.getMessage( "DeployMojo.missingWar", warFile.getPath() ) ); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void deployWar() + throws MojoExecutionException, TomcatManagerException, IOException + { + validateWarFile(); + + getLog().info( messagesProvider.getMessage( "AbstractDeployMojo.deployingWar", getDeployedURL() ) ); + + TomcatManagerResponse tomcatManagerResponse = + getManager().deploy( getPath(), warFile, isUpdate(), getTag(), warFile.length() ); + + checkTomcatResponse( tomcatManagerResponse ); + + getLog().info( "tomcatManager status code:" + tomcatManagerResponse.getStatusCode() + ", ReasonPhrase:" + + tomcatManagerResponse.getReasonPhrase() ); + + log( tomcatManagerResponse.getHttpResponseBody() ); + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/DeployMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/DeployMojo.java new file mode 100644 index 00000000..fcf0395e --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/DeployMojo.java @@ -0,0 +1,37 @@ +package org.apache.tomcat.maven.plugin.tomcat9.deploy; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; + +/** + * Deploy a WAR to Tomcat. + * + * @author Mark Hobson + */ +@Mojo(name = "deploy", threadSafe = true) +@Execute(phase = LifecyclePhase.PACKAGE) +public class DeployMojo + extends AbstractDeployWarMojo +{ + // no-op : only mojo metadata overriding +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/DeployOnlyMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/DeployOnlyMojo.java new file mode 100644 index 00000000..aa7b56a3 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/DeployOnlyMojo.java @@ -0,0 +1,35 @@ +package org.apache.tomcat.maven.plugin.tomcat9.deploy; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Mojo; + +/** + * Deploy a WAR to Tomcat without forking the package lifecycle. + * + * @author olamy + * @since 1.0-alpha-2 + */ +@Mojo(name = "deploy-only", threadSafe = true) +public class DeployOnlyMojo + extends AbstractDeployWarMojo +{ + // no-op : only mojo metadata overriding +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/RedeployMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/RedeployMojo.java new file mode 100644 index 00000000..5c1e006b --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/RedeployMojo.java @@ -0,0 +1,43 @@ +package org.apache.tomcat.maven.plugin.tomcat9.deploy; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; + +/** + * Redeploy a WAR in Tomcat. (Alias for the deploy goal with its update parameter set to true.) + * + * @author Olivier Lamy + * @since 2.1 + */ +@Mojo(name = "redeploy", threadSafe = true) +@Execute(phase = LifecyclePhase.PACKAGE) +public class RedeployMojo + extends DeployMojo +{ + @Override + protected boolean isUpdate() + { + return true; + } + +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/RedeployOnlyMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/RedeployOnlyMojo.java new file mode 100644 index 00000000..9bad94b5 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/RedeployOnlyMojo.java @@ -0,0 +1,40 @@ +package org.apache.tomcat.maven.plugin.tomcat9.deploy; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Mojo; + +/** + * Redeploy a WAR in Tomcat without forking the package lifecycle. + * (Alias for the deploy-only goal with its update parameter set to true.) + * + * @since 2.1 + */ +@Mojo( name = "redeploy-only", threadSafe = true ) +public class RedeployOnlyMojo + extends DeployOnlyMojo +{ + @Override + protected boolean isUpdate() + { + return true; + } + +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/UndeployMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/UndeployMojo.java new file mode 100644 index 00000000..c2d2dd48 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/deploy/UndeployMojo.java @@ -0,0 +1,84 @@ +package org.apache.tomcat.maven.plugin.tomcat9.deploy; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.tomcat.maven.common.deployer.TomcatManagerException; +import org.apache.tomcat.maven.common.deployer.TomcatManagerResponse; +import org.apache.tomcat.maven.plugin.tomcat9.AbstractWarCatalinaMojo; + +import java.io.IOException; + +/** + * Undeploy a WAR from Tomcat. + * + * @since 2.1 + */ +@Mojo( name = "undeploy", threadSafe = true ) +public class UndeployMojo + extends AbstractWarCatalinaMojo +{ + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * Whether to fail the build if the web application cannot be undeployed. + */ + @Parameter( property = "maven.tomcat.failOnError", defaultValue = "true" ) + private boolean failOnError; + + // ---------------------------------------------------------------------- + // Protected Methods + // ---------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + protected void invokeManager() + throws MojoExecutionException, TomcatManagerException, IOException + { + getLog().info( messagesProvider.getMessage( "UndeployMojo.undeployingApp", getDeployedURL() ) ); + + try + { + + TomcatManagerResponse tomcatResponse = getManager().undeploy( getPath() ); + + checkTomcatResponse( tomcatResponse ); + + log( tomcatResponse.getHttpResponseBody() ); + + } + catch ( TomcatManagerException e ) + { + if ( failOnError ) + { + throw e; + } + + getLog().warn( messagesProvider.getMessage( "UndeployMojo.undeployError", e.getMessage() ) ); + } + } + +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractExecWarMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractExecWarMojo.java new file mode 100644 index 00000000..5ed0f444 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractExecWarMojo.java @@ -0,0 +1,679 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.archivers.ArchiveOutputStream; +import org.apache.commons.compress.archivers.ArchiveStreamFactory; +import org.apache.commons.compress.archivers.jar.JarArchiveEntry; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.model.Dependency; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectHelper; +import org.apache.tomcat.maven.plugin.tomcat9.AbstractTomcat9Mojo; +import org.apache.tomcat.maven.runner.Tomcat9Runner; +import org.apache.tomcat.maven.runner.Tomcat9RunnerCli; +import org.codehaus.plexus.archiver.jar.Manifest; +import org.codehaus.plexus.archiver.jar.ManifestException; +import org.codehaus.plexus.util.DirectoryScanner; +import org.codehaus.plexus.util.SelectorUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +public abstract class AbstractExecWarMojo + extends AbstractTomcat9Mojo +{ + + @Parameter( defaultValue = "${project.artifact}", required = true, readonly = true ) + protected Artifact projectArtifact; + + /** + * The maven project. + */ + @Parameter( defaultValue = "${project}", required = true, readonly = true ) + protected MavenProject project; + + @Parameter( defaultValue = "${plugin.artifacts}", required = true ) + protected List pluginArtifacts; + + @Parameter( defaultValue = "${project.build.directory}" ) + protected File buildDirectory; + + /** + * Path under {@link #buildDirectory} where this mojo may do temporary work. + */ + @Parameter( defaultValue = "${project.build.directory}/tomcat9-maven-plugin-exec" ) + private File pluginWorkDirectory; + + @Parameter( property = "maven.tomcat.exec.war.tomcatConf", defaultValue = "src/main/tomcatconf" ) + protected File tomcatConfigurationFilesDirectory; + + @Parameter( defaultValue = "src/main/tomcatconf/server.xml", property = "maven.tomcat.exec.war.serverXml" ) + protected File serverXml; + + /** + * Name of the generated exec JAR. + */ + @Parameter( property = "tomcat.jar.finalName", + defaultValue = "${project.artifactId}-${project.version}-war-exec.jar", required = true ) + protected String finalName; + + /** + * Skip the execution + * + * @since 2.2 + */ + @Parameter( property = "maven.tomcat.skip", defaultValue = "false" ) + private boolean skip; + + /** + * The webapp context path to use for the web application being run. + * The name to store webapp in exec jar. Do not use / + */ + @Parameter( property = "maven.tomcat.path", defaultValue = "${project.artifactId}", required = true ) + protected String path; + + @Parameter + protected List warRunDependencies; + + @Component + protected ArtifactResolver artifactResolver; + + /** + * Maven Artifact Factory component. + */ + @Component + protected ArtifactFactory artifactFactory; + + /** + * Location of the local repository. + */ + @Parameter( defaultValue = "${localRepository}", required = true, readonly = true ) + protected ArtifactRepository local; + + /** + * List of Remote Repositories used by the resolver + */ + @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true ) + protected List remoteRepos; + + @Component + protected MavenProjectHelper projectHelper; + + /** + * Attach or not the generated artifact to the build (use true if you want to install or deploy it) + */ + @Parameter( property = "maven.tomcat.exec.war.attachArtifact", defaultValue = "true", required = true ) + protected boolean attachArtifact; + + + /** + * the classifier to use for the attached/generated artifact + */ + @Parameter( property = "maven.tomcat.exec.war.attachArtifactClassifier", defaultValue = "exec-war", + required = true ) + protected String attachArtifactClassifier; + + + /** + * the type to use for the attached/generated artifact + */ + @Parameter( property = "maven.tomcat.exec.war.attachArtifactType", defaultValue = "jar", required = true ) + protected String attachArtifactClassifierType; + + /** + * to enable naming when starting tomcat + */ + @Parameter( property = "maven.tomcat.exec.war.enableNaming", defaultValue = "false", required = true ) + protected boolean enableNaming; + + /** + * see http://tomcat.apache.org/tomcat-7.0-doc/config/valve.html + */ + @Parameter( property = "maven.tomcat.exec.war.accessLogValveFormat", defaultValue = "%h %l %u %t %r %s %b %I %D", + required = true ) + protected String accessLogValveFormat; + + /** + * list of extra dependencies to add in the standalone tomcat jar: your jdbc driver, mail.jar etc.. + * Those dependencies will be in root classloader. + */ + @Parameter + protected List extraDependencies; + + /** + * list of extra resources to add in the standalone tomcat jar: your logger configuration etc + */ + @Parameter + protected List extraResources; + + /** + * Main class to use for starting the standalone jar. + */ + @Parameter( property = "maven.tomcat.exec.war.mainClass", + defaultValue = "org.apache.tomcat.maven.runner.Tomcat9RunnerCli", required = true ) + protected String mainClass; + + /** + * which connector protocol to use HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol + */ + @Parameter( property = "maven.tomcat.exec.war.connectorHttpProtocol", defaultValue = "HTTP/1.1", required = true ) + protected String connectorHttpProtocol; + + /** + * configure a default http port for the standalone jar + * + * @since 2.2 + */ + @Parameter( property = "maven.tomcat.exec.war.httpPort" ) + protected String httpPort; + + /** + * File patterns to exclude from extraDependencies + * + * @since 2.2 + */ + @Parameter + protected String[] excludes; + + public void execute() + throws MojoExecutionException, MojoFailureException + { + if ( this.skip ) + { + getLog().info( "skip execution" ); + return; + } + //project.addAttachedArtifact( ); + File warExecFile = new File( buildDirectory, finalName ); + if ( warExecFile.exists() ) + { + warExecFile.delete(); + } + + File execWarJar = new File( buildDirectory, finalName ); + + FileOutputStream execWarJarOutputStream = null; + ArchiveOutputStream os = null; + File tmpPropertiesFile = null; + File tmpManifestFile = null; + FileOutputStream tmpPropertiesFileOutputStream = null; + PrintWriter tmpManifestWriter = null; + + try + { + + tmpPropertiesFile = new File( buildDirectory, "war-exec.properties" ); + if ( tmpPropertiesFile.exists() ) + { + tmpPropertiesFile.delete(); + } + tmpPropertiesFile.getParentFile().mkdirs(); + + tmpManifestFile = new File( buildDirectory, "war-exec.manifest" ); + if ( tmpManifestFile.exists() ) + { + tmpManifestFile.delete(); + } + tmpPropertiesFileOutputStream = new FileOutputStream( tmpPropertiesFile ); + execWarJar.getParentFile().mkdirs(); + execWarJar.createNewFile(); + execWarJarOutputStream = new FileOutputStream( execWarJar ); + + tmpManifestWriter = new PrintWriter( tmpManifestFile ); + + // store : + //* wars in the root: foo.war + //* tomcat jars + //* file tomcat.standalone.properties with possible values : + // * useServerXml=true/false to use directly the one provided + // * enableNaming=true/false + // * wars=foo.war|contextpath;bar.war ( |contextpath is optionnal if empty use the war name ) + // * accessLogValveFormat= + // * connectorhttpProtocol: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol + //* optionnal: conf/ with usual tomcat configuration files + //* MANIFEST with Main-Class + + Properties properties = new Properties(); + + properties.put(Tomcat9Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY, + Long.toString( System.currentTimeMillis() ) ); + properties.put(Tomcat9Runner.ENABLE_NAMING_KEY, Boolean.toString( enableNaming ) ); + properties.put(Tomcat9Runner.ACCESS_LOG_VALVE_FORMAT_KEY, accessLogValveFormat ); + properties.put(Tomcat9Runner.HTTP_PROTOCOL_KEY, connectorHttpProtocol ); + + if ( httpPort != null ) + { + properties.put(Tomcat9Runner.HTTP_PORT_KEY, httpPort ); + } + + os = new ArchiveStreamFactory().createArchiveOutputStream( ArchiveStreamFactory.JAR, + execWarJarOutputStream ); + + if ( "war".equals( project.getPackaging() ) ) + { + + os.putArchiveEntry( new JarArchiveEntry( StringUtils.removeStart( path, "/" ) + ".war" ) ); + IOUtils.copy( new FileInputStream( projectArtifact.getFile() ), os ); + os.closeArchiveEntry(); + + properties.put(Tomcat9Runner.WARS_KEY, StringUtils.removeStart( path, "/" ) + ".war|" + path ); + } + else if ( warRunDependencies != null && !warRunDependencies.isEmpty() ) + { + for ( WarRunDependency warRunDependency : warRunDependencies ) + { + if ( warRunDependency.dependency != null ) + { + Dependency dependency = warRunDependency.dependency; + String version = dependency.getVersion(); + if ( StringUtils.isEmpty( version ) ) + { + version = findArtifactVersion( dependency ); + } + + if ( StringUtils.isEmpty( version ) ) + { + throw new MojoExecutionException( + "Dependency '" + dependency.getGroupId() + "':'" + dependency.getArtifactId() + + "' does not have version specified" ); + } + Artifact artifact = artifactFactory.createArtifactWithClassifier( dependency.getGroupId(), // + dependency.getArtifactId(), // + version, // + dependency.getType(), // + dependency.getClassifier() ); + + artifactResolver.resolve( artifact, this.remoteRepos, this.local ); + + File warFileToBundle = new File( resolvePluginWorkDir(), artifact.getFile().getName() ); + FileUtils.copyFile( artifact.getFile(), warFileToBundle ); + + if ( warRunDependency.contextXml != null ) + { + warFileToBundle = addContextXmlToWar( warRunDependency.contextXml, warFileToBundle ); + } + final String warFileName = artifact.getFile().getName(); + os.putArchiveEntry( new JarArchiveEntry( warFileName ) ); + IOUtils.copy( new FileInputStream( warFileToBundle ), os ); + os.closeArchiveEntry(); + String propertyWarValue = properties.getProperty(Tomcat9Runner.WARS_KEY ); + String contextPath = + StringUtils.isEmpty( warRunDependency.contextPath ) ? "/" : warRunDependency.contextPath; + if ( propertyWarValue != null ) + { + properties.put(Tomcat9Runner.WARS_KEY, + propertyWarValue + ";" + warFileName + "|" + contextPath ); + } + else + { + properties.put(Tomcat9Runner.WARS_KEY, warFileName + "|" + contextPath ); + } + } + } + } + + if ( serverXml != null && serverXml.exists() ) + { + os.putArchiveEntry( new JarArchiveEntry( "conf/server.xml" ) ); + IOUtils.copy( new FileInputStream( serverXml ), os ); + os.closeArchiveEntry(); + properties.put(Tomcat9Runner.USE_SERVER_XML_KEY, Boolean.TRUE.toString() ); + } + else + { + properties.put(Tomcat9Runner.USE_SERVER_XML_KEY, Boolean.FALSE.toString() ); + } + + os.putArchiveEntry( new JarArchiveEntry( "conf/web.xml" ) ); + IOUtils.copy( getClass().getResourceAsStream( "/conf/web.xml" ), os ); + os.closeArchiveEntry(); + + properties.store( tmpPropertiesFileOutputStream, "created by Apache Tomcat Maven plugin" ); + + tmpPropertiesFileOutputStream.flush(); + tmpPropertiesFileOutputStream.close(); + + os.putArchiveEntry(new JarArchiveEntry( Tomcat9RunnerCli.STAND_ALONE_PROPERTIES_FILENAME ) ); + IOUtils.copy( new FileInputStream( tmpPropertiesFile ), os ); + os.closeArchiveEntry(); + + // add tomcat classes + for ( Artifact pluginArtifact : pluginArtifacts ) + { + if ( StringUtils.equals( "org.apache.tomcat", pluginArtifact.getGroupId() ) // + || StringUtils.equals( "org.apache.tomcat.embed", pluginArtifact.getGroupId() ) // + || StringUtils.equals( "org.eclipse.jdt.core.compiler", pluginArtifact.getGroupId() ) // + || StringUtils.equals( "commons-cli", pluginArtifact.getArtifactId() ) // + || StringUtils.equals( "tomcat9-war-runner", pluginArtifact.getArtifactId() ) ) + { + JarFile jarFile = new JarFile( pluginArtifact.getFile() ); + extractJarToArchive( jarFile, os, null ); + } + } + + // add extra dependencies + if ( extraDependencies != null && !extraDependencies.isEmpty() ) + { + for ( Dependency dependency : extraDependencies ) + { + String version = dependency.getVersion(); + if ( StringUtils.isEmpty( version ) ) + { + version = findArtifactVersion( dependency ); + } + + if ( StringUtils.isEmpty( version ) ) + { + throw new MojoExecutionException( + "Dependency '" + dependency.getGroupId() + "':'" + dependency.getArtifactId() + + "' does not have version specified" ); + } + + // String groupId, String artifactId, String version, String scope, String type + Artifact artifact = artifactFactory.createArtifact( dependency.getGroupId(), // + dependency.getArtifactId(), // + version, // + dependency.getScope(), // + dependency.getType() ); + + artifactResolver.resolve( artifact, this.remoteRepos, this.local ); + JarFile jarFile = new JarFile( artifact.getFile() ); + extractJarToArchive( jarFile, os, this.excludes ); + } + } + + Manifest manifest = new Manifest(); + + Manifest.Attribute mainClassAtt = new Manifest.Attribute(); + mainClassAtt.setName( "Main-Class" ); + mainClassAtt.setValue( mainClass ); + manifest.addConfiguredAttribute( mainClassAtt ); + + manifest.write( tmpManifestWriter ); + tmpManifestWriter.flush(); + tmpManifestWriter.close(); + + os.putArchiveEntry( new JarArchiveEntry( "META-INF/MANIFEST.MF" ) ); + IOUtils.copy( new FileInputStream( tmpManifestFile ), os ); + os.closeArchiveEntry(); + + if ( attachArtifact ) + { + //MavenProject project, String artifactType, String artifactClassifier, File artifactFile + projectHelper.attachArtifact( project, attachArtifactClassifierType, attachArtifactClassifier, + execWarJar ); + } + + if ( extraResources != null ) + { + for ( ExtraResource extraResource : extraResources ) + { + + DirectoryScanner directoryScanner = new DirectoryScanner(); + directoryScanner.setBasedir( extraResource.getDirectory() ); + directoryScanner.addDefaultExcludes(); + directoryScanner.setExcludes( toStringArray( extraResource.getExcludes() ) ); + directoryScanner.setIncludes( toStringArray( extraResource.getIncludes() ) ); + directoryScanner.scan(); + for ( String includeFile : directoryScanner.getIncludedFiles() ) + { + getLog().debug( "include file:" + includeFile ); + os.putArchiveEntry( new JarArchiveEntry( includeFile ) ); + IOUtils.copy( new FileInputStream( new File( extraResource.getDirectory(), includeFile ) ), + os ); + os.closeArchiveEntry(); + } + } + } + + if ( tomcatConfigurationFilesDirectory != null && tomcatConfigurationFilesDirectory.exists() ) + { + // Because its the tomcat default dir for configs + String aConfigOutputDir = "conf/"; + copyDirectoryContentIntoArchive( tomcatConfigurationFilesDirectory, aConfigOutputDir, os ); + } + + } + catch ( ManifestException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( ArchiveException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( ArtifactNotFoundException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( ArtifactResolutionException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + finally + { + IOUtils.closeQuietly( os ); + IOUtils.closeQuietly( tmpManifestWriter ); + IOUtils.closeQuietly( execWarJarOutputStream ); + IOUtils.closeQuietly( tmpPropertiesFileOutputStream ); + } + } + + protected String findArtifactVersion( Dependency dependency ) + { + // search in project.dependencies + for ( Dependency projectDependency : (List) this.project.getDependencies() ) + { + if ( sameDependencyWithoutVersion( dependency, projectDependency ) ) + { + return projectDependency.getVersion(); + } + } + + // search in project.dependencies + for ( Dependency projectDependency : this.project.getDependencyManagement().getDependencies() ) + { + if ( sameDependencyWithoutVersion( dependency, projectDependency ) ) + { + return projectDependency.getVersion(); + } + } + + return null; + } + + protected boolean sameDependencyWithoutVersion( Dependency that, Dependency dependency ) + { + return StringUtils.equals( that.getGroupId(), dependency.getGroupId() ) && StringUtils.equals( + that.getArtifactId(), dependency.getArtifactId() ); + } + + protected void copyDirectoryContentIntoArchive( File sourceFolder, String destinationPath, + ArchiveOutputStream archiveOutputStream ) + throws IOException + { + + // Scan the directory + DirectoryScanner directoryScanner = new DirectoryScanner(); + directoryScanner.setBasedir( sourceFolder ); + directoryScanner.addDefaultExcludes(); + directoryScanner.scan(); + + // Each File + for ( String includeFileName : directoryScanner.getIncludedFiles() ) + { + getLog().debug( "include configuration file : " + destinationPath + includeFileName ); + File inputFile = new File( sourceFolder, includeFileName ); + + FileInputStream sourceFileInputStream = null; + try + { + sourceFileInputStream = new FileInputStream( inputFile ); + + archiveOutputStream.putArchiveEntry( new JarArchiveEntry( destinationPath + includeFileName ) ); + IOUtils.copy( sourceFileInputStream, archiveOutputStream ); + archiveOutputStream.closeArchiveEntry(); + } + finally + { + IOUtils.closeQuietly( sourceFileInputStream ); + } + } + + } + + /** + * Resolves the plugin work dir as a sub directory of {@link #buildDirectory}, creating it if it does not exist. + * + * @return File representing the resolved plugin work dir + * @throws MojoExecutionException if the plugin work dir cannot be created + */ + protected File resolvePluginWorkDir() + throws MojoExecutionException + { + if ( !pluginWorkDirectory.exists() && !pluginWorkDirectory.mkdirs() ) + { + throw new MojoExecutionException( + "Could not create plugin work directory at " + pluginWorkDirectory.getAbsolutePath() ); + } + + return pluginWorkDirectory; + + } + + protected String[] toStringArray( List list ) + { + if ( list == null || list.isEmpty() ) + { + return new String[0]; + } + List res = new ArrayList( list.size() ); + + for ( Iterator ite = list.iterator(); ite.hasNext(); ) + { + res.add( (String) ite.next() ); + } + return res.toArray( new String[res.size()] ); + } + + + /** + * return file can be deleted + */ + protected File addContextXmlToWar( File contextXmlFile, File warFile ) + throws IOException, ArchiveException + { + ArchiveOutputStream os = null; + OutputStream warOutputStream = null; + File tmpWar = File.createTempFile( "tomcat", "war-exec" ); + tmpWar.deleteOnExit(); + + try + { + warOutputStream = new FileOutputStream( tmpWar ); + os = new ArchiveStreamFactory().createArchiveOutputStream( ArchiveStreamFactory.JAR, warOutputStream ); + os.putArchiveEntry( new JarArchiveEntry( "META-INF/context.xml" ) ); + IOUtils.copy( new FileInputStream( contextXmlFile ), os ); + os.closeArchiveEntry(); + + JarFile jarFile = new JarFile( warFile ); + extractJarToArchive( jarFile, os, null ); + os.flush(); + } + finally + { + IOUtils.closeQuietly( os ); + IOUtils.closeQuietly( warOutputStream ); + } + return tmpWar; + } + + /** + * Copy the contents of a jar file to another archive + * + * @param file The input jar file + * @param os The output archive + * @throws IOException + */ + protected void extractJarToArchive( JarFile file, ArchiveOutputStream os, String[] excludes ) + throws IOException + { + Enumeration entries = file.entries(); + while ( entries.hasMoreElements() ) + { + JarEntry j = entries.nextElement(); + + if ( excludes != null && excludes.length > 0 ) + { + for ( String exclude : excludes ) + { + if ( SelectorUtils.match( exclude, j.getName() ) ) + { + continue; + } + } + } + + if ( StringUtils.equalsIgnoreCase( j.getName(), "META-INF/MANIFEST.MF" ) ) + { + continue; + } + os.putArchiveEntry( new JarArchiveEntry( j.getName() ) ); + IOUtils.copy( file.getInputStream( j ), os ); + os.closeArchiveEntry(); + } + if ( file != null ) + { + file.close(); + } + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractRunMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractRunMojo.java new file mode 100644 index 00000000..1e9ffb07 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractRunMojo.java @@ -0,0 +1,1563 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.catalina.Context; +import org.apache.catalina.Host; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.loader.WebappLoader; +import org.apache.catalina.realm.MemoryRealm; +import org.apache.catalina.servlets.DefaultServlet; +import org.apache.catalina.startup.Catalina; +import org.apache.catalina.startup.CatalinaProperties; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.valves.AccessLogValve; +import org.apache.catalina.webresources.StandardRoot; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.filtering.MavenFileFilter; +import org.apache.maven.shared.filtering.MavenFileFilterRequest; +import org.apache.maven.shared.filtering.MavenFilteringException; +import org.apache.tomcat.JarScanner; +import org.apache.tomcat.maven.common.config.AbstractWebapp; +import org.apache.tomcat.maven.common.run.EmbeddedRegistry; +import org.apache.tomcat.maven.common.run.ExternalRepositoriesReloadableWebappLoader; +import org.apache.tomcat.maven.plugin.tomcat9.AbstractTomcat9Mojo; +import org.apache.tomcat.util.scan.StandardJarScanner; +import org.codehaus.plexus.archiver.ArchiverException; +import org.codehaus.plexus.archiver.UnArchiver; +import org.codehaus.plexus.archiver.manager.ArchiverManager; +import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; +import org.codehaus.plexus.classworlds.ClassWorld; +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; +import org.codehaus.plexus.util.DirectoryScanner; +import org.codehaus.plexus.util.FileUtils; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +public abstract class AbstractRunMojo + extends AbstractTomcat9Mojo +{ + // --------------------------------------------------------------------- + // Mojo Components + // --------------------------------------------------------------------- + + /** + * Used to look up Artifacts in the remote repository. + */ + @Component + protected ArtifactFactory factory; + + /** + * Location of the local repository. + */ + @Parameter( defaultValue = "${localRepository}", required = true, readonly = true ) + private ArtifactRepository local; + + /** + * Used to look up Artifacts in the remote repository. + */ + @Component + protected ArtifactResolver resolver; + + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * The packaging of the Maven project that this goal operates upon. + */ + @Parameter( defaultValue = "${project.packaging}", required = true, readonly = true ) + private String packaging; + + /** + * The directory to create the Tomcat server configuration under. + */ + @Parameter( defaultValue = "${project.build.directory}/tomcat" ) + private File configurationDir; + + /** + * The port to run the Tomcat server on. + * Will be exposed as System props and session.executionProperties with key tomcat.maven.http.port + */ + @Parameter( property = "maven.tomcat.port", defaultValue = "8080" ) + private int port; + + /** + * this IP address will be used on all ports + * + * @since 2.2 + */ + @Parameter( property = "maven.tomcat.address" ) + private String address; + + /** + * The AJP port to run the Tomcat server on. + * By default it's 0 this means won't be started. + * The ajp connector will be started only for value > 0. + * Will be exposed as System props and session.executionProperties with key tomcat.maven.ajp.port + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.ajp.port", defaultValue = "0" ) + private int ajpPort; + + /** + * The AJP protocol to run the Tomcat server on. + * By default it's ajp. + * NOTE The ajp connector will be started only if {@link #ajpPort} > 0. + * possible values are: + *
    + *
  • org.apache.coyote.ajp.AjpProtocol - new blocking Java connector that supports an executor
  • + *
  • org.apache.coyote.ajp.AjpAprProtocol - the APR/native connector.
  • + *
+ * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.ajp.protocol", defaultValue = "org.apache.coyote.ajp.AjpProtocol" ) + private String ajpProtocol; + + /** + * The https port to run the Tomcat server on. + * By default it's 0 this means won't be started. + * The https connector will be started only for value > 0. + * Will be exposed as System props and session.executionProperties with key tomcat.maven.https.port + * + * @since 1.0 + */ + @Parameter( property = "maven.tomcat.httpsPort", defaultValue = "0" ) + private int httpsPort; + + /** + * The max post size to run the Tomcat server on. + * By default it's 2097152 bytes. That's the default Tomcat configuration. + * Set this value to 0 or less to disable the post size limit. + * + * @since 2.3 + */ + @Parameter( property = "maven.tomcat.maxPostSize", defaultValue = "2097152" ) + private int maxPostSize; + + /** + * The character encoding to use for decoding URIs. + * + * @since 1.0 + */ + @Parameter( property = "maven.tomcat.uriEncoding", defaultValue = "ISO-8859-1" ) + private String uriEncoding; + + /** + * List of System properties to pass to the Tomcat Server. + * + * @since 1.0-alpha-2 + */ + @Parameter + private Map systemProperties; + + /** + * The directory contains additional configuration Files that copied in the Tomcat conf Directory. + * + * @since 1.0-alpha-2 + */ + @Parameter( property = "maven.tomcat.additionalConfigFilesDir", defaultValue = "${basedir}/src/main/tomcatconf" ) + private File additionalConfigFilesDir; + + /** + * server.xml to use Note if you use this you must configure in this file your webapp paths. + * + * @since 1.0-alpha-2 + */ + @Parameter( property = "maven.tomcat.serverXml" ) + private File serverXml; + + /** + * overriding the providing web.xml to run tomcat + * This override the global Tomcat web.xml located in $CATALINA_HOME/conf/ + * + * @since 1.0-alpha-2 + */ + @Parameter( property = "maven.tomcat.webXml" ) + private File tomcatWebXml; + + /** + * Set this to true to allow Maven to continue to execute after invoking + * the run goal. + * + * @since 1.0 + */ + @Parameter( property = "maven.tomcat.fork", defaultValue = "false" ) + private boolean fork; + + /** + * Will create a tomcat context for each dependencies of war type with 'scope' set to 'tomcat'. + * In other words, dependencies with: + *
+     *    <type>war</type>
+     *    <scope>tomcat</scope>
+     * 
+ * To preserve backward compatibility it's false by default. + * + * @since 1.0 + * @deprecated use webapps instead + */ + @Parameter( property = "maven.tomcat.addContextWarDependencies", defaultValue = "false" ) + private boolean addContextWarDependencies; + + /** + * The maven project. + * + * @since 1.0 + */ + @Component + protected MavenProject project; + + /** + * The archive manager. + * + * @since 1.0 + */ + @Component + private ArchiverManager archiverManager; + + /** + * if true a new classLoader separated from maven core will be created to start tomcat. + * + * @since 1.0 + */ + @Parameter( property = "tomcat.useSeparateTomcatClassLoader", defaultValue = "false" ) + protected boolean useSeparateTomcatClassLoader; + + /** + * @since 1.0 + */ + @Parameter( defaultValue = "${plugin.artifacts}", required = true ) + private List pluginArtifacts; + + /** + * If set to true ignore if packaging of project is not 'war'. + * + * @since 1.0 + */ + @Parameter( property = "tomcat.ignorePackaging", defaultValue = "false" ) + private boolean ignorePackaging; + + /** + * Override the default keystoreFile for the HTTPS connector (if enabled) + * + * @since 1.1 + */ + @Parameter + private String keystoreFile; + + /** + * Override the default keystorePass for the HTTPS connector (if enabled) + * + * @since 1.1 + */ + @Parameter + private String keystorePass; + + /** + * Override the type of keystore file to be used for the server certificate. If not specified, the default value is "JKS". + * + * @since 2.0 + */ + @Parameter( defaultValue = "JKS" ) + private String keystoreType; + + /** + *

+ * Enables or disables naming support for the embedded Tomcat server. + *

+ *

+ * Note: This setting is ignored if you provide a server.xml for your + * Tomcat. Instead please configure naming in the server.xml. + *

+ * + * @see org.apache.catalina.startup.Embedded + * @see org.apache.catalina.startup.Tomcat + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.useNaming", defaultValue = "true" ) + private boolean useNaming; + + /** + * Force context scanning if you don't use a context file with reloadable = "true". + * The other way to use contextReloadable is to add attribute reloadable = "true" + * in your context file. + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.contextReloadable", defaultValue = "false" ) + protected boolean contextReloadable; + + /** + * represents the delay in seconds between each classPathScanning change invocation + * + * @see http://tomcat.apache.org/tomcat-7.0-doc/config/context.html + */ + @Parameter( property = "maven.tomcat.backgroundProcessorDelay", defaultValue = "-1" ) + protected int backgroundProcessorDelay = -1; + + + /** + *

The path of the Tomcat context XML file.

+ *

Since release 2.0, the file is filtered as a maven resource so you can use + * interpolation tokens ${ }

+ */ + @Parameter( property = "maven.tomcat.contextFile" ) + protected File contextFile; + + /** + * The default context file to check for if contextFile not configured. + * If no contextFile configured and the below default not present, no + * contextFile will be sent to Tomcat, resulting in the latter's default + * context configuration being used instead. + */ + @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}/META-INF/context.xml", + readonly = true ) + private File defaultContextFile; + + /** + * The protocol to run the Tomcat server on. + * By default it's HTTP/1.1. + * See possible values HTTP Connector + * protocol attribute + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.protocol", defaultValue = "HTTP/1.1" ) + private String protocol; + + /** + * The path of the Tomcat users XML file. + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.tomcatUsers.file" ) + private File tomcatUsers; + + /** + * The path of the Tomcat logging configuration. + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.tomcatLogging.file" ) + private File tomcatLoggingFile; + + /** + * Skip execution + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.skip", defaultValue = "false" ) + protected boolean skip; + + /** + * Collection of webapp artifacts to be deployed. Elements are <webapp> and contain + * usual GAVC plus contextPath and/or contextFile elements.

+ * + * @see {@link Webapp} + * @since 2.0 + */ + @Parameter + private List webapps; + + /** + * The static context + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.staticContextPath", defaultValue = "/" ) + private String staticContextPath; + + /** + * The static context docroot base fully qualified path + * if null static context won't be added + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.staticContextDocbase" ) + private String staticContextDocbase; + + /** + * Class loader class to set. + * + * @since 2.0 + */ + @Parameter + protected String classLoaderClass; + + @Parameter( defaultValue = "${session}", readonly = true, required = true ) + protected MavenSession session; + + /** + * Will dump port in a properties file (see ports for property names). + * If empty no file generated + */ + @Parameter( property = "maven.tomcat.propertiesPortFilePath" ) + protected String propertiesPortFilePath; + + /** + * configure host name + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.hostName", defaultValue = "localhost" ) + protected String hostName; + + /** + * configure aliases + * see Host Name aliases + * + * @since 2.0 + */ + @Parameter + protected String[] aliases; + + /** + * enable client authentication for https (if configured) + * see http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#SSL_Support_-_BIO_and_NIO + * + * @since 2.1 + */ + @Parameter( property = "maven.tomcat.https.clientAuth", defaultValue = "false" ) + protected String clientAuth = "false"; + + @Component( role = MavenFileFilter.class, hint = "default" ) + protected MavenFileFilter mavenFileFilter; + + + /** + * In case a module in your reactors has some web-fragments they will be read. + * If you don't need that for performance reasons, you can deactivate it. + * + * @since 2.2 + */ + @Parameter( property = "maven.tomcat.jarScan.allDirectories", defaultValue = "true" ) + protected boolean jarScanAllDirectories = true; + + /** + * @since 2.2 + */ + @Parameter( property = "maven.tomcat.useBodyEncodingForURI", defaultValue = "false" ) + protected boolean useBodyEncodingForURI; + + /** + * @since 2.2 + */ + @Parameter + protected String trustManagerClassName; + + /** + * @since 2.2 + */ + @Parameter + protected String trustMaxCertLength; + + /** + * @since 2.2 + */ + @Parameter + protected String truststoreAlgorithm; + + /** + * @since 2.2 + */ + @Parameter + protected String truststoreFile; + + /** + * @since 2.2 + */ + @Parameter + protected String truststorePass; + + /** + * @since 2.2 + */ + @Parameter + protected String truststoreProvider; + + /** + * @since 2.2 + */ + @Parameter + protected String truststoreType; + + // ---------------------------------------------------------------------- + // Fields + // ---------------------------------------------------------------------- + + /** + * @since 1.0 + */ + private ClassRealm tomcatRealm; + + // ---------------------------------------------------------------------- + // Mojo Implementation + // ---------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + public void execute() + throws MojoExecutionException, MojoFailureException + { + if ( skip ) + { + getLog().info( "skip execution" ); + return; + } + // ensure project is a web application + if ( !isWar() && !addContextWarDependencies && getAdditionalWebapps().isEmpty() ) + { + getLog().info( messagesProvider.getMessage( "AbstractRunMojo.nonWar" ) ); + return; + } + ClassLoader originalClassLoader = null; + if ( useSeparateTomcatClassLoader ) + { + originalClassLoader = Thread.currentThread().getContextClassLoader(); + } + try + { + getLog().info( messagesProvider.getMessage( "AbstractRunMojo.runningWar", getWebappUrl() ) ); + + initConfiguration(); + startContainer(); + if ( !fork ) + { + waitIndefinitely(); + } + } + catch ( LifecycleException exception ) + { + throw new MojoExecutionException( messagesProvider.getMessage( "AbstractRunMojo.cannotStart" ), exception ); + } + catch ( IOException exception ) + { + throw new MojoExecutionException( + messagesProvider.getMessage( "AbstractRunMojo.cannotCreateConfiguration" ), exception ); + } + catch ( ServletException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( MavenFilteringException e ) + { + throw new MojoExecutionException( "filtering issue: " + e.getMessage(), e ); + } + finally + { + if ( useSeparateTomcatClassLoader ) + { + Thread.currentThread().setContextClassLoader( originalClassLoader ); + } + } + } + + // ---------------------------------------------------------------------- + // Protected Methods + // ---------------------------------------------------------------------- + + /** + * Gets the webapp context path to use for the web application being run. + * + * @return the webapp context path + */ + @Override + protected String getPath() + { + return path; + } + + protected void enhanceContext( final Context context ) + throws MojoExecutionException + { + // no op + } + + + /** + * Gets the context to run this web application under for the specified embedded Tomcat. + * + * @param container the embedded Tomcat container being used + * @return the context to run this web application under + * @throws IOException if the context could not be created + * @throws MojoExecutionException in case of an error creating the context + */ + protected Context createContext( Tomcat container ) + throws IOException, MojoExecutionException, ServletException + { + String contextPath = getPath(); + + String baseDir = getDocBase().getAbsolutePath(); + + File overriddenContextFile = getContextFile(); + + StandardContext standardContext = null; + + if ( overriddenContextFile != null && overriddenContextFile.exists() ) + { + getLog().info("Using dynamic context configuration file: " + overriddenContextFile.getAbsolutePath()); + standardContext = parseContextFile( overriddenContextFile ); + } + else if ( defaultContextFile.exists() ) + { + getLog().info("Using default context configuration file: " + defaultContextFile.getAbsolutePath()); + standardContext = parseContextFile( defaultContextFile ); + } + + if ( standardContext != null ) + { + if ( standardContext.getPath() != null ) + { + contextPath = standardContext.getPath(); + } + if ( standardContext.getDocBase() != null ) + { + baseDir = standardContext.getDocBase(); + } + } + + contextPath = "/".equals( contextPath ) ? "" : contextPath; + + getLog().info( "create webapp with contextPath: " + contextPath ); + + Context context = container.addWebapp( contextPath, baseDir ); + + StandardRoot root = new StandardRoot(context); + context.setResources(root); + + if ( useSeparateTomcatClassLoader ) + { + context.setParentClassLoader( getTomcatClassLoader() ); + } + + enhanceContext( context ); + + final WebappLoader loader = createWebappLoader(); + + context.setLoader( loader ); + + if ( overriddenContextFile != null ) + { + // here, send file to Tomcat for it to complain if missing + context.setConfigFile( overriddenContextFile.toURI().toURL() ); + } + else if ( defaultContextFile.exists() ) + { + // here, only sending default file if it indeed exists + // otherwise Tomcat will create a default context + context.setConfigFile( defaultContextFile.toURI().toURL() ); + } + + if ( classLoaderClass != null ) + { + loader.setLoaderClass( classLoaderClass ); + } + + // https://issues.apache.org/jira/browse/MTOMCAT-239 + // get the jar scanner to configure scanning directories as we can run a jar or a reactor project with a jar so + // the entries is a directory (target/classes) + JarScanner jarScanner = context.getJarScanner(); + + // normally this one only but just in case ... + if ( jarScanner instanceof StandardJarScanner ) + { + ( (StandardJarScanner) jarScanner ).setScanAllDirectories( jarScanAllDirectories ); + } + + return context; + + } + + protected StandardContext parseContextFile( File file ) + throws MojoExecutionException + { + try + { + StandardContext standardContext = new StandardContext(); + XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader( new FileInputStream( file ) ); + + int tag = reader.next(); + + while ( true ) + { + if ( tag == XMLStreamConstants.START_ELEMENT && StringUtils.equals( "Context", reader.getLocalName() ) ) + { + String path = reader.getAttributeValue( null, "path" ); + if ( StringUtils.isNotBlank( path ) ) + { + standardContext.setPath( path ); + } + + String docBase = reader.getAttributeValue( null, "docBase" ); + if ( StringUtils.isNotBlank( docBase ) ) + { + standardContext.setDocBase( docBase ); + } + } + if ( !reader.hasNext() ) + { + break; + } + tag = reader.next(); + } + + return standardContext; + } + catch ( XMLStreamException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( FileNotFoundException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + } + + /** + * Gets the webapp loader to run this web application under. + * + * @return the webapp loader to use + * @throws IOException if the webapp loader could not be created + * @throws MojoExecutionException in case of an error creating the webapp loader + */ + protected WebappLoader createWebappLoader() + throws IOException, MojoExecutionException + { + WebappLoader webappLoader = null; + if ( useSeparateTomcatClassLoader ) + { + if ( isContextReloadable() ) + { + webappLoader = new ExternalRepositoriesReloadableWebappLoader( getTomcatClassLoader(), getLog() ); + } + else + { + webappLoader = new WebappLoader( getTomcatClassLoader() ); + } + } + else + { + if ( isContextReloadable() ) + { + webappLoader = + new ExternalRepositoriesReloadableWebappLoader( Thread.currentThread().getContextClassLoader(), + getLog() ); + } + else + { + webappLoader = new WebappLoader( Thread.currentThread().getContextClassLoader() ); + } + } + return webappLoader; + } + + /** + * Determine whether the passed context.xml file declares the context as reloadable or not. + * + * @return false by default, true if reloadable="true" in context.xml. + */ + protected boolean isContextReloadable() + throws MojoExecutionException + { + if ( contextReloadable || backgroundProcessorDelay > 0 ) + { + return true; + } + // determine whether to use a reloadable Loader or not (default is false). + boolean reloadable = false; + try + { + if ( contextFile != null && contextFile.exists() ) + { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document contextDoc = builder.parse( contextFile ); + contextDoc.getDocumentElement().normalize(); + + NamedNodeMap nodeMap = contextDoc.getDocumentElement().getAttributes(); + Node reloadableAttribute = nodeMap.getNamedItem( "reloadable" ); + + reloadable = + ( reloadableAttribute != null ) ? Boolean.valueOf( reloadableAttribute.getNodeValue() ) : false; + } + getLog().debug( "context reloadable: " + reloadable ); + } + catch ( IOException ioe ) + { + getLog().error( "Could not parse file: [" + contextFile.getAbsolutePath() + "]", ioe ); + } + catch ( ParserConfigurationException pce ) + { + getLog().error( "Could not configure XML parser", pce ); + } + catch ( SAXException se ) + { + getLog().error( "Could not parse file: [" + contextFile.getAbsolutePath() + "]", se ); + } + + return reloadable; + } + + + /** + * Gets the webapp directory to run. + * + * @return the webapp directory + */ + protected abstract File getDocBase() + throws IOException; + + /** + * Gets the Tomcat context XML file to use. + * + * @return the context XML file + */ + protected abstract File getContextFile() + throws MojoExecutionException; + + // ---------------------------------------------------------------------- + // Private Methods + // ---------------------------------------------------------------------- + + /** + * Gets whether this project uses WAR packaging. + * + * @return whether this project uses WAR packaging + */ + protected boolean isWar() + { + return "war".equals( packaging ) || ignorePackaging; + } + + /** + * Gets the URL of the running webapp. + * + * @return the URL of the running webapp + * @throws java.net.MalformedURLException if the running webapp URL is invalid + */ + private URL getWebappUrl() + throws MalformedURLException + { + return new URL( "http", "localhost", port, getPath() ); + } + + /** + * FIXME not sure we need all of those files with tomcat9 + * Creates the Tomcat configuration directory with the necessary resources. + * + * @throws IOException if the Tomcat configuration could not be created + * @throws MojoExecutionException if the Tomcat configuration could not be created + */ + private void initConfiguration() + throws IOException, MojoExecutionException, MavenFilteringException + { + if ( configurationDir.exists() ) + { + getLog().info( messagesProvider.getMessage( "AbstractRunMojo.usingConfiguration", configurationDir ) ); + } + else + { + getLog().info( messagesProvider.getMessage( "AbstractRunMojo.creatingConfiguration", configurationDir ) ); + + configurationDir.mkdirs(); + + File confDir = new File( configurationDir, "conf" ); + confDir.mkdir(); + + if ( tomcatLoggingFile != null ) + { + FileUtils.copyFile( tomcatLoggingFile, new File( confDir, "logging.properties" ) ); + } + else + { + copyFile( "/conf/logging.properties", new File( confDir, "logging.properties" ) ); + } + + copyFile( "/conf/tomcat-users.xml", new File( confDir, "tomcat-users.xml" ) ); + if ( tomcatWebXml != null ) + { + if ( !tomcatWebXml.exists() ) + { + throw new MojoExecutionException( " tomcatWebXml " + tomcatWebXml.getPath() + " not exists" ); + } + //MTOMCAT-42 here it's a real file resources not a one coming with the mojo + //MTOMCAT-128 apply filtering + MavenFileFilterRequest mavenFileFilterRequest = new MavenFileFilterRequest(); + mavenFileFilterRequest.setFrom( tomcatWebXml ); + mavenFileFilterRequest.setTo( new File( confDir, "web.xml" ) ); + mavenFileFilterRequest.setMavenProject( project ); + mavenFileFilterRequest.setMavenSession( session ); + mavenFileFilterRequest.setFiltering( true ); + + mavenFileFilter.copyFile( mavenFileFilterRequest ); + + } + else + { + copyFile( "/conf/web.xml", new File( confDir, "web.xml" ) ); + } + + File logDir = new File( configurationDir, "logs" ); + logDir.mkdir(); + + File webappsDir = new File( configurationDir, "webapps" ); + webappsDir.mkdir(); + + if ( additionalConfigFilesDir != null && additionalConfigFilesDir.exists() ) + { + DirectoryScanner scanner = new DirectoryScanner(); + scanner.addDefaultExcludes(); + scanner.setBasedir( additionalConfigFilesDir.getPath() ); + scanner.scan(); + + String[] files = scanner.getIncludedFiles(); + + if ( files != null && files.length > 0 ) + { + getLog().info( "Coping additional tomcat config files" ); + + for ( int i = 0; i < files.length; i++ ) + { + File file = new File( additionalConfigFilesDir, files[i] ); + + getLog().info( " copy " + file.getName() ); + + FileUtils.copyFileToDirectory( file, confDir ); + } + } + } + } + } + + /** + * Copies the specified class resource to the specified file. + * + * @param fromPath the path of the class resource to copy + * @param toFile the file to copy to + * @throws IOException if the file could not be copied + */ + private void copyFile( String fromPath, File toFile ) + throws IOException + { + URL fromURL = getClass().getResource( fromPath ); + + if ( fromURL == null ) + { + throw new FileNotFoundException( fromPath ); + } + + FileUtils.copyURLToFile( fromURL, toFile ); + } + + /** + * Starts the embedded Tomcat server. + * + * @throws IOException if the server could not be configured + * @throws LifecycleException if the server could not be started + * @throws MojoExecutionException if the server could not be configured + */ + private void startContainer() + throws IOException, LifecycleException, MojoExecutionException, ServletException + { + String previousCatalinaBase = System.getProperty( "catalina.base" ); + + try + { + // Default to headless + System.setProperty("java.awt.headless", "true"); + System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true"); + // Set the system properties + setupSystemProperties(); + + System.setProperty( "catalina.base", configurationDir.getAbsolutePath() ); + + if ( serverXml != null ) + { + if ( !serverXml.exists() ) + { + throw new MojoExecutionException( serverXml.getPath() + " not exists" ); + } + + Catalina container = new Catalina(); + + if ( useSeparateTomcatClassLoader ) + { + Thread.currentThread().setContextClassLoader( getTomcatClassLoader() ); + container.setParentClassLoader( getTomcatClassLoader() ); + } + + container.setUseNaming( this.useNaming ); + container.setConfigFile( serverXml.getAbsolutePath() ); + container.start(); + EmbeddedRegistry.getInstance().register( container ); + } + else + { + + System.setProperty( "java.util.logging.manager", "org.apache.juli.ClassLoaderLogManager" ); + System.setProperty( "java.util.logging.config.file", + new File( configurationDir, "conf/logging.properties" ).toString() ); + + // Trigger loading of catalina.properties + CatalinaProperties.getProperty( "foo" ); + + Tomcat embeddedTomcat = new ExtendedTomcat( configurationDir ); + + embeddedTomcat.setBaseDir( configurationDir.getAbsolutePath() ); + MemoryRealm memoryRealm = new MemoryRealm(); + + if ( tomcatUsers != null ) + { + if ( !tomcatUsers.exists() ) + { + throw new MojoExecutionException( " tomcatUsers " + tomcatUsers.getPath() + " not exists" ); + } + getLog().info( "use tomcat-users.xml from " + tomcatUsers.getAbsolutePath() ); + memoryRealm.setPathname( tomcatUsers.getAbsolutePath() ); + } + + embeddedTomcat.getEngine().setRealm( memoryRealm ); + + Context ctx = createContext( embeddedTomcat ); + + if ( useNaming ) + { + embeddedTomcat.enableNaming(); + } + + embeddedTomcat.getHost().setAppBase( new File( configurationDir, "webapps" ).getAbsolutePath() ); + + if ( hostName != null ) + { + embeddedTomcat.getHost().setName( hostName ); + } + if ( aliases != null ) + { + for ( String alias : aliases ) + { + embeddedTomcat.getHost().addAlias( alias ); + } + + } + createStaticContext( embeddedTomcat, ctx, embeddedTomcat.getHost() ); + + Connector connector = new Connector( protocol ); + connector.setPort( port ); + connector.setMaxPostSize( maxPostSize ); + + if ( httpsPort > 0 ) + { + connector.setRedirectPort( httpsPort ); + } + + if ( address != null ) + { + connector.setAttribute( "address", address ); + } + + connector.setURIEncoding( uriEncoding ); + + connector.setUseBodyEncodingForURI( this.useBodyEncodingForURI ); + + embeddedTomcat.getService().addConnector( connector ); + + embeddedTomcat.setConnector( connector ); + + AccessLogValve alv = new AccessLogValve(); + alv.setDirectory( new File( configurationDir, "logs" ).getAbsolutePath() ); + alv.setPattern( "%h %l %u %t \"%r\" %s %b %I %D" ); + embeddedTomcat.getHost().getPipeline().addValve( alv ); + + // create https connector + Connector httpsConnector = null; + if ( httpsPort > 0 ) + { + httpsConnector = new Connector( protocol ); + httpsConnector.setPort( httpsPort ); + httpsConnector.setMaxPostSize( maxPostSize ); + httpsConnector.setSecure( true ); + httpsConnector.setProperty( "SSLEnabled", "true" ); + // should be default but configure it anyway + httpsConnector.setProperty( "sslProtocol", "TLS" ); + if ( keystoreFile != null ) + { + httpsConnector.setAttribute( "keystoreFile", keystoreFile ); + } + if ( keystorePass != null ) + { + httpsConnector.setAttribute( "keystorePass", keystorePass ); + } + if ( keystoreType != null ) + { + httpsConnector.setAttribute( "keystoreType", keystoreType ); + } + + if ( trustManagerClassName != null ) + { + httpsConnector.setAttribute( "trustManagerClassName", trustManagerClassName ); + } + + if ( trustMaxCertLength != null ) + { + httpsConnector.setAttribute( "trustMaxCertLength", trustMaxCertLength ); + } + + if ( truststoreAlgorithm != null ) + { + httpsConnector.setAttribute( "truststoreAlgorithm", truststoreAlgorithm ); + } + + if ( truststoreFile != null ) + { + httpsConnector.setAttribute( "truststoreFile", truststoreFile ); + } + + if ( truststorePass != null ) + { + httpsConnector.setAttribute( "truststorePass", truststorePass ); + } + + if ( truststoreProvider != null ) + { + httpsConnector.setAttribute( "truststoreProvider", truststoreProvider ); + } + + if ( truststoreType != null ) + { + httpsConnector.setAttribute( "truststoreType", truststoreType ); + } + + httpsConnector.setAttribute( "clientAuth", clientAuth ); + + httpsConnector.setUseBodyEncodingForURI( this.useBodyEncodingForURI ); + + if ( address != null ) + { + httpsConnector.setAttribute( "address", address ); + } + + embeddedTomcat.getEngine().getService().addConnector( httpsConnector ); + + } + + // create ajp connector + Connector ajpConnector = null; + if ( ajpPort > 0 ) + { + ajpConnector = new Connector( ajpProtocol ); + ajpConnector.setPort( ajpPort ); + ajpConnector.setURIEncoding( uriEncoding ); + ajpConnector.setUseBodyEncodingForURI( this.useBodyEncodingForURI ); + if ( address != null ) + { + ajpConnector.setAttribute( "address", address ); + } + embeddedTomcat.getEngine().getService().addConnector( ajpConnector ); + } + + if ( addContextWarDependencies || !getAdditionalWebapps().isEmpty() ) + { + createDependencyContexts( embeddedTomcat ); + } + + if ( useSeparateTomcatClassLoader ) + { + Thread.currentThread().setContextClassLoader( getTomcatClassLoader() ); + embeddedTomcat.getEngine().setParentClassLoader( getTomcatClassLoader() ); + } + + embeddedTomcat.start(); + + Properties portProperties = new Properties(); + + portProperties.put( "tomcat.maven.http.port", Integer.toString( connector.getLocalPort() ) ); + + session.getExecutionProperties().put( "tomcat.maven.http.port", + Integer.toString( connector.getLocalPort() ) ); + System.setProperty( "tomcat.maven.http.port", Integer.toString( connector.getLocalPort() ) ); + + if ( httpsConnector != null ) + { + session.getExecutionProperties().put( "tomcat.maven.https.port", + Integer.toString( httpsConnector.getLocalPort() ) ); + portProperties.put( "tomcat.maven.https.port", Integer.toString( httpsConnector.getLocalPort() ) ); + System.setProperty( "tomcat.maven.https.port", Integer.toString( httpsConnector.getLocalPort() ) ); + } + + if ( ajpConnector != null ) + { + session.getExecutionProperties().put( "tomcat.maven.ajp.port", + Integer.toString( ajpConnector.getLocalPort() ) ); + portProperties.put( "tomcat.maven.ajp.port", Integer.toString( ajpConnector.getLocalPort() ) ); + System.setProperty( "tomcat.maven.ajp.port", Integer.toString( ajpConnector.getLocalPort() ) ); + } + if ( propertiesPortFilePath != null ) + { + File propertiesPortsFile = new File( propertiesPortFilePath ); + if ( propertiesPortsFile.exists() ) + { + propertiesPortsFile.delete(); + } + FileOutputStream fileOutputStream = new FileOutputStream( propertiesPortsFile ); + try + { + portProperties.store( fileOutputStream, "Apache Tomcat Maven plugin port used" ); + } + finally + { + IOUtils.closeQuietly( fileOutputStream ); + } + } + + EmbeddedRegistry.getInstance().register( embeddedTomcat ); + + } + + + } + finally + { + if ( previousCatalinaBase != null ) + { + System.setProperty( "catalina.base", previousCatalinaBase ); + } + } + } + + private List getAdditionalWebapps() + { + if ( webapps == null ) + { + return Collections.emptyList(); + } + return webapps; + } + + protected ClassRealm getTomcatClassLoader() + throws MojoExecutionException + { + if ( this.tomcatRealm != null ) + { + return tomcatRealm; + } + try + { + ClassWorld world = new ClassWorld(); + ClassRealm root = world.newRealm( "tomcat", Thread.currentThread().getContextClassLoader() ); + + for ( Iterator i = pluginArtifacts.iterator(); i.hasNext(); ) + { + Artifact pluginArtifact = i.next(); + // add all plugin artifacts see https://issues.apache.org/jira/browse/MTOMCAT-122 + if ( pluginArtifact.getFile() != null ) + { + root.addURL( pluginArtifact.getFile().toURI().toURL() ); + } + + } + tomcatRealm = root; + return root; + } + catch ( DuplicateRealmException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( MalformedURLException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + } + + @SuppressWarnings( "unchecked" ) + public Set getProjectArtifacts() + { + return project.getArtifacts(); + } + + /** + * Causes the current thread to wait indefinitely. This method does not return. + */ + private void waitIndefinitely() + { + Object lock = new Object(); + + synchronized ( lock ) + { + try + { + lock.wait(); + } + catch ( InterruptedException exception ) + { + getLog().warn( messagesProvider.getMessage( "AbstractRunMojo.interrupted" ), exception ); + } + } + } + + + /** + * Set the SystemProperties from the configuration. + */ + private void setupSystemProperties() + { + if ( systemProperties != null && !systemProperties.isEmpty() ) + { + getLog().info( "setting SystemProperties:" ); + + for ( String key : systemProperties.keySet() ) + { + String value = systemProperties.get( key ); + + if ( value != null ) + { + getLog().info( " " + key + "=" + value ); + System.setProperty( key, value ); + } + else + { + getLog().info( "skip sysProps " + key + " with empty value" ); + } + } + } + } + + + /** + * Allows the startup of additional webapps in the tomcat container by declaration with scope + * "tomcat". + * + * @param container tomcat + * @return dependency tomcat contexts of warfiles in scope "tomcat" + */ + private Collection createDependencyContexts( Tomcat container ) + throws MojoExecutionException, MalformedURLException, ServletException, IOException + { + getLog().info( "Deploying dependency wars" ); + // Let's add other modules + List contexts = new ArrayList(); + + ScopeArtifactFilter filter = new ScopeArtifactFilter( "tomcat" ); + @SuppressWarnings( "unchecked" ) Set artifacts = project.getArtifacts(); + for ( Artifact artifact : artifacts ) + { + + // Artifact is not yet registered and it has neither test, nor a + // provided scope, not is it optional + if ( "war".equals( artifact.getType() ) && !artifact.isOptional() && filter.include( artifact ) ) + { + addContextFromArtifact( container, contexts, artifact, "/" + artifact.getArtifactId(), null, false ); + } + } + + for ( AbstractWebapp additionalWebapp : getAdditionalWebapps() ) + { + String contextPath = additionalWebapp.getContextPath(); + if ( !contextPath.startsWith( "/" ) ) + { + contextPath = "/" + contextPath; + } + addContextFromArtifact( container, contexts, getArtifact( additionalWebapp ), contextPath, + additionalWebapp.getContextFile(), additionalWebapp.isAsWebapp() ); + } + return contexts; + } + + + private void addContextFromArtifact( Tomcat container, List contexts, Artifact artifact, + String contextPath, File contextXml, boolean asWebApp ) + throws MojoExecutionException, ServletException, IOException + { + getLog().info( "Deploy warfile: " + String.valueOf( artifact.getFile() ) + " to contextPath: " + contextPath ); + File webapps = new File( configurationDir, "webapps" ); + File artifactWarDir = new File( webapps, artifact.getArtifactId() ); + if ( !artifactWarDir.exists() ) + { + //dont extract if exists + artifactWarDir.mkdir(); + try + { + UnArchiver unArchiver = archiverManager.getUnArchiver( "zip" ); + unArchiver.setSourceFile( artifact.getFile() ); + unArchiver.setDestDirectory( artifactWarDir ); + + // Extract the module + unArchiver.extract(); + } + catch ( NoSuchArchiverException e ) + { + getLog().error( e ); + return; + } + catch ( ArchiverException e ) + { + getLog().error( e ); + return; + } + } + // TODO make that configurable ? + //WebappLoader webappLoader = new WebappLoader( Thread.currentThread().getContextClassLoader() ); + WebappLoader webappLoader = createWebappLoader(); + Context context = null; + if ( asWebApp ) + { + context = container.addWebapp( contextPath, artifactWarDir.getAbsolutePath() ); + } + else + { + context = container.addContext( contextPath, artifactWarDir.getAbsolutePath() ); + } + context.setLoader( webappLoader ); + + File contextFile = contextXml != null ? contextXml : getContextFile(); + if ( contextFile != null ) + { + context.setConfigFile( contextFile.toURI().toURL() ); + } + + contexts.add( context ); +// container.getHost().addChild(context); + } + + private void createStaticContext( final Tomcat container, Context context, Host host ) + { + if ( staticContextDocbase != null ) + { + Context staticContext = container.addContext( staticContextPath, staticContextDocbase ); + staticContext.setPrivileged( true ); + Wrapper servlet = context.createWrapper(); + servlet.setServletClass( DefaultServlet.class.getName() ); + servlet.setName( "staticContent" ); + servlet.addMapping("/"); + staticContext.addChild( servlet ); + //staticContext.addServletMapping( "/", "staticContent" ); + // see https://issues.apache.org/jira/browse/MTOMCAT-238 + //host.addChild( staticContext ); + } + } + + + /** + * Resolves the Artifact from the remote repository if necessary. If no version is specified, it will be retrieved + * from the dependency list or from the DependencyManagement section of the pom. + * + * @param additionalWebapp containing information about artifact from plugin configuration. + * @return Artifact object representing the specified file. + * @throws MojoExecutionException with a message if the version can't be found in DependencyManagement. + */ + protected Artifact getArtifact( AbstractWebapp additionalWebapp ) + throws MojoExecutionException + { + + Artifact artifact; + VersionRange vr; + try + { + vr = VersionRange.createFromVersionSpec( additionalWebapp.getVersion() ); + } + catch ( InvalidVersionSpecificationException e ) + { + getLog().warn( "fail to create versionRange from version: " + additionalWebapp.getVersion(), e ); + vr = VersionRange.createFromVersion( additionalWebapp.getVersion() ); + } + + if ( StringUtils.isEmpty( additionalWebapp.getClassifier() ) ) + { + artifact = + factory.createDependencyArtifact( additionalWebapp.getGroupId(), additionalWebapp.getArtifactId(), vr, + additionalWebapp.getType(), null, Artifact.SCOPE_COMPILE ); + } + else + { + artifact = + factory.createDependencyArtifact( additionalWebapp.getGroupId(), additionalWebapp.getArtifactId(), vr, + additionalWebapp.getType(), additionalWebapp.getClassifier(), + Artifact.SCOPE_COMPILE ); + } + + try + { + resolver.resolve( artifact, project.getRemoteArtifactRepositories(), this.local ); + } + catch ( ArtifactResolutionException e ) + { + throw new MojoExecutionException( "Unable to resolve artifact.", e ); + } + catch ( ArtifactNotFoundException e ) + { + throw new MojoExecutionException( "Unable to find artifact.", e ); + } + + return artifact; + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractRunWarMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractRunWarMojo.java new file mode 100644 index 00000000..836f180c --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractRunWarMojo.java @@ -0,0 +1,66 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Parameter; + +import java.io.File; + +/** + * Runs the current project as a packaged web application using an embedded Tomcat server. + * + * @author Mark Hobson + * @todo depend on war:exploded when MNG-1649 resolved + */ +public abstract class AbstractRunWarMojo + extends AbstractRunMojo +{ + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + /** + * The path of the exploded WAR directory to run. + */ + @Parameter( property = "maven.tomcat.warDirectory", defaultValue = "${project.build.directory}/${project.build.finalName}", required = true ) + private File warDirectory; + + // ---------------------------------------------------------------------- + // AbstractRunMojo Implementation + // ---------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + protected File getDocBase() + { + return warDirectory; + } + + /** + * {@inheritDoc} + */ + @Override + protected File getContextFile() + { + return contextFile; + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractStandaloneWarMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractStandaloneWarMojo.java new file mode 100644 index 00000000..89f899d3 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/AbstractStandaloneWarMojo.java @@ -0,0 +1,299 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.archivers.ArchiveOutputStream; +import org.apache.commons.compress.archivers.ArchiveStreamFactory; +import org.apache.commons.compress.archivers.jar.JarArchiveEntry; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.model.Dependency; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.tomcat.maven.runner.Tomcat9Runner; +import org.apache.tomcat.maven.runner.Tomcat9RunnerCli; +import org.codehaus.plexus.archiver.jar.Manifest; +import org.codehaus.plexus.archiver.jar.ManifestException; +import org.codehaus.plexus.util.DirectoryScanner; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; +import java.util.jar.JarFile; + +/** + * Abstract Mojo for building deployable and executable war files + * + * @since 2.1 + */ +public abstract class AbstractStandaloneWarMojo + extends AbstractExecWarMojo +{ + + /** + * Name of the generated WAR. + */ + @Parameter( property = "tomcat.jar.finalName", + defaultValue = "${project.artifactId}-${project.version}-standalone.war", required = true ) + protected String finalName; + + /** + * the classifier to use for the attached/generated artifact + */ + @Parameter( property = "maven.tomcat.exec.war.attachArtifactClassifier", defaultValue = "standalone", + required = true ) + protected String attachArtifactClassifier; + + /** + * the type to use for the attached/generated artifact + * + * @since 2.2 + */ + @Parameter( property = "maven.tomcat.exec.war.attachArtifactType", defaultValue = "war", required = true ) + protected String attachArtifactClassifierType; + + public void execute() + throws MojoExecutionException, MojoFailureException + { + if ( !"war".equals( project.getPackaging() ) ) + { + throw new MojoFailureException( "Pacakaging must be of type war for standalone-war goal." ); + } + + File warExecFile = new File( buildDirectory, finalName ); + if ( warExecFile.exists() ) + { + warExecFile.delete(); + } + + File execWarJar = new File( buildDirectory, finalName ); + + FileOutputStream execWarJarOutputStream = null; + ArchiveOutputStream os = null; + File tmpPropertiesFile = null; + File tmpManifestFile = null; + FileOutputStream tmpPropertiesFileOutputStream = null; + PrintWriter tmpManifestWriter = null; + + try + { + tmpPropertiesFile = new File( buildDirectory, "war-exec.properties" ); + if ( tmpPropertiesFile.exists() ) + { + tmpPropertiesFile.delete(); + } + tmpPropertiesFile.getParentFile().mkdirs(); + + tmpManifestFile = new File( buildDirectory, "war-exec.manifest" ); + if ( tmpManifestFile.exists() ) + { + tmpManifestFile.delete(); + } + tmpPropertiesFileOutputStream = new FileOutputStream( tmpPropertiesFile ); + execWarJar.getParentFile().mkdirs(); + execWarJar.createNewFile(); + execWarJarOutputStream = new FileOutputStream( execWarJar ); + + tmpManifestWriter = new PrintWriter( tmpManifestFile ); + + // store : + //* wars in the root: foo.war + //* tomcat jars + //* file tomcat.standalone.properties with possible values : + // * useServerXml=true/false to use directly the one provided + // * enableNaming=true/false + // * wars=foo.war|contextpath;bar.war ( |contextpath is optionnal if empty use the war name ) + // * accessLogValveFormat= + // * connectorhttpProtocol: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol + // * codeSourceContextPath=path parameter, default is project.artifactId + //* optionnal: conf/ with usual tomcat configuration files + //* MANIFEST with Main-Class + + Properties properties = new Properties(); + + properties.put(Tomcat9Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY, + Long.toString( System.currentTimeMillis() ) ); + properties.put(Tomcat9Runner.ENABLE_NAMING_KEY, Boolean.toString( enableNaming ) ); + properties.put(Tomcat9Runner.ACCESS_LOG_VALVE_FORMAT_KEY, accessLogValveFormat ); + properties.put(Tomcat9Runner.HTTP_PROTOCOL_KEY, connectorHttpProtocol ); + properties.put(Tomcat9Runner.CODE_SOURCE_CONTEXT_PATH, path ); + + os = new ArchiveStreamFactory().createArchiveOutputStream( ArchiveStreamFactory.JAR, + execWarJarOutputStream ); + + extractJarToArchive( new JarFile( projectArtifact.getFile() ), os, null ); + + if ( serverXml != null && serverXml.exists() ) + { + os.putArchiveEntry( new JarArchiveEntry( "conf/server.xml" ) ); + IOUtils.copy( new FileInputStream( serverXml ), os ); + os.closeArchiveEntry(); + properties.put(Tomcat9Runner.USE_SERVER_XML_KEY, Boolean.TRUE.toString() ); + } + else + { + properties.put(Tomcat9Runner.USE_SERVER_XML_KEY, Boolean.FALSE.toString() ); + } + + os.putArchiveEntry( new JarArchiveEntry( "conf/web.xml" ) ); + IOUtils.copy( getClass().getResourceAsStream( "/conf/web.xml" ), os ); + os.closeArchiveEntry(); + + properties.store( tmpPropertiesFileOutputStream, "created by Apache Tomcat Maven plugin" ); + + tmpPropertiesFileOutputStream.flush(); + tmpPropertiesFileOutputStream.close(); + + os.putArchiveEntry(new JarArchiveEntry( Tomcat9RunnerCli.STAND_ALONE_PROPERTIES_FILENAME ) ); + IOUtils.copy( new FileInputStream( tmpPropertiesFile ), os ); + os.closeArchiveEntry(); + + // add tomcat classes + for ( Artifact pluginArtifact : pluginArtifacts ) + { + if ( StringUtils.equals( "org.apache.tomcat", pluginArtifact.getGroupId() ) // + || StringUtils.equals( "org.apache.tomcat.embed", pluginArtifact.getGroupId() ) // + || StringUtils.equals( "org.eclipse.jdt.core.compiler", pluginArtifact.getGroupId() ) // + || StringUtils.equals( "commons-cli", pluginArtifact.getArtifactId() ) // + || StringUtils.equals( "tomcat9-war-runner", pluginArtifact.getArtifactId() ) ) + { + JarFile jarFile = new JarFile( pluginArtifact.getFile() ); + extractJarToArchive( jarFile, os, null ); + } + } + + // add extra dependencies + if ( extraDependencies != null && !extraDependencies.isEmpty() ) + { + for ( Dependency dependency : extraDependencies ) + { + String version = dependency.getVersion(); + if ( StringUtils.isEmpty( version ) ) + { + version = findArtifactVersion( dependency ); + } + + if ( StringUtils.isEmpty( version ) ) + { + throw new MojoExecutionException( + "Dependency '" + dependency.getGroupId() + "':'" + dependency.getArtifactId() + + "' does not have version specified" ); + } + // String groupId, String artifactId, String version, String scope, String type + Artifact artifact = artifactFactory.createArtifact( dependency.getGroupId(), // + dependency.getArtifactId(), // + version, // + dependency.getScope(), // + dependency.getType() ); + + artifactResolver.resolve( artifact, this.remoteRepos, this.local ); + JarFile jarFile = new JarFile( artifact.getFile() ); + extractJarToArchive( jarFile, os, excludes ); + } + } + + Manifest manifest = new Manifest(); + + Manifest.Attribute mainClassAtt = new Manifest.Attribute(); + mainClassAtt.setName( "Main-Class" ); + mainClassAtt.setValue( mainClass ); + manifest.addConfiguredAttribute( mainClassAtt ); + + manifest.write( tmpManifestWriter ); + tmpManifestWriter.flush(); + tmpManifestWriter.close(); + + os.putArchiveEntry( new JarArchiveEntry( "META-INF/MANIFEST.MF" ) ); + IOUtils.copy( new FileInputStream( tmpManifestFile ), os ); + os.closeArchiveEntry(); + + if ( attachArtifact ) + { + //MavenProject project, String artifactType, String artifactClassifier, File artifactFile + projectHelper.attachArtifact( project, attachArtifactClassifierType, attachArtifactClassifier, + execWarJar ); + } + + if ( extraResources != null ) + { + for ( ExtraResource extraResource : extraResources ) + { + + DirectoryScanner directoryScanner = new DirectoryScanner(); + directoryScanner.setBasedir( extraResource.getDirectory() ); + directoryScanner.addDefaultExcludes(); + directoryScanner.setExcludes( toStringArray( extraResource.getExcludes() ) ); + directoryScanner.setIncludes( toStringArray( extraResource.getIncludes() ) ); + directoryScanner.scan(); + for ( String includeFile : directoryScanner.getIncludedFiles() ) + { + getLog().debug( "include file:" + includeFile ); + os.putArchiveEntry( new JarArchiveEntry( includeFile ) ); + IOUtils.copy( new FileInputStream( new File( extraResource.getDirectory(), includeFile ) ), + os ); + os.closeArchiveEntry(); + } + } + } + + if ( tomcatConfigurationFilesDirectory != null && tomcatConfigurationFilesDirectory.exists() ) + { + // Because its the tomcat default dir for configs + String aConfigOutputDir = "conf/"; + copyDirectoryContentIntoArchive( tomcatConfigurationFilesDirectory, aConfigOutputDir, os ); + } + } + catch ( ManifestException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( ArchiveException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( ArtifactNotFoundException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + catch ( ArtifactResolutionException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + finally + { + IOUtils.closeQuietly( os ); + IOUtils.closeQuietly( tmpManifestWriter ); + IOUtils.closeQuietly( execWarJarOutputStream ); + IOUtils.closeQuietly( tmpPropertiesFileOutputStream ); + } + + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExecWarMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExecWarMojo.java new file mode 100644 index 00000000..921f853f --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExecWarMojo.java @@ -0,0 +1,40 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; + +/** + * Create a self executable jar file containing all necessary Apache Tomcat classes. + * This allows for using just java -jar mywebapp.jar to run your webapp without + * needing to install a Tomcat instance. + * More details here. + * + * @author Olivier Lamy + * @since 2.0 + */ +@Mojo( name = "exec-war", threadSafe = true ) +@Execute( phase = LifecyclePhase.PACKAGE ) +public class ExecWarMojo + extends AbstractExecWarMojo +{ + // no op only mojo metadatas +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExecWarOnlyMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExecWarOnlyMojo.java new file mode 100644 index 00000000..686fe9d8 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExecWarOnlyMojo.java @@ -0,0 +1,34 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Mojo; + +/** + * Same as exec-war goal without forking the package lifecycle. + * + * @author Olivier Lamy + * @since 2.0 + */ +@Mojo( name = "exec-war-only", threadSafe = true ) +public class ExecWarOnlyMojo + extends AbstractExecWarMojo +{ + // no op only mojo metadatas to not fork a lifecycle +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtendedTomcat.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtendedTomcat.java new file mode 100644 index 00000000..ebd6a7ee --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtendedTomcat.java @@ -0,0 +1,69 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.catalina.Context; +import org.apache.catalina.Host; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.startup.ContextConfig; +import org.apache.catalina.startup.Tomcat; + +import java.io.File; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +public class ExtendedTomcat + extends Tomcat +{ + + private File configurationDir; + + public ExtendedTomcat( File configurationDir ) + { + super(); + this.configurationDir = configurationDir; + } + + public Context addWebapp( Host host, String url, String name, String path ) + { + + Context ctx = new StandardContext(); + ctx.setName( name ); + ctx.setPath( url ); + ctx.setDocBase( path ); + + ContextConfig ctxCfg = new ContextConfig(); + ctx.addLifecycleListener( ctxCfg ); + + ctxCfg.setDefaultWebXml( new File( configurationDir, "conf/web.xml" ).getAbsolutePath() ); + + if ( host == null ) + { + getHost().addChild( ctx ); + } + else + { + host.addChild( ctx ); + } + + return ctx; + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtraDependency.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtraDependency.java new file mode 100644 index 00000000..7accec71 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtraDependency.java @@ -0,0 +1,31 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.model.Dependency; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +public class ExtraDependency + extends Dependency +{ + // no op just here to support for maven 2.x +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtraResource.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtraResource.java new file mode 100644 index 00000000..9a00bd04 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ExtraResource.java @@ -0,0 +1,31 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.model.Resource; + +/** + * @author Olivier Lamy + */ +public class ExtraResource + extends Resource +{ + // no op just here to support for maven 2.x +} + diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunMojo.java new file mode 100644 index 00000000..8b097d2f --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunMojo.java @@ -0,0 +1,462 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.apache.catalina.Context; +import org.apache.catalina.WebResource; +import org.apache.catalina.loader.WebappLoader; +import org.apache.catalina.webresources.DirResourceSet; +import org.apache.catalina.webresources.EmptyResource; +import org.apache.catalina.webresources.FileResourceSet; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.model.Plugin; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.shared.filtering.MavenFileFilterRequest; +import org.apache.maven.shared.filtering.MavenFilteringException; +import org.apache.tomcat.maven.common.run.ClassLoaderEntriesCalculator; +import org.apache.tomcat.maven.common.run.ClassLoaderEntriesCalculatorRequest; +import org.apache.tomcat.maven.common.run.ClassLoaderEntriesCalculatorResult; +import org.apache.tomcat.maven.common.run.TomcatRunException; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.Xpp3DomBuilder; +import org.codehaus.plexus.util.xml.Xpp3DomWriter; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +/** + * Runs the current project as a dynamic web application using an embedded Tomcat server. + * + * @author Olivier Lamy + * @since 2.0 + */ +@Mojo( name = "run", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true ) +@Execute( phase = LifecyclePhase.PROCESS_CLASSES ) +public class RunMojo + extends AbstractRunMojo +{ + // ---------------------------------------------------------------------- + // Mojo Parameters + // ---------------------------------------------------------------------- + + + /** + * The set of dependencies for the web application being run. + */ + @Parameter( defaultValue = "${project.artifacts}", required = true, readonly = true ) + private Set dependencies; + + /** + * The web resources directory for the web application being run. + */ + @Parameter( defaultValue = "${basedir}/src/main/webapp", property = "tomcat.warSourceDirectory" ) + private File warSourceDirectory; + + + /** + * Set the "follow standard delegation model" flag used to configure our ClassLoader. + * + * @see http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/loader/WebappLoader.html#setDelegate(boolean) + * @since 1.0 + */ + @Parameter( property = "tomcat.delegate", defaultValue = "true" ) + private boolean delegate = true; + + /** + * @since 2.0 + */ + @Component + private ClassLoaderEntriesCalculator classLoaderEntriesCalculator; + + /** + * will add /WEB-INF/lib/*.jar and /WEB-INF/classes from war dependencies in the webappclassloader + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.addWarDependenciesInClassloader", defaultValue = "true" ) + private boolean addWarDependenciesInClassloader; + + /** + * will use the test classpath rather than the compile one and will add test dependencies too + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.useTestClasspath", defaultValue = "false" ) + private boolean useTestClasspath; + + /** + * Additional optional directories to add to the embedded tomcat classpath. + * + * @since 2.0 + */ + @Parameter( alias = "additionalClassesDirs" ) + private List additionalClasspathDirs; + + + public final File getWarSourceDirectory() + { + return warSourceDirectory; + } + + /** + * {@inheritDoc} + */ + @Override + protected File getDocBase() + throws IOException + { + // https://issues.apache.org/jira/browse/MTOMCAT-239 + // when running a jar docBase doesn't exists so create a fake one + if ( !warSourceDirectory.exists() ) + { + // we create a temporary file in build.directory + final File tempDocBase = createTempDirectory( new File( project.getBuild().getDirectory() ) ); + Runtime.getRuntime().addShutdownHook( new Thread() + { + @Override + public void run() + { + try + { + FileUtils.deleteDirectory( tempDocBase ); + } + catch ( Exception e ) + { + // we can consider as safe to ignore as it's located in build directory + } + } + } ); + return tempDocBase; + } + return warSourceDirectory; + } + + private static File createTempDirectory( File baseTmpDirectory ) + throws IOException + { + final File temp = File.createTempFile( "temp", Long.toString( System.nanoTime() ), baseTmpDirectory ); + + if ( !( temp.delete() ) ) + { + throw new IOException( "Could not delete temp file: " + temp.getAbsolutePath() ); + } + + if ( !( temp.mkdir() ) ) + { + throw new IOException( "Could not create temp directory: " + temp.getAbsolutePath() ); + } + + return temp; + } + + /** + * {@inheritDoc} + */ + @Override + protected File getContextFile() + throws MojoExecutionException + { + File temporaryContextFile = null; + + //---------------------------------------------------------------------------- + // context attributes backgroundProcessorDelay reloadable cannot be modified at runtime. + // It looks only values from the file are used + // so here we create a temporary file with values modified + //---------------------------------------------------------------------------- + FileReader fr = null; + FileWriter fw = null; + StringWriter sw = new StringWriter(); + try + { + temporaryContextFile = File.createTempFile( "tomcat-maven-plugin", "temp-ctx-file" ); + temporaryContextFile.deleteOnExit(); + + // format to modify/create + if ( contextFile != null && contextFile.exists() ) + { + MavenFileFilterRequest mavenFileFilterRequest = new MavenFileFilterRequest(); + mavenFileFilterRequest.setFrom( contextFile ); + mavenFileFilterRequest.setTo( temporaryContextFile ); + mavenFileFilterRequest.setMavenProject( project ); + mavenFileFilterRequest.setMavenSession( session ); + mavenFileFilterRequest.setFiltering( true ); + + mavenFileFilter.copyFile( mavenFileFilterRequest ); + + fr = new FileReader( temporaryContextFile ); + Xpp3Dom xpp3Dom = Xpp3DomBuilder.build( fr ); + xpp3Dom.setAttribute( "backgroundProcessorDelay", Integer.toString( backgroundProcessorDelay ) ); + xpp3Dom.setAttribute( "reloadable", Boolean.toString( isContextReloadable() ) ); + fw = new FileWriter( temporaryContextFile ); + Xpp3DomWriter.write( fw, xpp3Dom ); + Xpp3DomWriter.write( sw, xpp3Dom ); + getLog().debug( " generated context file " + sw.toString() ); + } + else + { + if ( contextReloadable ) + { + // don't care about using a complicated xml api to create one xml line :-) + StringBuilder sb = new StringBuilder( "" ); + + getLog().debug( " generated context file " + sb.toString() ); + fw = new FileWriter( temporaryContextFile ); + fw.write( sb.toString() ); + } + else + { + // no user context file and contextReloadable false so no need about creating a hack one + return null; + } + } + } + catch ( IOException e ) + { + getLog().error( "error creating fake context.xml : " + e.getMessage(), e ); + throw new MojoExecutionException( "error creating fake context.xml : " + e.getMessage(), e ); + } + catch ( XmlPullParserException e ) + { + getLog().error( "error creating fake context.xml : " + e.getMessage(), e ); + throw new MojoExecutionException( "error creating fake context.xml : " + e.getMessage(), e ); + } + catch ( MavenFilteringException e ) + { + getLog().error( "error filtering context.xml : " + e.getMessage(), e ); + throw new MojoExecutionException( "error filtering context.xml : " + e.getMessage(), e ); + } + finally + { + IOUtil.close( fw ); + IOUtil.close( fr ); + IOUtil.close( sw ); + } + + return temporaryContextFile; + } + + /** + * {@inheritDoc} + * + * @throws MojoExecutionException + */ + @Override + protected WebappLoader createWebappLoader() + throws IOException, MojoExecutionException + { + WebappLoader loader = super.createWebappLoader(); + + if ( useSeparateTomcatClassLoader ) + { + loader.setDelegate( delegate ); + } + + return loader; + } + + @Override + protected void enhanceContext( final Context context ) + throws MojoExecutionException + { + super.enhanceContext( context ); + + try + { + ClassLoaderEntriesCalculatorRequest request = new ClassLoaderEntriesCalculatorRequest() // + .setDependencies( dependencies ) // + .setLog( getLog() ) // + .setMavenProject( project ) // + .setAddWarDependenciesInClassloader( addWarDependenciesInClassloader ) // + .setUseTestClassPath( useTestClasspath ); + final ClassLoaderEntriesCalculatorResult classLoaderEntriesCalculatorResult = + classLoaderEntriesCalculator.calculateClassPathEntries( request ); + final List classLoaderEntries = classLoaderEntriesCalculatorResult.getClassPathEntries(); + final List tmpDirectories = classLoaderEntriesCalculatorResult.getTmpDirectories(); + + /* Add jars */ + final List jarPaths = extractJars( classLoaderEntries ); + for (String jarPath : jarPaths) { + File f = new File(jarPath); + if (f.exists()) { + /* We add the jar as a file under /WEB-INF/lib and Tomcat takes care of creating a JarResourceSet for its classes and + for its resources in /META-INF/resources as appropriate. Basically it hooks into Tomcat's usual handling. + */ + getLog().debug("Adding jar resource: " + f.getAbsolutePath()); + FileResourceSet fileResourceSet = new FileResourceSet(context.getResources(), "/WEB-INF/lib/" + f.getName(), f.getAbsolutePath(), "/"); + context.getResources().addPostResources(fileResourceSet); + } + } + + /* Add build directories */ + getLog().debug("Adding classes resource: " + new File(project.getBuild().getOutputDirectory()).getAbsolutePath()); + DirResourceSet webinfClassesResources = new DirResourceSet(context.getResources(), "/WEB-INF/classes", new File(project.getBuild().getOutputDirectory()).getAbsolutePath(), "/") { + + @Override + public WebResource getResource(String path) { + /* We need to juggle with /META-INF/beans.xml as Weld's WebAppBeanArchiveScanner has special handling + for /WEB-INF/classes that doesn't work with this. + That is because it first finds _all_ resources /META-INF/beans.xml and it ends up with the URLs to those + resources, which are all file-system URLs, and then looks for /WEB-INF/classes in the URL, which we don't + have as our files are in the Maven target directory. + */ + if ("/WEB-INF/classes/META-INF/beans.xml".equals(path)) { + getLog().info("Rejecting request for /WEB-INF/classes/META-INF/beans.xml for Weld compatibility. beans.xml can be found at /WEB-INF/beans.xml"); + return new EmptyResource(getRoot(), path); + } else if ("/WEB-INF/beans.xml".equals(path)) { + WebResource beans = super.getResource(path); + if (!beans.exists()) { + beans = super.getResource("/WEB-INF/classes/META-INF/beans.xml"); + if (beans.exists()) { + getLog().info("Returning /WEB-INF/classes/META-INF/beans.xml for request of /WEB-INF/beans.xml for Weld compatibility"); + } + } + return beans; + } else { + return super.getResource(path); + } + } + + }; + context.getResources().addPreResources(webinfClassesResources); + + for (final String buildDirectory : classLoaderEntriesCalculatorResult.getBuildDirectories()) { + if (buildDirectory.equals(project.getBuild().getOutputDirectory())) { + continue; + } + + final File buildDirectoryFile = new File(buildDirectory); + getLog().debug("Adding additional classes resource: " + buildDirectoryFile.getAbsolutePath()); + DirResourceSet otherClassesResources = new DirResourceSet(context.getResources(), "/WEB-INF/classes", buildDirectoryFile.getAbsolutePath(), "/"); + context.getResources().addPreResources(otherClassesResources); + } + + /* Support the maven-war-plugin's webResources configuration to add resources */ + final Plugin warPlugin = (Plugin) project.getBuild().getPluginsAsMap().get("org.apache.maven.plugins:maven-war-plugin"); + if (warPlugin != null && warPlugin.getConfiguration() instanceof Xpp3Dom) { + final Xpp3Dom cfg = (Xpp3Dom) warPlugin.getConfiguration(); + Xpp3Dom webResources = cfg.getChild("webResources"); + if (webResources != null) { + Xpp3Dom[] resources = webResources.getChildren("resource"); + for (Xpp3Dom resource : resources) { + Xpp3Dom directoryNode = resource.getChild("directory"); + if (directoryNode == null) { + continue; + } + final String directory = directoryNode.getValue(); + + Xpp3Dom targetPathNode = resource.getChild("targetPath"); + final String targetPath = targetPathNode != null ? "/" + targetPathNode.getValue() : "/"; + + Xpp3Dom filtering = resource.getChild("filtering"); + if (filtering != null && "true".equals(filtering.getValue())) { + /* We don't support filtered resources */ + getLog().warn("Cannot support filtered web-resource, not adding: " + directory); + continue; + } + + File directoryFile = directory.startsWith(File.separator) ? new File(directory) : new File(project.getBasedir(), directory); + DirResourceSet dirResourceSet = new DirResourceSet(context.getResources(), targetPath, directoryFile.getAbsolutePath(), "/"); + dirResourceSet.setStaticOnly(true); + context.getResources().addPostResources(dirResourceSet); + + getLog().debug("Adding additional static resources at \"" + targetPath + "\": " + directoryFile.getAbsolutePath()); + } + } + } + + Runtime.getRuntime().addShutdownHook( new Thread() + { + @Override + public void run() + { + for ( File tmpDir : tmpDirectories ) + { + try + { + FileUtils.deleteDirectory( tmpDir ); + } + catch ( IOException e ) + { + // ignore + } + } + } + } ); + } + catch ( TomcatRunException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + + } + + + /** + * extract List of path which are jar files + * + * @param classLoaderEntries + * @return + */ + private List extractJars( List classLoaderEntries ) + throws MojoExecutionException + { + + List jarPaths = new ArrayList(); + + try + { + for ( String classLoaderEntry : classLoaderEntries ) + { + URI uri = new URI( classLoaderEntry ); + File file = new File( uri ); + if ( !file.isDirectory() && StringUtils.endsWithIgnoreCase(file.getName(), ".jar")) + { + jarPaths.add( file.getAbsolutePath() ); + } + } + } + catch ( URISyntaxException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } + + return jarPaths; + + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunWarMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunWarMojo.java new file mode 100644 index 00000000..7f617ecd --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunWarMojo.java @@ -0,0 +1,40 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Runs the current project as a packaged web application using an embedded Tomcat server. + * + * @author Mark Hobson + * @todo depend on war:exploded when MNG-1649 resolved + */ +@Mojo( name = "run-war", requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true ) +@Execute( phase = LifecyclePhase.PACKAGE ) +public class RunWarMojo + extends AbstractRunWarMojo +{ + // no-op : only mojo metadata overriding +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunWarOnlyMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunWarOnlyMojo.java new file mode 100644 index 00000000..978821f0 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/RunWarOnlyMojo.java @@ -0,0 +1,36 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Same as run-war goal without forking the package cycle. + * + * @author vlatombe + */ +@Mojo( name = "run-war-only", requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true ) +public class RunWarOnlyMojo + extends AbstractRunWarMojo +{ + // no-op : only mojo metadata overriding +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ShutdownMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ShutdownMojo.java new file mode 100644 index 00000000..6b0df953 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/ShutdownMojo.java @@ -0,0 +1,90 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; + +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.tomcat.maven.common.run.EmbeddedRegistry; +import org.apache.tomcat.maven.plugin.tomcat9.AbstractTomcat9Mojo; + + +/** + *

+ * Shuts down all possibly started embedded Tomcat servers. This will be automatically done + * through a shutdown hook or you may call this Mojo to shut them down explictly. + *

+ *

+ * By default the shutdown goal is not bound to any phase. For integration tests + * you might want to bind it to post-integration-test. + *

+ * + * @author Mark Michaelis + * @since 2.0 + */ +@Mojo( name = "shutdown", requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true ) +public class ShutdownMojo + extends AbstractTomcat9Mojo +{ + + /** + * Ignore error when shutdown + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.skipErrorOnShutdown", defaultValue = "false" ) + protected boolean skipErrorOnShutdown; + + /** + * Skip execution + * + * @since 2.0 + */ + @Parameter( property = "maven.tomcat.skipShutdown", defaultValue = "false" ) + protected boolean skip; + + /** + * Shuts down all embedded tomcats which got started up to now. + * + * @throws org.apache.maven.plugin.MojoExecutionException + * if shutting down one or all servers failed + */ + public void execute() + throws MojoExecutionException + { + if ( skip ) + { + getLog().info( "skip execution" ); + return; + } + try + { + EmbeddedRegistry.getInstance().shutdownAll( getLog() ); + } + catch ( Exception e ) + { + if ( !skipErrorOnShutdown ) + { + throw new MojoExecutionException( messagesProvider.getMessage( "ShutdownMojo.shutdownError" ), e ); + } + } + } +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/StandaloneWarMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/StandaloneWarMojo.java new file mode 100644 index 00000000..00d0c54f --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/StandaloneWarMojo.java @@ -0,0 +1,36 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; + +/** + * This Mojo will create an executable war file with embedded Tomcat that is also capable of being deployed elsewhere. + * + * @since 2.1 + */ +@Mojo(name = "standalone-war", threadSafe = true) +@Execute(phase = LifecyclePhase.PACKAGE) +public class StandaloneWarMojo + extends AbstractStandaloneWarMojo +{ + // no op +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/StandaloneWarOnlyMojo.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/StandaloneWarOnlyMojo.java new file mode 100644 index 00000000..fd93e586 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/StandaloneWarOnlyMojo.java @@ -0,0 +1,33 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.plugins.annotations.Mojo; + +/** + * This Mojo will create an executable war file with embedded Tomcat that is also capable of being deployed elsewhere. + * + * @since 2.1 + */ +@Mojo(name = "standalone-war-only", threadSafe = true) +public class StandaloneWarOnlyMojo + extends AbstractStandaloneWarMojo +{ + // no op +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/WarRunDependency.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/WarRunDependency.java new file mode 100644 index 00000000..882dbb87 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/WarRunDependency.java @@ -0,0 +1,43 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.model.Dependency; + +import java.io.File; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +public class WarRunDependency +{ + + public Dependency dependency; + + public String contextPath; + + public File contextXml; + + public WarRunDependency() + { + // no op + } + +} diff --git a/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/Webapp.java b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/Webapp.java new file mode 100644 index 00000000..7e75658f --- /dev/null +++ b/tomcat9-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat9/run/Webapp.java @@ -0,0 +1,44 @@ +package org.apache.tomcat.maven.plugin.tomcat9.run; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.artifact.Artifact; +import org.apache.tomcat.maven.common.config.AbstractWebapp; + +/** + * Webapp represents information specified in the plugin configuration section + * for each webapp. + * + * @since 2.0 + */ +public class Webapp + extends AbstractWebapp +{ + + public Webapp() + { + // default constructor + } + + public Webapp( Artifact artifact ) + { + super( artifact ); + } +} diff --git a/tomcat9-maven-plugin/src/main/resources/conf/logging.properties b/tomcat9-maven-plugin/src/main/resources/conf/logging.properties new file mode 100644 index 00000000..6b6c8c00 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/resources/conf/logging.properties @@ -0,0 +1,64 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +handlers = 1catalina.org.apache.juli.AsyncFileHandler, 2localhost.org.apache.juli.AsyncFileHandler, 3manager.org.apache.juli.AsyncFileHandler, 4host-manager.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler + +.handlers = 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +1catalina.org.apache.juli.AsyncFileHandler.level = FINE +1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs +1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina. + +2localhost.org.apache.juli.AsyncFileHandler.level = FINE +2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs +2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost. + +3manager.org.apache.juli.AsyncFileHandler.level = FINE +3manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs +3manager.org.apache.juli.AsyncFileHandler.prefix = manager. + +4host-manager.org.apache.juli.AsyncFileHandler.level = FINE +4host-manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs +4host-manager.org.apache.juli.AsyncFileHandler.prefix = host-manager. + +java.util.logging.ConsoleHandler.level = FINE +java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter + + +############################################################ +# Facility specific properties. +# Provides extra control for each logger. +############################################################ + +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler + +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler + +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler + +# For example, set the org.apache.catalina.util.LifecycleBase logger to log +# each component that extends LifecycleBase changing state: +#org.apache.catalina.util.LifecycleBase.level = FINE + +# To see debug messages in TldLocationsCache, uncomment the following line: +#org.apache.jasper.compiler.TldLocationsCache.level = FINE diff --git a/tomcat9-maven-plugin/src/main/resources/conf/tomcat-users.xml b/tomcat9-maven-plugin/src/main/resources/conf/tomcat-users.xml new file mode 100644 index 00000000..34e268d8 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/resources/conf/tomcat-users.xml @@ -0,0 +1,36 @@ + + + + + + + diff --git a/tomcat9-maven-plugin/src/main/resources/conf/web.xml b/tomcat9-maven-plugin/src/main/resources/conf/web.xml new file mode 100644 index 00000000..81a201f8 --- /dev/null +++ b/tomcat9-maven-plugin/src/main/resources/conf/web.xml @@ -0,0 +1,4614 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + org.apache.catalina.servlets.DefaultServlet + + debug + 0 + + + listings + false + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jsp + org.apache.jasper.servlet.JspServlet + + fork + false + + + xpoweredBy + false + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + / + + + + + jsp + *.jsp + *.jspx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30 + + + + + + + + + + + + + 123 + application/vnd.lotus-1-2-3 + + + 3dml + text/vnd.in3d.3dml + + + 3ds + image/x-3ds + + + 3g2 + video/3gpp2 + + + 3gp + video/3gpp + + + 7z + application/x-7z-compressed + + + aab + application/x-authorware-bin + + + aac + audio/x-aac + + + aam + application/x-authorware-map + + + aas + application/x-authorware-seg + + + abs + audio/x-mpeg + + + abw + application/x-abiword + + + ac + application/pkix-attr-cert + + + acc + application/vnd.americandynamics.acc + + + ace + application/x-ace-compressed + + + acu + application/vnd.acucobol + + + acutc + application/vnd.acucorp + + + adp + audio/adpcm + + + aep + application/vnd.audiograph + + + afm + application/x-font-type1 + + + afp + application/vnd.ibm.modcap + + + ahead + application/vnd.ahead.space + + + ai + application/postscript + + + aif + audio/x-aiff + + + aifc + audio/x-aiff + + + aiff + audio/x-aiff + + + aim + application/x-aim + + + air + application/vnd.adobe.air-application-installer-package+zip + + + ait + application/vnd.dvb.ait + + + ami + application/vnd.amiga.ami + + + anx + application/annodex + + + apk + application/vnd.android.package-archive + + + appcache + text/cache-manifest + + + application + application/x-ms-application + + + apr + application/vnd.lotus-approach + + + arc + application/x-freearc + + + art + image/x-jg + + + asc + application/pgp-signature + + + asf + video/x-ms-asf + + + asm + text/x-asm + + + aso + application/vnd.accpac.simply.aso + + + asx + video/x-ms-asf + + + atc + application/vnd.acucorp + + + atom + application/atom+xml + + + atomcat + application/atomcat+xml + + + atomsvc + application/atomsvc+xml + + + atx + application/vnd.antix.game-component + + + au + audio/basic + + + avi + video/x-msvideo + + + avx + video/x-rad-screenplay + + + aw + application/applixware + + + axa + audio/annodex + + + axv + video/annodex + + + azf + application/vnd.airzip.filesecure.azf + + + azs + application/vnd.airzip.filesecure.azs + + + azw + application/vnd.amazon.ebook + + + bat + application/x-msdownload + + + bcpio + application/x-bcpio + + + bdf + application/x-font-bdf + + + bdm + application/vnd.syncml.dm+wbxml + + + bed + application/vnd.realvnc.bed + + + bh2 + application/vnd.fujitsu.oasysprs + + + bin + application/octet-stream + + + blb + application/x-blorb + + + blorb + application/x-blorb + + + bmi + application/vnd.bmi + + + bmp + image/bmp + + + body + text/html + + + book + application/vnd.framemaker + + + box + application/vnd.previewsystems.box + + + boz + application/x-bzip2 + + + bpk + application/octet-stream + + + btif + image/prs.btif + + + bz + application/x-bzip + + + bz2 + application/x-bzip2 + + + c + text/x-c + + + c11amc + application/vnd.cluetrust.cartomobile-config + + + c11amz + application/vnd.cluetrust.cartomobile-config-pkg + + + c4d + application/vnd.clonk.c4group + + + c4f + application/vnd.clonk.c4group + + + c4g + application/vnd.clonk.c4group + + + c4p + application/vnd.clonk.c4group + + + c4u + application/vnd.clonk.c4group + + + cab + application/vnd.ms-cab-compressed + + + caf + audio/x-caf + + + cap + application/vnd.tcpdump.pcap + + + car + application/vnd.curl.car + + + cat + application/vnd.ms-pki.seccat + + + cb7 + application/x-cbr + + + cba + application/x-cbr + + + cbr + application/x-cbr + + + cbt + application/x-cbr + + + cbz + application/x-cbr + + + cc + text/x-c + + + cct + application/x-director + + + ccxml + application/ccxml+xml + + + cdbcmsg + application/vnd.contact.cmsg + + + cdf + application/x-cdf + + + cdkey + application/vnd.mediastation.cdkey + + + cdmia + application/cdmi-capability + + + cdmic + application/cdmi-container + + + cdmid + application/cdmi-domain + + + cdmio + application/cdmi-object + + + cdmiq + application/cdmi-queue + + + cdx + chemical/x-cdx + + + cdxml + application/vnd.chemdraw+xml + + + cdy + application/vnd.cinderella + + + cer + application/pkix-cert + + + cfs + application/x-cfs-compressed + + + cgm + image/cgm + + + chat + application/x-chat + + + chm + application/vnd.ms-htmlhelp + + + chrt + application/vnd.kde.kchart + + + cif + chemical/x-cif + + + cii + application/vnd.anser-web-certificate-issue-initiation + + + cil + application/vnd.ms-artgalry + + + cla + application/vnd.claymore + + + class + application/java + + + clkk + application/vnd.crick.clicker.keyboard + + + clkp + application/vnd.crick.clicker.palette + + + clkt + application/vnd.crick.clicker.template + + + clkw + application/vnd.crick.clicker.wordbank + + + clkx + application/vnd.crick.clicker + + + clp + application/x-msclip + + + cmc + application/vnd.cosmocaller + + + cmdf + chemical/x-cmdf + + + cml + chemical/x-cml + + + cmp + application/vnd.yellowriver-custom-menu + + + cmx + image/x-cmx + + + cod + application/vnd.rim.cod + + + com + application/x-msdownload + + + conf + text/plain + + + cpio + application/x-cpio + + + cpp + text/x-c + + + cpt + application/mac-compactpro + + + crd + application/x-mscardfile + + + crl + application/pkix-crl + + + crt + application/x-x509-ca-cert + + + cryptonote + application/vnd.rig.cryptonote + + + csh + application/x-csh + + + csml + chemical/x-csml + + + csp + application/vnd.commonspace + + + css + text/css + + + cst + application/x-director + + + csv + text/csv + + + cu + application/cu-seeme + + + curl + text/vnd.curl + + + cww + application/prs.cww + + + cxt + application/x-director + + + cxx + text/x-c + + + dae + model/vnd.collada+xml + + + daf + application/vnd.mobius.daf + + + dart + application/vnd.dart + + + dataless + application/vnd.fdsn.seed + + + davmount + application/davmount+xml + + + dbk + application/docbook+xml + + + dcr + application/x-director + + + dcurl + text/vnd.curl.dcurl + + + dd2 + application/vnd.oma.dd2+xml + + + ddd + application/vnd.fujixerox.ddd + + + deb + application/x-debian-package + + + def + text/plain + + + deploy + application/octet-stream + + + der + application/x-x509-ca-cert + + + dfac + application/vnd.dreamfactory + + + dgc + application/x-dgc-compressed + + + dib + image/bmp + + + dic + text/x-c + + + dir + application/x-director + + + dis + application/vnd.mobius.dis + + + dist + application/octet-stream + + + distz + application/octet-stream + + + djv + image/vnd.djvu + + + djvu + image/vnd.djvu + + + dll + application/x-msdownload + + + dmg + application/x-apple-diskimage + + + dmp + application/vnd.tcpdump.pcap + + + dms + application/octet-stream + + + dna + application/vnd.dna + + + doc + application/msword + + + docm + application/vnd.ms-word.document.macroenabled.12 + + + docx + application/vnd.openxmlformats-officedocument.wordprocessingml.document + + + dot + application/msword + + + dotm + application/vnd.ms-word.template.macroenabled.12 + + + dotx + application/vnd.openxmlformats-officedocument.wordprocessingml.template + + + dp + application/vnd.osgi.dp + + + dpg + application/vnd.dpgraph + + + dra + audio/vnd.dra + + + dsc + text/prs.lines.tag + + + dssc + application/dssc+der + + + dtb + application/x-dtbook+xml + + + dtd + application/xml-dtd + + + dts + audio/vnd.dts + + + dtshd + audio/vnd.dts.hd + + + dump + application/octet-stream + + + dv + video/x-dv + + + dvb + video/vnd.dvb.file + + + dvi + application/x-dvi + + + dwf + model/vnd.dwf + + + dwg + image/vnd.dwg + + + dxf + image/vnd.dxf + + + dxp + application/vnd.spotfire.dxp + + + dxr + application/x-director + + + ecelp4800 + audio/vnd.nuera.ecelp4800 + + + ecelp7470 + audio/vnd.nuera.ecelp7470 + + + ecelp9600 + audio/vnd.nuera.ecelp9600 + + + ecma + application/ecmascript + + + edm + application/vnd.novadigm.edm + + + edx + application/vnd.novadigm.edx + + + efif + application/vnd.picsel + + + ei6 + application/vnd.pg.osasli + + + elc + application/octet-stream + + + emf + application/x-msmetafile + + + eml + message/rfc822 + + + emma + application/emma+xml + + + emz + application/x-msmetafile + + + eol + audio/vnd.digital-winds + + + eot + application/vnd.ms-fontobject + + + eps + application/postscript + + + epub + application/epub+zip + + + es3 + application/vnd.eszigno3+xml + + + esa + application/vnd.osgi.subsystem + + + esf + application/vnd.epson.esf + + + et3 + application/vnd.eszigno3+xml + + + etx + text/x-setext + + + eva + application/x-eva + + + evy + application/x-envoy + + + exe + application/octet-stream + + + exi + application/exi + + + ext + application/vnd.novadigm.ext + + + ez + application/andrew-inset + + + ez2 + application/vnd.ezpix-album + + + ez3 + application/vnd.ezpix-package + + + f + text/x-fortran + + + f4v + video/x-f4v + + + f77 + text/x-fortran + + + f90 + text/x-fortran + + + fbs + image/vnd.fastbidsheet + + + fcdt + application/vnd.adobe.formscentral.fcdt + + + fcs + application/vnd.isac.fcs + + + fdf + application/vnd.fdf + + + fe_launch + application/vnd.denovo.fcselayout-link + + + fg5 + application/vnd.fujitsu.oasysgp + + + fgd + application/x-director + + + fh + image/x-freehand + + + fh4 + image/x-freehand + + + fh5 + image/x-freehand + + + fh7 + image/x-freehand + + + fhc + image/x-freehand + + + fig + application/x-xfig + + + flac + audio/flac + + + fli + video/x-fli + + + flo + application/vnd.micrografx.flo + + + flv + video/x-flv + + + flw + application/vnd.kde.kivio + + + flx + text/vnd.fmi.flexstor + + + fly + text/vnd.fly + + + fm + application/vnd.framemaker + + + fnc + application/vnd.frogans.fnc + + + for + text/x-fortran + + + fpx + image/vnd.fpx + + + frame + application/vnd.framemaker + + + fsc + application/vnd.fsc.weblaunch + + + fst + image/vnd.fst + + + ftc + application/vnd.fluxtime.clip + + + fti + application/vnd.anser-web-funds-transfer-initiation + + + fvt + video/vnd.fvt + + + fxp + application/vnd.adobe.fxp + + + fxpl + application/vnd.adobe.fxp + + + fzs + application/vnd.fuzzysheet + + + g2w + application/vnd.geoplan + + + g3 + image/g3fax + + + g3w + application/vnd.geospace + + + gac + application/vnd.groove-account + + + gam + application/x-tads + + + gbr + application/rpki-ghostbusters + + + gca + application/x-gca-compressed + + + gdl + model/vnd.gdl + + + geo + application/vnd.dynageo + + + gex + application/vnd.geometry-explorer + + + ggb + application/vnd.geogebra.file + + + ggt + application/vnd.geogebra.tool + + + ghf + application/vnd.groove-help + + + gif + image/gif + + + gim + application/vnd.groove-identity-message + + + gml + application/gml+xml + + + gmx + application/vnd.gmx + + + gnumeric + application/x-gnumeric + + + gph + application/vnd.flographit + + + gpx + application/gpx+xml + + + gqf + application/vnd.grafeq + + + gqs + application/vnd.grafeq + + + gram + application/srgs + + + gramps + application/x-gramps-xml + + + gre + application/vnd.geometry-explorer + + + grv + application/vnd.groove-injector + + + grxml + application/srgs+xml + + + gsf + application/x-font-ghostscript + + + gtar + application/x-gtar + + + gtm + application/vnd.groove-tool-message + + + gtw + model/vnd.gtw + + + gv + text/vnd.graphviz + + + gxf + application/gxf + + + gxt + application/vnd.geonext + + + gz + application/x-gzip + + + h + text/x-c + + + h261 + video/h261 + + + h263 + video/h263 + + + h264 + video/h264 + + + hal + application/vnd.hal+xml + + + hbci + application/vnd.hbci + + + hdf + application/x-hdf + + + hh + text/x-c + + + hlp + application/winhlp + + + hpgl + application/vnd.hp-hpgl + + + hpid + application/vnd.hp-hpid + + + hps + application/vnd.hp-hps + + + hqx + application/mac-binhex40 + + + htc + text/x-component + + + htke + application/vnd.kenameaapp + + + htm + text/html + + + html + text/html + + + hvd + application/vnd.yamaha.hv-dic + + + hvp + application/vnd.yamaha.hv-voice + + + hvs + application/vnd.yamaha.hv-script + + + i2g + application/vnd.intergeo + + + icc + application/vnd.iccprofile + + + ice + x-conference/x-cooltalk + + + icm + application/vnd.iccprofile + + + ico + image/x-icon + + + ics + text/calendar + + + ief + image/ief + + + ifb + text/calendar + + + ifm + application/vnd.shana.informed.formdata + + + iges + model/iges + + + igl + application/vnd.igloader + + + igm + application/vnd.insors.igm + + + igs + model/iges + + + igx + application/vnd.micrografx.igx + + + iif + application/vnd.shana.informed.interchange + + + imp + application/vnd.accpac.simply.imp + + + ims + application/vnd.ms-ims + + + in + text/plain + + + ink + application/inkml+xml + + + inkml + application/inkml+xml + + + install + application/x-install-instructions + + + iota + application/vnd.astraea-software.iota + + + ipfix + application/ipfix + + + ipk + application/vnd.shana.informed.package + + + irm + application/vnd.ibm.rights-management + + + irp + application/vnd.irepository.package+xml + + + iso + application/x-iso9660-image + + + itp + application/vnd.shana.informed.formtemplate + + + ivp + application/vnd.immervision-ivp + + + ivu + application/vnd.immervision-ivu + + + jad + text/vnd.sun.j2me.app-descriptor + + + jam + application/vnd.jam + + + jar + application/java-archive + + + java + text/x-java-source + + + jisp + application/vnd.jisp + + + jlt + application/vnd.hp-jlyt + + + jnlp + application/x-java-jnlp-file + + + joda + application/vnd.joost.joda-archive + + + jpe + image/jpeg + + + jpeg + image/jpeg + + + jpg + image/jpeg + + + jpgm + video/jpm + + + jpgv + video/jpeg + + + jpm + video/jpm + + + js + application/javascript + + + jsf + text/plain + + + json + application/json + + + jsonml + application/jsonml+json + + + jspf + text/plain + + + kar + audio/midi + + + karbon + application/vnd.kde.karbon + + + kfo + application/vnd.kde.kformula + + + kia + application/vnd.kidspiration + + + kml + application/vnd.google-earth.kml+xml + + + kmz + application/vnd.google-earth.kmz + + + kne + application/vnd.kinar + + + knp + application/vnd.kinar + + + kon + application/vnd.kde.kontour + + + kpr + application/vnd.kde.kpresenter + + + kpt + application/vnd.kde.kpresenter + + + kpxx + application/vnd.ds-keypoint + + + ksp + application/vnd.kde.kspread + + + ktr + application/vnd.kahootz + + + ktx + image/ktx + + + ktz + application/vnd.kahootz + + + kwd + application/vnd.kde.kword + + + kwt + application/vnd.kde.kword + + + lasxml + application/vnd.las.las+xml + + + latex + application/x-latex + + + lbd + application/vnd.llamagraphics.life-balance.desktop + + + lbe + application/vnd.llamagraphics.life-balance.exchange+xml + + + les + application/vnd.hhe.lesson-player + + + lha + application/x-lzh-compressed + + + link66 + application/vnd.route66.link66+xml + + + list + text/plain + + + list3820 + application/vnd.ibm.modcap + + + listafp + application/vnd.ibm.modcap + + + lnk + application/x-ms-shortcut + + + log + text/plain + + + lostxml + application/lost+xml + + + lrf + application/octet-stream + + + lrm + application/vnd.ms-lrm + + + ltf + application/vnd.frogans.ltf + + + lvp + audio/vnd.lucent.voice + + + lwp + application/vnd.lotus-wordpro + + + lzh + application/x-lzh-compressed + + + m13 + application/x-msmediaview + + + m14 + application/x-msmediaview + + + m1v + video/mpeg + + + m21 + application/mp21 + + + m2a + audio/mpeg + + + m2v + video/mpeg + + + m3a + audio/mpeg + + + m3u + audio/x-mpegurl + + + m3u8 + application/vnd.apple.mpegurl + + + m4a + audio/mp4 + + + m4b + audio/mp4 + + + m4r + audio/mp4 + + + m4u + video/vnd.mpegurl + + + m4v + video/mp4 + + + ma + application/mathematica + + + mac + image/x-macpaint + + + mads + application/mads+xml + + + mag + application/vnd.ecowin.chart + + + maker + application/vnd.framemaker + + + man + text/troff + + + mar + application/octet-stream + + + mathml + application/mathml+xml + + + mb + application/mathematica + + + mbk + application/vnd.mobius.mbk + + + mbox + application/mbox + + + mc1 + application/vnd.medcalcdata + + + mcd + application/vnd.mcd + + + mcurl + text/vnd.curl.mcurl + + + mdb + application/x-msaccess + + + mdi + image/vnd.ms-modi + + + me + text/troff + + + mesh + model/mesh + + + meta4 + application/metalink4+xml + + + metalink + application/metalink+xml + + + mets + application/mets+xml + + + mfm + application/vnd.mfmp + + + mft + application/rpki-manifest + + + mgp + application/vnd.osgeo.mapguide.package + + + mgz + application/vnd.proteus.magazine + + + mid + audio/midi + + + midi + audio/midi + + + mie + application/x-mie + + + mif + application/x-mif + + + mime + message/rfc822 + + + mj2 + video/mj2 + + + mjp2 + video/mj2 + + + mk3d + video/x-matroska + + + mka + audio/x-matroska + + + mks + video/x-matroska + + + mkv + video/x-matroska + + + mlp + application/vnd.dolby.mlp + + + mmd + application/vnd.chipnuts.karaoke-mmd + + + mmf + application/vnd.smaf + + + mmr + image/vnd.fujixerox.edmics-mmr + + + mng + video/x-mng + + + mny + application/x-msmoney + + + mobi + application/x-mobipocket-ebook + + + mods + application/mods+xml + + + mov + video/quicktime + + + movie + video/x-sgi-movie + + + mp1 + audio/mpeg + + + mp2 + audio/mpeg + + + mp21 + application/mp21 + + + mp2a + audio/mpeg + + + mp3 + audio/mpeg + + + mp4 + video/mp4 + + + mp4a + audio/mp4 + + + mp4s + application/mp4 + + + mp4v + video/mp4 + + + mpa + audio/mpeg + + + mpc + application/vnd.mophun.certificate + + + mpe + video/mpeg + + + mpeg + video/mpeg + + + mpega + audio/x-mpeg + + + mpg + video/mpeg + + + mpg4 + video/mp4 + + + mpga + audio/mpeg + + + mpkg + application/vnd.apple.installer+xml + + + mpm + application/vnd.blueice.multipass + + + mpn + application/vnd.mophun.application + + + mpp + application/vnd.ms-project + + + mpt + application/vnd.ms-project + + + mpv2 + video/mpeg2 + + + mpy + application/vnd.ibm.minipay + + + mqy + application/vnd.mobius.mqy + + + mrc + application/marc + + + mrcx + application/marcxml+xml + + + ms + text/troff + + + mscml + application/mediaservercontrol+xml + + + mseed + application/vnd.fdsn.mseed + + + mseq + application/vnd.mseq + + + msf + application/vnd.epson.msf + + + msh + model/mesh + + + msi + application/x-msdownload + + + msl + application/vnd.mobius.msl + + + msty + application/vnd.muvee.style + + + mts + model/vnd.mts + + + mus + application/vnd.musician + + + musicxml + application/vnd.recordare.musicxml+xml + + + mvb + application/x-msmediaview + + + mwf + application/vnd.mfer + + + mxf + application/mxf + + + mxl + application/vnd.recordare.musicxml + + + mxml + application/xv+xml + + + mxs + application/vnd.triscape.mxs + + + mxu + video/vnd.mpegurl + + + n-gage + application/vnd.nokia.n-gage.symbian.install + + + n3 + text/n3 + + + nb + application/mathematica + + + nbp + application/vnd.wolfram.player + + + nc + application/x-netcdf + + + ncx + application/x-dtbncx+xml + + + nfo + text/x-nfo + + + ngdat + application/vnd.nokia.n-gage.data + + + nitf + application/vnd.nitf + + + nlu + application/vnd.neurolanguage.nlu + + + nml + application/vnd.enliven + + + nnd + application/vnd.noblenet-directory + + + nns + application/vnd.noblenet-sealer + + + nnw + application/vnd.noblenet-web + + + npx + image/vnd.net-fpx + + + nsc + application/x-conference + + + nsf + application/vnd.lotus-notes + + + ntf + application/vnd.nitf + + + nzb + application/x-nzb + + + oa2 + application/vnd.fujitsu.oasys2 + + + oa3 + application/vnd.fujitsu.oasys3 + + + oas + application/vnd.fujitsu.oasys + + + obd + application/x-msbinder + + + obj + application/x-tgif + + + oda + application/oda + + + + odb + application/vnd.oasis.opendocument.database + + + + odc + application/vnd.oasis.opendocument.chart + + + + odf + application/vnd.oasis.opendocument.formula + + + odft + application/vnd.oasis.opendocument.formula-template + + + + odg + application/vnd.oasis.opendocument.graphics + + + + odi + application/vnd.oasis.opendocument.image + + + + odm + application/vnd.oasis.opendocument.text-master + + + + odp + application/vnd.oasis.opendocument.presentation + + + + ods + application/vnd.oasis.opendocument.spreadsheet + + + + odt + application/vnd.oasis.opendocument.text + + + oga + audio/ogg + + + ogg + audio/ogg + + + ogv + video/ogg + + + + ogx + application/ogg + + + omdoc + application/omdoc+xml + + + onepkg + application/onenote + + + onetmp + application/onenote + + + onetoc + application/onenote + + + onetoc2 + application/onenote + + + opf + application/oebps-package+xml + + + opml + text/x-opml + + + oprc + application/vnd.palm + + + org + application/vnd.lotus-organizer + + + osf + application/vnd.yamaha.openscoreformat + + + osfpvg + application/vnd.yamaha.openscoreformat.osfpvg+xml + + + otc + application/vnd.oasis.opendocument.chart-template + + + otf + application/x-font-otf + + + + otg + application/vnd.oasis.opendocument.graphics-template + + + + oth + application/vnd.oasis.opendocument.text-web + + + oti + application/vnd.oasis.opendocument.image-template + + + + otp + application/vnd.oasis.opendocument.presentation-template + + + + ots + application/vnd.oasis.opendocument.spreadsheet-template + + + + ott + application/vnd.oasis.opendocument.text-template + + + oxps + application/oxps + + + oxt + application/vnd.openofficeorg.extension + + + p + text/x-pascal + + + p10 + application/pkcs10 + + + p12 + application/x-pkcs12 + + + p7b + application/x-pkcs7-certificates + + + p7c + application/pkcs7-mime + + + p7m + application/pkcs7-mime + + + p7r + application/x-pkcs7-certreqresp + + + p7s + application/pkcs7-signature + + + p8 + application/pkcs8 + + + pas + text/x-pascal + + + paw + application/vnd.pawaafile + + + pbd + application/vnd.powerbuilder6 + + + pbm + image/x-portable-bitmap + + + pcap + application/vnd.tcpdump.pcap + + + pcf + application/x-font-pcf + + + pcl + application/vnd.hp-pcl + + + pclxl + application/vnd.hp-pclxl + + + pct + image/pict + + + pcurl + application/vnd.curl.pcurl + + + pcx + image/x-pcx + + + pdb + application/vnd.palm + + + pdf + application/pdf + + + pfa + application/x-font-type1 + + + pfb + application/x-font-type1 + + + pfm + application/x-font-type1 + + + pfr + application/font-tdpfr + + + pfx + application/x-pkcs12 + + + pgm + image/x-portable-graymap + + + pgn + application/x-chess-pgn + + + pgp + application/pgp-encrypted + + + pic + image/pict + + + pict + image/pict + + + pkg + application/octet-stream + + + pki + application/pkixcmp + + + pkipath + application/pkix-pkipath + + + plb + application/vnd.3gpp.pic-bw-large + + + plc + application/vnd.mobius.plc + + + plf + application/vnd.pocketlearn + + + pls + audio/x-scpls + + + pml + application/vnd.ctc-posml + + + png + image/png + + + pnm + image/x-portable-anymap + + + pnt + image/x-macpaint + + + portpkg + application/vnd.macports.portpkg + + + pot + application/vnd.ms-powerpoint + + + potm + application/vnd.ms-powerpoint.template.macroenabled.12 + + + potx + application/vnd.openxmlformats-officedocument.presentationml.template + + + ppam + application/vnd.ms-powerpoint.addin.macroenabled.12 + + + ppd + application/vnd.cups-ppd + + + ppm + image/x-portable-pixmap + + + pps + application/vnd.ms-powerpoint + + + ppsm + application/vnd.ms-powerpoint.slideshow.macroenabled.12 + + + ppsx + application/vnd.openxmlformats-officedocument.presentationml.slideshow + + + ppt + application/vnd.ms-powerpoint + + + pptm + application/vnd.ms-powerpoint.presentation.macroenabled.12 + + + pptx + application/vnd.openxmlformats-officedocument.presentationml.presentation + + + pqa + application/vnd.palm + + + prc + application/x-mobipocket-ebook + + + pre + application/vnd.lotus-freelance + + + prf + application/pics-rules + + + ps + application/postscript + + + psb + application/vnd.3gpp.pic-bw-small + + + psd + image/vnd.adobe.photoshop + + + psf + application/x-font-linux-psf + + + pskcxml + application/pskc+xml + + + ptid + application/vnd.pvi.ptid1 + + + pub + application/x-mspublisher + + + pvb + application/vnd.3gpp.pic-bw-var + + + pwn + application/vnd.3m.post-it-notes + + + pya + audio/vnd.ms-playready.media.pya + + + pyv + video/vnd.ms-playready.media.pyv + + + qam + application/vnd.epson.quickanime + + + qbo + application/vnd.intu.qbo + + + qfx + application/vnd.intu.qfx + + + qps + application/vnd.publishare-delta-tree + + + qt + video/quicktime + + + qti + image/x-quicktime + + + qtif + image/x-quicktime + + + qwd + application/vnd.quark.quarkxpress + + + qwt + application/vnd.quark.quarkxpress + + + qxb + application/vnd.quark.quarkxpress + + + qxd + application/vnd.quark.quarkxpress + + + qxl + application/vnd.quark.quarkxpress + + + qxt + application/vnd.quark.quarkxpress + + + ra + audio/x-pn-realaudio + + + ram + audio/x-pn-realaudio + + + rar + application/x-rar-compressed + + + ras + image/x-cmu-raster + + + rcprofile + application/vnd.ipunplugged.rcprofile + + + rdf + application/rdf+xml + + + rdz + application/vnd.data-vision.rdz + + + rep + application/vnd.businessobjects + + + res + application/x-dtbresource+xml + + + rgb + image/x-rgb + + + rif + application/reginfo+xml + + + rip + audio/vnd.rip + + + ris + application/x-research-info-systems + + + rl + application/resource-lists+xml + + + rlc + image/vnd.fujixerox.edmics-rlc + + + rld + application/resource-lists-diff+xml + + + rm + application/vnd.rn-realmedia + + + rmi + audio/midi + + + rmp + audio/x-pn-realaudio-plugin + + + rms + application/vnd.jcp.javame.midlet-rms + + + rmvb + application/vnd.rn-realmedia-vbr + + + rnc + application/relax-ng-compact-syntax + + + roa + application/rpki-roa + + + roff + text/troff + + + rp9 + application/vnd.cloanto.rp9 + + + rpss + application/vnd.nokia.radio-presets + + + rpst + application/vnd.nokia.radio-preset + + + rq + application/sparql-query + + + rs + application/rls-services+xml + + + rsd + application/rsd+xml + + + rss + application/rss+xml + + + rtf + application/rtf + + + rtx + text/richtext + + + s + text/x-asm + + + s3m + audio/s3m + + + saf + application/vnd.yamaha.smaf-audio + + + sbml + application/sbml+xml + + + sc + application/vnd.ibm.secure-container + + + scd + application/x-msschedule + + + scm + application/vnd.lotus-screencam + + + scq + application/scvp-cv-request + + + scs + application/scvp-cv-response + + + scurl + text/vnd.curl.scurl + + + sda + application/vnd.stardivision.draw + + + sdc + application/vnd.stardivision.calc + + + sdd + application/vnd.stardivision.impress + + + sdkd + application/vnd.solent.sdkm+xml + + + sdkm + application/vnd.solent.sdkm+xml + + + sdp + application/sdp + + + sdw + application/vnd.stardivision.writer + + + see + application/vnd.seemail + + + seed + application/vnd.fdsn.seed + + + sema + application/vnd.sema + + + semd + application/vnd.semd + + + semf + application/vnd.semf + + + ser + application/java-serialized-object + + + setpay + application/set-payment-initiation + + + setreg + application/set-registration-initiation + + + sfd-hdstx + application/vnd.hydrostatix.sof-data + + + sfs + application/vnd.spotfire.sfs + + + sfv + text/x-sfv + + + sgi + image/sgi + + + sgl + application/vnd.stardivision.writer-global + + + sgm + text/sgml + + + sgml + text/sgml + + + sh + application/x-sh + + + shar + application/x-shar + + + shf + application/shf+xml + + + + sid + image/x-mrsid-image + + + sig + application/pgp-signature + + + sil + audio/silk + + + silo + model/mesh + + + sis + application/vnd.symbian.install + + + sisx + application/vnd.symbian.install + + + sit + application/x-stuffit + + + sitx + application/x-stuffitx + + + skd + application/vnd.koan + + + skm + application/vnd.koan + + + skp + application/vnd.koan + + + skt + application/vnd.koan + + + sldm + application/vnd.ms-powerpoint.slide.macroenabled.12 + + + sldx + application/vnd.openxmlformats-officedocument.presentationml.slide + + + slt + application/vnd.epson.salt + + + sm + application/vnd.stepmania.stepchart + + + smf + application/vnd.stardivision.math + + + smi + application/smil+xml + + + smil + application/smil+xml + + + smv + video/x-smv + + + smzip + application/vnd.stepmania.package + + + snd + audio/basic + + + snf + application/x-font-snf + + + so + application/octet-stream + + + spc + application/x-pkcs7-certificates + + + spf + application/vnd.yamaha.smaf-phrase + + + spl + application/x-futuresplash + + + spot + text/vnd.in3d.spot + + + spp + application/scvp-vp-response + + + spq + application/scvp-vp-request + + + spx + audio/ogg + + + sql + application/x-sql + + + src + application/x-wais-source + + + srt + application/x-subrip + + + sru + application/sru+xml + + + srx + application/sparql-results+xml + + + ssdl + application/ssdl+xml + + + sse + application/vnd.kodak-descriptor + + + ssf + application/vnd.epson.ssf + + + ssml + application/ssml+xml + + + st + application/vnd.sailingtracker.track + + + stc + application/vnd.sun.xml.calc.template + + + std + application/vnd.sun.xml.draw.template + + + stf + application/vnd.wt.stf + + + sti + application/vnd.sun.xml.impress.template + + + stk + application/hyperstudio + + + stl + application/vnd.ms-pki.stl + + + str + application/vnd.pg.format + + + stw + application/vnd.sun.xml.writer.template + + + sub + text/vnd.dvb.subtitle + + + sus + application/vnd.sus-calendar + + + susp + application/vnd.sus-calendar + + + sv4cpio + application/x-sv4cpio + + + sv4crc + application/x-sv4crc + + + svc + application/vnd.dvb.service + + + svd + application/vnd.svd + + + svg + image/svg+xml + + + svgz + image/svg+xml + + + swa + application/x-director + + + swf + application/x-shockwave-flash + + + swi + application/vnd.aristanetworks.swi + + + sxc + application/vnd.sun.xml.calc + + + sxd + application/vnd.sun.xml.draw + + + sxg + application/vnd.sun.xml.writer.global + + + sxi + application/vnd.sun.xml.impress + + + sxm + application/vnd.sun.xml.math + + + sxw + application/vnd.sun.xml.writer + + + t + text/troff + + + t3 + application/x-t3vm-image + + + taglet + application/vnd.mynfc + + + tao + application/vnd.tao.intent-module-archive + + + tar + application/x-tar + + + tcap + application/vnd.3gpp2.tcap + + + tcl + application/x-tcl + + + teacher + application/vnd.smart.teacher + + + tei + application/tei+xml + + + teicorpus + application/tei+xml + + + tex + application/x-tex + + + texi + application/x-texinfo + + + texinfo + application/x-texinfo + + + text + text/plain + + + tfi + application/thraud+xml + + + tfm + application/x-tex-tfm + + + tga + image/x-tga + + + thmx + application/vnd.ms-officetheme + + + tif + image/tiff + + + tiff + image/tiff + + + tmo + application/vnd.tmobile-livetv + + + torrent + application/x-bittorrent + + + tpl + application/vnd.groove-tool-template + + + tpt + application/vnd.trid.tpt + + + tr + text/troff + + + tra + application/vnd.trueapp + + + trm + application/x-msterminal + + + tsd + application/timestamped-data + + + tsv + text/tab-separated-values + + + ttc + application/x-font-ttf + + + ttf + application/x-font-ttf + + + ttl + text/turtle + + + twd + application/vnd.simtech-mindmapper + + + twds + application/vnd.simtech-mindmapper + + + txd + application/vnd.genomatix.tuxedo + + + txf + application/vnd.mobius.txf + + + txt + text/plain + + + u32 + application/x-authorware-bin + + + udeb + application/x-debian-package + + + ufd + application/vnd.ufdl + + + ufdl + application/vnd.ufdl + + + ulw + audio/basic + + + ulx + application/x-glulx + + + umj + application/vnd.umajin + + + unityweb + application/vnd.unity + + + uoml + application/vnd.uoml+xml + + + uri + text/uri-list + + + uris + text/uri-list + + + urls + text/uri-list + + + ustar + application/x-ustar + + + utz + application/vnd.uiq.theme + + + uu + text/x-uuencode + + + uva + audio/vnd.dece.audio + + + uvd + application/vnd.dece.data + + + uvf + application/vnd.dece.data + + + uvg + image/vnd.dece.graphic + + + uvh + video/vnd.dece.hd + + + uvi + image/vnd.dece.graphic + + + uvm + video/vnd.dece.mobile + + + uvp + video/vnd.dece.pd + + + uvs + video/vnd.dece.sd + + + uvt + application/vnd.dece.ttml+xml + + + uvu + video/vnd.uvvu.mp4 + + + uvv + video/vnd.dece.video + + + uvva + audio/vnd.dece.audio + + + uvvd + application/vnd.dece.data + + + uvvf + application/vnd.dece.data + + + uvvg + image/vnd.dece.graphic + + + uvvh + video/vnd.dece.hd + + + uvvi + image/vnd.dece.graphic + + + uvvm + video/vnd.dece.mobile + + + uvvp + video/vnd.dece.pd + + + uvvs + video/vnd.dece.sd + + + uvvt + application/vnd.dece.ttml+xml + + + uvvu + video/vnd.uvvu.mp4 + + + uvvv + video/vnd.dece.video + + + uvvx + application/vnd.dece.unspecified + + + uvvz + application/vnd.dece.zip + + + uvx + application/vnd.dece.unspecified + + + uvz + application/vnd.dece.zip + + + vcard + text/vcard + + + vcd + application/x-cdlink + + + vcf + text/x-vcard + + + vcg + application/vnd.groove-vcard + + + vcs + text/x-vcalendar + + + vcx + application/vnd.vcx + + + vis + application/vnd.visionary + + + viv + video/vnd.vivo + + + vob + video/x-ms-vob + + + vor + application/vnd.stardivision.writer + + + vox + application/x-authorware-bin + + + vrml + model/vrml + + + vsd + application/vnd.visio + + + vsf + application/vnd.vsf + + + vss + application/vnd.visio + + + vst + application/vnd.visio + + + vsw + application/vnd.visio + + + vtu + model/vnd.vtu + + + vxml + application/voicexml+xml + + + w3d + application/x-director + + + wad + application/x-doom + + + wav + audio/x-wav + + + wax + audio/x-ms-wax + + + + wbmp + image/vnd.wap.wbmp + + + wbs + application/vnd.criticaltools.wbs+xml + + + wbxml + application/vnd.wap.wbxml + + + wcm + application/vnd.ms-works + + + wdb + application/vnd.ms-works + + + wdp + image/vnd.ms-photo + + + weba + audio/webm + + + webm + video/webm + + + webp + image/webp + + + wg + application/vnd.pmi.widget + + + wgt + application/widget + + + wks + application/vnd.ms-works + + + wm + video/x-ms-wm + + + wma + audio/x-ms-wma + + + wmd + application/x-ms-wmd + + + wmf + application/x-msmetafile + + + + wml + text/vnd.wap.wml + + + + wmlc + application/vnd.wap.wmlc + + + + wmls + text/vnd.wap.wmlscript + + + + wmlsc + application/vnd.wap.wmlscriptc + + + wmv + video/x-ms-wmv + + + wmx + video/x-ms-wmx + + + wmz + application/x-msmetafile + + + woff + application/x-font-woff + + + wpd + application/vnd.wordperfect + + + wpl + application/vnd.ms-wpl + + + wps + application/vnd.ms-works + + + wqd + application/vnd.wqd + + + wri + application/x-mswrite + + + wrl + model/vrml + + + wsdl + application/wsdl+xml + + + wspolicy + application/wspolicy+xml + + + wtb + application/vnd.webturbo + + + wvx + video/x-ms-wvx + + + x32 + application/x-authorware-bin + + + x3d + model/x3d+xml + + + x3db + model/x3d+binary + + + x3dbz + model/x3d+binary + + + x3dv + model/x3d+vrml + + + x3dvz + model/x3d+vrml + + + x3dz + model/x3d+xml + + + xaml + application/xaml+xml + + + xap + application/x-silverlight-app + + + xar + application/vnd.xara + + + xbap + application/x-ms-xbap + + + xbd + application/vnd.fujixerox.docuworks.binder + + + xbm + image/x-xbitmap + + + xdf + application/xcap-diff+xml + + + xdm + application/vnd.syncml.dm+xml + + + xdp + application/vnd.adobe.xdp+xml + + + xdssc + application/dssc+xml + + + xdw + application/vnd.fujixerox.docuworks + + + xenc + application/xenc+xml + + + xer + application/patch-ops-error+xml + + + xfdf + application/vnd.adobe.xfdf + + + xfdl + application/vnd.xfdl + + + xht + application/xhtml+xml + + + xhtml + application/xhtml+xml + + + xhvml + application/xv+xml + + + xif + image/vnd.xiff + + + xla + application/vnd.ms-excel + + + xlam + application/vnd.ms-excel.addin.macroenabled.12 + + + xlc + application/vnd.ms-excel + + + xlf + application/x-xliff+xml + + + xlm + application/vnd.ms-excel + + + xls + application/vnd.ms-excel + + + xlsb + application/vnd.ms-excel.sheet.binary.macroenabled.12 + + + xlsm + application/vnd.ms-excel.sheet.macroenabled.12 + + + xlsx + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + + + xlt + application/vnd.ms-excel + + + xltm + application/vnd.ms-excel.template.macroenabled.12 + + + xltx + application/vnd.openxmlformats-officedocument.spreadsheetml.template + + + xlw + application/vnd.ms-excel + + + xm + audio/xm + + + xml + application/xml + + + xo + application/vnd.olpc-sugar + + + xop + application/xop+xml + + + xpi + application/x-xpinstall + + + xpl + application/xproc+xml + + + xpm + image/x-xpixmap + + + xpr + application/vnd.is-xpr + + + xps + application/vnd.ms-xpsdocument + + + xpw + application/vnd.intercon.formnet + + + xpx + application/vnd.intercon.formnet + + + xsl + application/xml + + + xslt + application/xslt+xml + + + xsm + application/vnd.syncml+xml + + + xspf + application/xspf+xml + + + xul + application/vnd.mozilla.xul+xml + + + xvm + application/xv+xml + + + xvml + application/xv+xml + + + xwd + image/x-xwindowdump + + + xyz + chemical/x-xyz + + + xz + application/x-xz + + + yang + application/yang + + + yin + application/yin+xml + + + z + application/x-compress + + + Z + application/x-compress + + + z1 + application/x-zmachine + + + z2 + application/x-zmachine + + + z3 + application/x-zmachine + + + z4 + application/x-zmachine + + + z5 + application/x-zmachine + + + z6 + application/x-zmachine + + + z7 + application/x-zmachine + + + z8 + application/x-zmachine + + + zaz + application/vnd.zzazz.deck+xml + + + zip + application/zip + + + zir + application/vnd.zul + + + zirz + application/vnd.zul + + + zmm + application/vnd.handheld-entertainment+xml + + + + + + + + + + + + + + + + + + index.html + index.htm + index.jsp + + + diff --git a/tomcat9-maven-plugin/src/site/apt/adjust-embedded-tomcat-version.apt.vm b/tomcat9-maven-plugin/src/site/apt/adjust-embedded-tomcat-version.apt.vm new file mode 100644 index 00000000..01f7d5d0 --- /dev/null +++ b/tomcat9-maven-plugin/src/site/apt/adjust-embedded-tomcat-version.apt.vm @@ -0,0 +1,162 @@ + --- + Adjust Tomcat Version + --- + Olivier Lamy + --- + 2012-04-11 + --- + + ~~ Licensed to the Apache Software Foundation (ASF) under one + ~~ or more contributor license agreements. See the NOTICE file + ~~ distributed with this work for additional information + ~~ regarding copyright ownership. The ASF licenses this file + ~~ to you under the Apache License, Version 2.0 (the + ~~ "License"); you may not use this file except in compliance + ~~ with the License. You may obtain a copy of the License at + ~~ + ~~ http://www.apache.org/licenses/LICENSE-2.0 + ~~ + ~~ Unless required by applicable law or agreed to in writing, + ~~ software distributed under the License is distributed on an + ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~~ KIND, either express or implied. See the License for the + ~~ specific language governing permissions and limitations + ~~ under the License. + + ~~ NOTE: For help with the syntax of this file, see: + ~~ http://maven.apache.org/doxia/references/apt-format.html + +Adjust Tomcat Version + + In case you need to adjust the version of the embedded tomcat to run you can do so by changing + the runtime-dependencies: + ++-- + + [...] + + 9.0.0 + [...] + + [...] + + + + + org.apache.tomcat.maven + tomcat9-maven-plugin + ${project.version} + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + org.apache.tomcat + tomcat-util + ${tomcat.version} + + + org.apache.tomcat + tomcat-coyote + ${tomcat.version} + + + org.apache.tomcat + tomcat-api + ${tomcat.version} + + + + org.apache.tomcat + tomcat-jdbc + ${tomcat.version} + + + + org.apache.tomcat + tomcat-dbcp + ${tomcat.version} + + + + org.apache.tomcat + tomcat-servlet-api + ${tomcat.version} + + + + org.apache.tomcat + tomcat-jsp-api + ${tomcat.version} + + + + org.apache.tomcat + tomcat-jasper + ${tomcat.version} + + + + org.apache.tomcat + tomcat-jasper-el + ${tomcat.version} + + + + org.apache.tomcat + tomcat-el-api + ${tomcat.version} + + + + org.apache.tomcat + tomcat-catalina + ${tomcat.version} + + + + org.apache.tomcat + tomcat-tribes + ${tomcat.version} + + + + org.apache.tomcat + tomcat-catalina-ha + ${tomcat.version} + + + + org.apache.tomcat + tomcat-annotations-api + ${tomcat.version} + + + + org.apache.tomcat + tomcat-juli + ${tomcat.version} + + + + org.apache.tomcat.embed + tomcat-embed-logging-juli + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-logging-log4j + ${tomcat.version} + + + + [...] + + + [...] + + [...] + ++-- diff --git a/tomcat9-maven-plugin/src/site/apt/index.apt b/tomcat9-maven-plugin/src/site/apt/index.apt new file mode 100644 index 00000000..476f1b67 --- /dev/null +++ b/tomcat9-maven-plugin/src/site/apt/index.apt @@ -0,0 +1,39 @@ + --- + Introduction + --- + Olivier Lamy + --- + 2012-02-03 + --- + + ~~ Licensed to the Apache Software Foundation (ASF) under one + ~~ or more contributor license agreements. See the NOTICE file + ~~ distributed with this work for additional information + ~~ regarding copyright ownership. The ASF licenses this file + ~~ to you under the Apache License, Version 2.0 (the + ~~ "License"); you may not use this file except in compliance + ~~ with the License. You may obtain a copy of the License at + ~~ + ~~ http://www.apache.org/licenses/LICENSE-2.0 + ~~ + ~~ Unless required by applicable law or agreed to in writing, + ~~ software distributed under the License is distributed on an + ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~~ KIND, either express or implied. See the License for the + ~~ specific language governing permissions and limitations + ~~ under the License. + + ~~ NOTE: For help with the syntax of this file, see: + ~~ http://maven.apache.org/doxia/references/apt-format.html + +Tomcat Maven Plugin + + The Tomcat9 Maven Plugin provides goals to manipulate WAR projects within the {{{http://tomcat.apache.org/}Tomcat}} servlet container version 9.x + +* Goals Overview + + The goals for this plugin are available here {{{./plugin-info.html}goals page}}. + +* Usage + + Instructions on how to use the Tomcat Maven Plugin can be found on the {{{./usage.html}usage page}}. diff --git a/tomcat9-maven-plugin/src/site/apt/usage.apt.vm b/tomcat9-maven-plugin/src/site/apt/usage.apt.vm new file mode 100644 index 00000000..89201bde --- /dev/null +++ b/tomcat9-maven-plugin/src/site/apt/usage.apt.vm @@ -0,0 +1,182 @@ + --- + Usage + --- + Olivier Lamy + --- + 2012-02-03 + --- + + ~~ Licensed to the Apache Software Foundation (ASF) under one + ~~ or more contributor license agreements. See the NOTICE file + ~~ distributed with this work for additional information + ~~ regarding copyright ownership. The ASF licenses this file + ~~ to you under the Apache License, Version 2.0 (the + ~~ "License"); you may not use this file except in compliance + ~~ with the License. You may obtain a copy of the License at + ~~ + ~~ http://www.apache.org/licenses/LICENSE-2.0 + ~~ + ~~ Unless required by applicable law or agreed to in writing, + ~~ software distributed under the License is distributed on an + ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~~ KIND, either express or implied. See the License for the + ~~ specific language governing permissions and limitations + ~~ under the License. + + ~~ NOTE: For help with the syntax of this file, see: + ~~ http://maven.apache.org/doxia/references/apt-format.html + +Usage + + If no explicit configuration is provided then the Tomcat9 Maven Plugin defaults to + the following: + + * Tomcat manager URL of <<>> + + * Authentication details of username <<>> and no password + + * Context path of <<>> + + [] + + These can be overridden as described below. + +* Using a different Tomcat manager URL + + To configure the plugin for a different Tomcat instance, add a plugin + configuration block to your <<>> as follows: + ++-- + + ... + + ... + + ... + + org.apache.tomcat.maven + tomcat9-maven-plugin + ${project.version} + + http://www.mydomain.com:1234/mymanager + + + ... + + ... + + ... + ++-- + + The default Tomcat manager URL is <<>>. + +* Using different Tomcat manager authentication details + + To specify a different username and password to use when authenticating with + Tomcat manager: + + [[1]] Add a plugin configuration block to your <<>>: + ++-- + + ... + + ... + + ... + + org.apache.tomcat.maven + tomcat9-maven-plugin + ${project.version} + + myserver + + + ... + + ... + + ... + ++-- + + [[2]] Add a corresponding <<>> block to your <<>>: + ++-- + + ... + + ... + + myserver + myusername + mypassword + + ... + + ... + ++-- + + [] + + The default authentication details are username <<>> and no password. + +* Using a different context path + + The default context path is <<>>. + + To change the context path to <<>> configure the plugin like this: + ++-- + + ... + + ... + + ... + + org.apache.tomcat.maven + tomcat9-maven-plugin + ${project.version} + + /mycontext + + + ... + + ... + + ... + ++-- + + If you are using <<>> to change the name of your WAR + file, you can use that value when you configure the context path as well. To do + that add the following configuration block to your <<>>: + ++-- + + ... + + ... + mycontext + ... + + ... + + org.apache.tomcat.maven + tomcat9-maven-plugin + ${project.version} + + /\${project.build.finalName} + + + ... + + ... + + ... + ++-- diff --git a/tomcat9-maven-plugin/src/site/site.xml b/tomcat9-maven-plugin/src/site/site.xml new file mode 100644 index 00000000..257830fb --- /dev/null +++ b/tomcat9-maven-plugin/src/site/site.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9DeployWarOnlyProjectIT.java b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9DeployWarOnlyProjectIT.java new file mode 100644 index 00000000..ddb6d9ce --- /dev/null +++ b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9DeployWarOnlyProjectIT.java @@ -0,0 +1,31 @@ +package org.apache.tomcat.maven.it; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.tomcat.maven.it.AbstractDeployWarOnlyProjectIT; + +/** + * @author Olivier Lamy + */ +public class Tomcat9DeployWarOnlyProjectIT + extends AbstractDeployWarOnlyProjectIT +{ + // no op + +} diff --git a/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9DeployWarProjectIT.java b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9DeployWarProjectIT.java new file mode 100644 index 00000000..cc20ce32 --- /dev/null +++ b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9DeployWarProjectIT.java @@ -0,0 +1,30 @@ +package org.apache.tomcat.maven.it; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.tomcat.maven.it.AbstractDeployWarProjectIT; + +/** + * @author Olivier Lamy + */ +public class Tomcat9DeployWarProjectIT + extends AbstractDeployWarProjectIT +{ + // no op +} diff --git a/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9RunMultiConfigIT.java b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9RunMultiConfigIT.java new file mode 100644 index 00000000..3ea09075 --- /dev/null +++ b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9RunMultiConfigIT.java @@ -0,0 +1,37 @@ +package org.apache.tomcat.maven.it; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.it.VerificationException; + +/** + * @author Olivier Lamy + */ +public class Tomcat9RunMultiConfigIT + extends AbstractTomcatRunMultiConfigIT +{ + @Override + protected void verifyConnectorsStarted() + throws VerificationException + { + verifier.verifyTextInLog("INFO: Starting ProtocolHandler [\"http-nio-" + getHttpItPort() + "\"]"); + verifier.verifyTextInLog("INFO: Starting ProtocolHandler [\"http-nio-" + getHttpsItPort() + "\"]"); + verifier.verifyTextInLog("INFO: Starting ProtocolHandler [\"ajp-bio-" + getAjpItPort() + "\"]"); + } +} diff --git a/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9SimpleWarProjectIT.java b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9SimpleWarProjectIT.java new file mode 100644 index 00000000..7efab2ca --- /dev/null +++ b/tomcat9-maven-plugin/src/test/java/org/apache/tomcat/maven/it/Tomcat9SimpleWarProjectIT.java @@ -0,0 +1,43 @@ +package org.apache.tomcat.maven.it; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.it.VerificationException; + +/** + * @author Olivier Lamy + */ +public class Tomcat9SimpleWarProjectIT + extends AbstractSimpleWarProjectIT +{ + @Override + protected int getTimeout() + { + return 20000; + } + + @Override + protected void verifyConnectorsStarted() + throws VerificationException + { + verifier.verifyTextInLog("INFO: Starting ProtocolHandler [\"http-nio-" + getHttpItPort() + "\"]"); + + verifier.verifyTextInLog( "INFO: Starting ProtocolHandler [\"ajp-bio-"+ getAjpItPort() +"\"]" ); + } +} diff --git a/tomcat9-maven-plugin/src/test/keystore b/tomcat9-maven-plugin/src/test/keystore new file mode 100644 index 00000000..016d5964 Binary files /dev/null and b/tomcat9-maven-plugin/src/test/keystore differ diff --git a/tomcat9-maven-plugin/src/test/manager.war b/tomcat9-maven-plugin/src/test/manager.war new file mode 100644 index 00000000..065cd9d8 Binary files /dev/null and b/tomcat9-maven-plugin/src/test/manager.war differ diff --git a/tomcat9-maven-plugin/src/test/resources/log4j2-test.xml b/tomcat9-maven-plugin/src/test/resources/log4j2-test.xml new file mode 100644 index 00000000..eef73d8a --- /dev/null +++ b/tomcat9-maven-plugin/src/test/resources/log4j2-test.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tomcat9-maven-plugin/src/test/simple-war-project-1.0-SNAPSHOT.war b/tomcat9-maven-plugin/src/test/simple-war-project-1.0-SNAPSHOT.war new file mode 100644 index 00000000..b0315c91 Binary files /dev/null and b/tomcat9-maven-plugin/src/test/simple-war-project-1.0-SNAPSHOT.war differ diff --git a/tomcat9-war-runner/NOTES.TXT b/tomcat9-war-runner/NOTES.TXT new file mode 100644 index 00000000..20eeb881 --- /dev/null +++ b/tomcat9-war-runner/NOTES.TXT @@ -0,0 +1,39 @@ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, + ~ software distributed under the License is distributed on an + ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~ KIND, either express or implied. See the License for the + ~ specific language governing permissions and limitations + ~ under the License. + +The generated standalone jar will contains: +* wars in the root: foo.war +* tomcat classes in jar +* file tomcat.standalone.properties with possible values : + * useServerXml=true/false to use directly the one provided + in the maven plugin configuration + * wars=foo.war|contextpath;bar.war ( |contextpath is optionnal if empty use the war name) + * enableNaming=true/false + * accessLogValveFormat= + * connectorhttpProtocol: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol + +* optionnal: conf/ with usual tomcat configuration files + +On start: +1. create a .extract directory with all the tomcat configuration +2. check if -serverXml is set: if yes use it + 2.1. check in tomcat.standalone.properties if useServerXml=true + if use extract it to .extract/conf and use it with + other files located in /conf (except if .extract already here ) + 2.2. if not use data from cli: -httpPort, -httpsPort, -ajpPort +3. now extract wars to .extract/webapps/ (except if .extract already here ) +4. start Tomcat embded with necessary configuration and add webapps. diff --git a/tomcat9-war-runner/pom.xml b/tomcat9-war-runner/pom.xml new file mode 100644 index 00000000..9bb24073 --- /dev/null +++ b/tomcat9-war-runner/pom.xml @@ -0,0 +1,137 @@ + + + + + 4.0.0 + + tomcat-maven-plugin + org.apache.tomcat.maven + 3.0-SNAPSHOT + + tomcat9-war-runner + 3.0-SNAPSHOT + Apache Tomcat Maven Plugin :: Tomcat 9.x War Runner + + + 9.0.96 + + + + + commons-cli + commons-cli + + + + + org.eclipse.jdt.core.compiler + ecj + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat9Version} + + + org.apache.tomcat + tomcat-util + ${tomcat9Version} + + + org.apache.tomcat + tomcat-coyote + ${tomcat9Version} + + + org.apache.tomcat + tomcat-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jdbc + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-dbcp + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-servlet-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jsp-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jasper + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-jasper-el + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-el-api + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-catalina + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-tribes + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-catalina-ha + ${tomcat9Version} + + + + org.apache.tomcat + tomcat-annotations-api + ${tomcat9Version} + + + + + diff --git a/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/PasswordUtil.java b/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/PasswordUtil.java new file mode 100644 index 00000000..15d8af0a --- /dev/null +++ b/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/PasswordUtil.java @@ -0,0 +1,131 @@ +package org.apache.tomcat.maven.runner; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Properties; + + +/** + * Password obfuscate utility class. Lifted from Jetty org.mortbay.jetty.security.Password + *

+ *

+ * Passwords that begin with OBF: are de obfuscated. + *

+ * Passwords can be obfuscated by running Obfuscate as a main class. Obfuscated password are required if a system needs + * to recover the full password (eg. so that it may be passed to another system). + *

+ * They are not secure, but prevent casual observation. + * + * @see Jetty Source org.mortbay.jetty.security.Password + * @since 2.0 + */ +public class PasswordUtil +{ + public static final String __OBFUSCATE = "OBF:"; + + /* ------------------------------------------------------------ */ + public static String obfuscate( String s ) + { + StringBuilder buf = new StringBuilder(); + byte[] b = s.getBytes(); + + buf.append( __OBFUSCATE ); + for ( int i = 0; i < b.length; i++ ) + { + byte b1 = b[i]; + byte b2 = b[s.length() - ( i + 1 )]; + int i1 = 127 + b1 + b2; + int i2 = 127 + b1 - b2; + int i0 = i1 * 256 + i2; + String x = Integer.toString( i0, 36 ); + + switch ( x.length() ) + { + case 1: + buf.append( '0' ); + case 2: + buf.append( '0' ); + case 3: + buf.append( '0' ); + default: + buf.append( x ); + } + } + return buf.toString(); + + } + + /* ------------------------------------------------------------ */ + public static String deobfuscate( String s ) + { + if ( s.startsWith( __OBFUSCATE ) ) + { + s = s.substring( __OBFUSCATE.length() ); + + byte[] b = new byte[s.length() / 2]; + int l = 0; + for ( int i = 0; i < s.length(); i += 4 ) + { + String x = s.substring( i, i + 4 ); + int i0 = Integer.parseInt( x, 36 ); + int i1 = ( i0 / 256 ); + int i2 = ( i0 % 256 ); + b[l++] = (byte) ( ( i1 + i2 - 254 ) / 2 ); + } + return new String( b, 0, l ); + } + else + { + return s; + } + + } + + public static void deobfuscateSystemProps() + { + Properties props = System.getProperties(); + for ( Object obj : props.keySet() ) + { + if ( obj instanceof String ) + { + String key = (String) obj; + String value = (String) props.getProperty( key ); + if ( value != null && value.startsWith( __OBFUSCATE ) ) + { + System.setProperty( key, deobfuscate( value ) ); + } + } + } + } + + public static void main( String[] args ) + { + if ( args[0].startsWith( __OBFUSCATE ) ) + { + System.out.println( PasswordUtil.deobfuscate( args[1] ) ); + } + else + { + System.out.println( PasswordUtil.obfuscate( args[1] ) ); + } + } +} diff --git a/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/Tomcat9Runner.java b/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/Tomcat9Runner.java new file mode 100644 index 00000000..293ce0d3 --- /dev/null +++ b/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/Tomcat9Runner.java @@ -0,0 +1,825 @@ +package org.apache.tomcat.maven.runner; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.catalina.Context; +import org.apache.catalina.Host; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.startup.Catalina; +import org.apache.catalina.startup.ContextConfig; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.valves.AccessLogValve; +import org.apache.juli.ClassLoaderLogManager; +import org.apache.tomcat.util.ExceptionUtils; +import org.apache.tomcat.util.http.fileupload.FileUtils; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.logging.LogManager; + +/** + * FIXME add junit for that but when https://issues.apache.org/bugzilla/show_bug.cgi?id=52028 fixed + * Main class used to run the standalone wars in a Apache Tomcat instance. + * + * @author Olivier Lamy + * @since 2.0 + */ +public class Tomcat9Runner +{ + // true/false to use the server.xml located in the jar /conf/server.xml + public static final String USE_SERVER_XML_KEY = "useServerXml"; + + // contains war name wars=foo.war,bar.war + public static final String WARS_KEY = "wars"; + + public static final String ARCHIVE_GENERATION_TIMESTAMP_KEY = "generationTimestamp"; + + public static final String ENABLE_NAMING_KEY = "enableNaming"; + + public static final String ACCESS_LOG_VALVE_FORMAT_KEY = "accessLogValveFormat"; + + public static final String CODE_SOURCE_CONTEXT_PATH = "codeSourceContextPath"; + + /** + * key of the property which contains http protocol : HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol + */ + public static final String HTTP_PROTOCOL_KEY = "connectorhttpProtocol"; + + /** + * key for default http port defined in the plugin + */ + public static final String HTTP_PORT_KEY = "httpPort"; + + + public int httpPort; + + public int httpsPort; + + public int maxPostSize = 2097152; + + public int ajpPort; + + public String serverXmlPath; + + public Properties runtimeProperties; + + public boolean resetExtract; + + public boolean debug = false; + + public String clientAuth = "false"; + + public String keyAlias = null; + + public String httpProtocol; + + public String extractDirectory = ".extract"; + + public File extractDirectoryFile; + + public String codeSourceContextPath = null; + + public File codeSourceWar = null; + + public String loggerName; + + Catalina container; + + Tomcat tomcat; + + String uriEncoding = "ISO-8859-1"; + + /** + * key = context of the webapp, value = war path on file system + */ + Map webappWarPerContext = new HashMap(); + + public Tomcat9Runner() + { + // no op + } + + public void run() + throws Exception + { + + PasswordUtil.deobfuscateSystemProps(); + + if ( loggerName != null && loggerName.length() > 0 ) + { + installLogger( loggerName ); + } + + this.extractDirectoryFile = new File( this.extractDirectory ); + + debugMessage( "use extractDirectory:" + extractDirectoryFile.getPath() ); + + boolean archiveTimestampChanged = false; + + // compare timestamp stored during previous run if exists + File timestampFile = new File( extractDirectoryFile, ".tomcat_executable_archive.timestamp" ); + + Properties timestampProps = loadProperties( timestampFile ); + + if ( timestampFile.exists() ) + { + String timestampValue = timestampProps.getProperty(Tomcat9Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY ); + if ( timestampValue != null ) + { + long timestamp = Long.parseLong( timestampValue ); + archiveTimestampChanged = + Long.parseLong(runtimeProperties.getProperty(Tomcat9Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY ) ) + > timestamp; + + debugMessage( "read timestamp from file " + timestampValue + ", archiveTimestampChanged: " + + archiveTimestampChanged ); + } + + } + + codeSourceContextPath = runtimeProperties.getProperty( CODE_SOURCE_CONTEXT_PATH ); + if ( codeSourceContextPath != null && !codeSourceContextPath.isEmpty() ) + { + codeSourceWar = AccessController.doPrivileged(new PrivilegedAction() + { + public File run() + { + try + { + File src = + new File( Tomcat9Runner.class.getProtectionDomain().getCodeSource().getLocation().toURI() ); + if ( src.getName().endsWith( ".war" ) ) + { + return src; + } + else + { + debugMessage( "ERROR: Code source is not a war file, ignoring." ); + } + } + catch ( URISyntaxException e ) + { + debugMessage( "ERROR: Could not find code source. " + e.getMessage() ); + + } + return null; + } + } ); + } + + // do we have to extract content + { + if ( !extractDirectoryFile.exists() || resetExtract || archiveTimestampChanged ) + { + extract(); + //if archiveTimestampChanged or timestamp file not exists store the last timestamp from the archive + if ( archiveTimestampChanged || !timestampFile.exists() ) + { + timestampProps.put(Tomcat9Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY, runtimeProperties.getProperty(Tomcat9Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY ) ); + saveProperties( timestampProps, timestampFile ); + } + } + else + { + String wars = runtimeProperties.getProperty( WARS_KEY ); + populateWebAppWarPerContext( wars ); + } + } + + // create tomcat various paths + new File( extractDirectory, "conf" ).mkdirs(); + new File( extractDirectory, "logs" ).mkdirs(); + new File( extractDirectory, "webapps" ).mkdirs(); + new File( extractDirectory, "work" ).mkdirs(); + File tmpDir = new File( extractDirectory, "temp" ); + tmpDir.mkdirs(); + + System.setProperty( "java.io.tmpdir", tmpDir.getAbsolutePath() ); + + System.setProperty( "catalina.base", extractDirectoryFile.getAbsolutePath() ); + System.setProperty( "catalina.home", extractDirectoryFile.getAbsolutePath() ); + + // start with a server.xml + if ( serverXmlPath != null || useServerXml() ) + { + container = new Catalina(); + container.setUseNaming( this.enableNaming() ); + if ( serverXmlPath != null && new File( serverXmlPath ).exists() ) + { + container.setConfigFile( serverXmlPath ); + } + else + { + container.setConfigFile( new File( extractDirectory, "conf/server.xml" ).getAbsolutePath() ); + } + container.start(); + } + else + { + tomcat = new Tomcat() + { + public Context addWebapp( Host host, String url, String name, String path ) + { + + Context ctx = new StandardContext(); + ctx.setName( name ); + ctx.setPath( url ); + ctx.setDocBase( path ); + + ContextConfig ctxCfg = new ContextConfig(); + ctx.addLifecycleListener( ctxCfg ); + + ctxCfg.setDefaultWebXml( new File( extractDirectory, "conf/web.xml" ).getAbsolutePath() ); + + if ( host == null ) + { + getHost().addChild( ctx ); + } + else + { + host.addChild( ctx ); + } + + return ctx; + } + }; + + if ( this.enableNaming() ) + { + System.setProperty( "catalina.useNaming", "true" ); + tomcat.enableNaming(); + } + + tomcat.getHost().setAppBase( new File( extractDirectory, "webapps" ).getAbsolutePath() ); + + String connectorHttpProtocol = runtimeProperties.getProperty( HTTP_PROTOCOL_KEY ); + + if ( httpProtocol != null && httpProtocol.trim().length() > 0 ) + { + connectorHttpProtocol = httpProtocol; + } + + debugMessage( "use connectorHttpProtocol:" + connectorHttpProtocol ); + + if ( httpPort > 0 ) + { + Connector connector = new Connector( connectorHttpProtocol ); + connector.setPort( httpPort ); + connector.setMaxPostSize( maxPostSize ); + + if ( httpsPort > 0 ) + { + connector.setRedirectPort( httpsPort ); + } + connector.setURIEncoding( uriEncoding ); + + tomcat.getService().addConnector( connector ); + + tomcat.setConnector( connector ); + } + + // add a default acces log valve + AccessLogValve alv = new AccessLogValve(); + alv.setDirectory( new File( extractDirectory, "logs" ).getAbsolutePath() ); + alv.setPattern(runtimeProperties.getProperty(Tomcat9Runner.ACCESS_LOG_VALVE_FORMAT_KEY ) ); + tomcat.getHost().getPipeline().addValve( alv ); + + // create https connector + if ( httpsPort > 0 ) + { + Connector httpsConnector = new Connector( connectorHttpProtocol ); + httpsConnector.setPort( httpsPort ); + httpsConnector.setMaxPostSize( maxPostSize ); + httpsConnector.setSecure( true ); + httpsConnector.setProperty( "SSLEnabled", "true" ); + httpsConnector.setProperty( "sslProtocol", "TLS" ); + httpsConnector.setURIEncoding( uriEncoding ); + + String keystoreFile = System.getProperty( "javax.net.ssl.keyStore" ); + String keystorePass = System.getProperty( "javax.net.ssl.keyStorePassword" ); + String keystoreType = System.getProperty( "javax.net.ssl.keyStoreType", "jks" ); + + if ( keystoreFile != null ) + { + httpsConnector.setAttribute( "keystoreFile", keystoreFile ); + } + if ( keystorePass != null ) + { + httpsConnector.setAttribute( "keystorePass", keystorePass ); + } + httpsConnector.setAttribute( "keystoreType", keystoreType ); + + String truststoreFile = System.getProperty( "javax.net.ssl.trustStore" ); + String truststorePass = System.getProperty( "javax.net.ssl.trustStorePassword" ); + String truststoreType = System.getProperty( "javax.net.ssl.trustStoreType", "jks" ); + if ( truststoreFile != null ) + { + httpsConnector.setAttribute( "truststoreFile", truststoreFile ); + } + if ( truststorePass != null ) + { + httpsConnector.setAttribute( "truststorePass", truststorePass ); + } + httpsConnector.setAttribute( "truststoreType", truststoreType ); + + httpsConnector.setAttribute( "clientAuth", clientAuth ); + httpsConnector.setAttribute( "keyAlias", keyAlias ); + + tomcat.getService().addConnector( httpsConnector ); + + if ( httpPort <= 0 ) + { + tomcat.setConnector( httpsConnector ); + } + } + + // create ajp connector + if ( ajpPort > 0 ) + { + Connector ajpConnector = new Connector( "org.apache.coyote.ajp.AjpProtocol" ); + ajpConnector.setPort( ajpPort ); + ajpConnector.setURIEncoding( uriEncoding ); + tomcat.getService().addConnector( ajpConnector ); + } + + // add webapps + for ( Map.Entry entry : this.webappWarPerContext.entrySet() ) + { + String baseDir = null; + Context context = null; + if ( entry.getKey().equals( "/" ) ) + { + baseDir = new File( extractDirectory, "webapps/ROOT.war" ).getAbsolutePath(); + context = tomcat.addWebapp( "", baseDir ); + } + else + { + baseDir = new File( extractDirectory, "webapps/" + entry.getValue() ).getAbsolutePath(); + context = tomcat.addWebapp( entry.getKey(), baseDir ); + } + + URL contextFileUrl = getContextXml( baseDir ); + if ( contextFileUrl != null ) + { + context.setConfigFile( contextFileUrl ); + } + } + + if ( codeSourceWar != null ) + { + String baseDir = new File( extractDirectory, "webapps/" + codeSourceWar.getName() ).getAbsolutePath(); + Context context = tomcat.addWebapp( codeSourceContextPath, baseDir ); + URL contextFileUrl = getContextXml( baseDir ); + if ( contextFileUrl != null ) + { + context.setConfigFile( contextFileUrl ); + } + } + + tomcat.start(); + + Runtime.getRuntime().addShutdownHook( new TomcatShutdownHook() ); + + } + + waitIndefinitely(); + + } + + protected class TomcatShutdownHook + extends Thread + { + + protected TomcatShutdownHook() + { + // no op + } + + @Override + public void run() + { + try + { + Tomcat9Runner.this.stop(); + } + catch ( Throwable ex ) + { + ExceptionUtils.handleThrowable( ex ); + System.out.println( "fail to properly shutdown Tomcat:" + ex.getMessage() ); + } + finally + { + // If JULI is used, shut JULI down *after* the server shuts down + // so log messages aren't lost + LogManager logManager = LogManager.getLogManager(); + if ( logManager instanceof ClassLoaderLogManager ) + { + ( (ClassLoaderLogManager) logManager ).shutdown(); + } + } + } + } + + private URL getContextXml( String warPath ) + throws IOException + { + InputStream inputStream = null; + try + { + String urlStr = "jar:file:" + warPath + "!/META-INF/context.xml"; + debugMessage( "search context.xml in url:'" + urlStr + "'" ); + URL url = new URL( urlStr ); + inputStream = url.openConnection().getInputStream(); + if ( inputStream != null ) + { + return url; + } + } + catch ( FileNotFoundException e ) + { + return null; + } + finally + { + closeQuietly( inputStream ); + } + return null; + } + + private static void closeQuietly( InputStream inputStream ) + { + if ( inputStream == null ) + { + return; + } + try + { + inputStream.close(); + } + catch ( IOException e ) + { + // ignore exception here + } + } + + private void waitIndefinitely() + { + Object lock = new Object(); + + synchronized ( lock ) + { + try + { + lock.wait(); + } + catch ( InterruptedException exception ) + { + throw new Error( "InterruptedException on wait Indefinitely lock:" + exception.getMessage(), + exception ); + } + } + } + + public void stop() + throws Exception + { + if ( container != null ) + { + container.stop(); + } + if ( tomcat != null ) + { + tomcat.stop(); + } + } + + protected void extract() + throws Exception + { + + if ( extractDirectoryFile.exists() ) + { + debugMessage( "delete extractDirectory:" + extractDirectoryFile.getAbsolutePath() ); + FileUtils.deleteDirectory( extractDirectoryFile ); + } + + if ( !this.extractDirectoryFile.exists() ) + { + boolean created = this.extractDirectoryFile.mkdirs(); + if ( !created ) + { + throw new Exception( "FATAL: impossible to create directory:" + this.extractDirectoryFile.getPath() ); + } + } + + // ensure webapp dir is here + boolean created = new File( extractDirectory, "webapps" ).mkdirs(); + if ( !created ) + { + throw new Exception( + "FATAL: impossible to create directory:" + this.extractDirectoryFile.getPath() + "/webapps" ); + + } + + String wars = runtimeProperties.getProperty( WARS_KEY ); + populateWebAppWarPerContext( wars ); + + for ( Map.Entry entry : webappWarPerContext.entrySet() ) + { + debugMessage( "webappWarPerContext entry key/value: " + entry.getKey() + "/" + entry.getValue() ); + InputStream inputStream = null; + try + { + File expandFile = null; + inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( entry.getValue() ); + if ( !useServerXml() ) + { + if ( entry.getKey().equals( "/" ) ) + { + expandFile = new File( extractDirectory, "webapps/ROOT.war" ); + } + else + { + expandFile = new File( extractDirectory, "webapps/" + entry.getValue() ); + } + } + else + { + expandFile = new File( extractDirectory, "webapps/" + entry.getValue() ); + } + + debugMessage( "expand to file:" + expandFile.getPath() ); + + // MTOMCAT-211 ensure parent directories created + File parentFile = expandFile.getParentFile(); + if ( !parentFile.mkdirs() && !parentFile.isDirectory() ) + { + throw new Exception( "FATAL: impossible to create directories:" + parentFile ); + } + + expand( inputStream, expandFile ); + + } + finally + { + if ( inputStream != null ) + { + inputStream.close(); + } + } + } + + //Copy code source to webapps folder + if ( codeSourceWar != null ) + { + FileInputStream inputStream = null; + try + { + File expandFile = new File( extractDirectory, "webapps/" + codeSourceContextPath + ".war" ); + inputStream = new FileInputStream( codeSourceWar ); + debugMessage( "move code source to file:" + expandFile.getPath() ); + expand( inputStream, expandFile ); + } + finally + { + if ( inputStream != null ) + { + inputStream.close(); + } + } + } + + // expand tomcat configuration files if there + expandConfigurationFile( "catalina.properties", extractDirectoryFile ); + expandConfigurationFile( "logging.properties", extractDirectoryFile ); + expandConfigurationFile( "tomcat-users.xml", extractDirectoryFile ); + expandConfigurationFile( "catalina.policy", extractDirectoryFile ); + expandConfigurationFile( "context.xml", extractDirectoryFile ); + expandConfigurationFile( "server.xml", extractDirectoryFile ); + expandConfigurationFile( "web.xml", extractDirectoryFile ); + + } + + private static void expandConfigurationFile( String fileName, File extractDirectory ) + throws Exception + { + InputStream inputStream = null; + try + { + inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( "conf/" + fileName ); + if ( inputStream != null ) + { + File confDirectory = new File( extractDirectory, "conf" ); + if ( !confDirectory.exists() ) + { + confDirectory.mkdirs(); + } + expand( inputStream, new File( confDirectory, fileName ) ); + } + } + finally + { + if ( inputStream != null ) + { + inputStream.close(); + } + } + + } + + /** + * @param warsValue we can value in format: wars=foo.war|contextpath;bar.war ( |contextpath is optionnal if empty use the war name) + * so here we return war file name and populate webappWarPerContext + */ + private void populateWebAppWarPerContext( String warsValue ) + { + if ( warsValue == null ) + { + return; + } + + StringTokenizer st = new StringTokenizer( warsValue, ";" ); + while ( st.hasMoreTokens() ) + { + String warValue = st.nextToken(); + debugMessage( "populateWebAppWarPerContext warValue:" + warValue ); + String warFileName = ""; + String contextValue = ""; + int separatorIndex = warValue.indexOf( "|" ); + if ( separatorIndex >= 0 ) + { + warFileName = warValue.substring( 0, separatorIndex ); + contextValue = warValue.substring( separatorIndex + 1, warValue.length() ); + + } + else + { + warFileName = contextValue; + } + debugMessage( "populateWebAppWarPerContext contextValue/warFileName:" + contextValue + "/" + warFileName ); + this.webappWarPerContext.put( contextValue, warFileName ); + } + } + + + /** + * Expand the specified input stream into the specified file. + * + * @param input InputStream to be copied + * @param file The file to be created + * @throws java.io.IOException if an input/output error occurs + */ + private static void expand( InputStream input, File file ) + throws IOException + { + BufferedOutputStream output = null; + try + { + output = new BufferedOutputStream( new FileOutputStream( file ) ); + byte buffer[] = new byte[2048]; + while ( true ) + { + int n = input.read( buffer ); + if ( n <= 0 ) + { + break; + } + output.write( buffer, 0, n ); + } + } + finally + { + if ( output != null ) + { + try + { + output.close(); + } + catch ( IOException e ) + { + // Ignore + } + } + } + } + + public boolean useServerXml() + { + return Boolean.parseBoolean( runtimeProperties.getProperty( USE_SERVER_XML_KEY, Boolean.FALSE.toString() ) ); + } + + + public void debugMessage( String message ) + { + if ( debug ) + { + System.out.println( message ); + } + } + + + public boolean enableNaming() + { + return Boolean.parseBoolean( runtimeProperties.getProperty( ENABLE_NAMING_KEY, Boolean.FALSE.toString() ) ); + } + + private void installLogger( String loggerName ) + throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, + InvocationTargetException + { + if ( "slf4j".equals( loggerName ) ) + { + + try + { + // Check class is available + + //final Class clazz = Class.forName( "org.slf4j.bridge.SLF4JBridgeHandler" ); + final Class clazz = + Thread.currentThread().getContextClassLoader().loadClass( "org.slf4j.bridge.SLF4JBridgeHandler" ); + + // Remove all JUL handlers + java.util.logging.LogManager.getLogManager().reset(); + + // Install slf4j bridge handler + final Method method = clazz.getMethod( "install", null ); + method.invoke( null ); + } + catch ( ClassNotFoundException e ) + { + System.out.println( "WARNING: issue configuring slf4j jul bridge, skip it" ); + } + } + else + { + System.out.println( "WARNING: loggerName " + loggerName + " not supported, skip it" ); + } + } + + private Properties loadProperties( File file ) + throws FileNotFoundException, IOException + { + Properties properties = new Properties(); + if ( file.exists() ) + { + + FileInputStream fileInputStream = new FileInputStream( file ); + try + { + properties.load( fileInputStream ); + } + finally + { + fileInputStream.close(); + } + + } + return properties; + } + + private void saveProperties( Properties properties, File file ) + throws FileNotFoundException, IOException + { + FileOutputStream fileOutputStream = new FileOutputStream( file ); + try + { + properties.store( fileOutputStream, "Timestamp file for executable war/jar" ); + } + finally + { + fileOutputStream.close(); + } + } +} diff --git a/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/Tomcat9RunnerCli.java b/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/Tomcat9RunnerCli.java new file mode 100644 index 00000000..07bcfe33 --- /dev/null +++ b/tomcat9-war-runner/src/main/java/org/apache/tomcat/maven/runner/Tomcat9RunnerCli.java @@ -0,0 +1,250 @@ +package org.apache.tomcat.maven.runner; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +@SuppressWarnings( "static-access" ) +public class Tomcat9RunnerCli +{ + + public static final String STAND_ALONE_PROPERTIES_FILENAME = "tomcat.standalone.properties"; + + static Option httpPort = + OptionBuilder.withArgName( "httpPort" ).hasArg().withDescription( "http port to use" ).create( "httpPort" ); + + static Option httpsPort = + OptionBuilder.withArgName( "httpsPort" ).hasArg().withDescription( "https port to use" ).create( "httpsPort" ); + + static Option maxPostSize = + OptionBuilder.withArgName( "maxPostSize" ).hasArg().withDescription( "max post size to use" ).create( + "maxPostSize" ); + + static Option ajpPort = + OptionBuilder.withArgName( "ajpPort" ).hasArg().withDescription( "ajp port to use" ).create( "ajpPort" ); + + static Option serverXmlPath = + OptionBuilder.withArgName( "serverXmlPath" ).hasArg().withDescription( "server.xml to use, optional" ).create( + "serverXmlPath" ); + + static Option resetExtract = + OptionBuilder.withArgName( "resetExtract" ).withDescription( "clean previous extract directory" ).create( + "resetExtract" ); + + static Option help = OptionBuilder.withLongOpt( "help" ).withDescription( "help" ).create( 'h' ); + + static Option debug = OptionBuilder.withLongOpt( "debug" ).withDescription( "debug" ).create( 'X' ); + + static Option sysProps = OptionBuilder.withDescription( "use value for given property" ).hasArgs().withDescription( + "key=value" ).withValueSeparator().create( 'D' ); + + static Option clientAuth = + OptionBuilder.withArgName( "clientAuth" ).withDescription( "enable client authentication for https" ).create( + "clientAuth" ); + + static Option keyAlias = + OptionBuilder.withArgName( "keyAlias" ).hasArgs().withDescription( "alias from keystore for ssl" ).create( + "keyAlias" ); + + static Option obfuscate = + OptionBuilder.withArgName( "password" ).hasArgs().withDescription( "obfuscate the password and exit" ).create( + "obfuscate" ); + + static Option httpProtocol = OptionBuilder.withArgName( "httpProtocol" ).hasArg().withDescription( + "http protocol to use: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol" ).create( "httpProtocol" ); + + static Option extractDirectory = OptionBuilder.withArgName( "extractDirectory" ).hasArg().withDescription( + "path to extract war content, default value: .extract" ).create( "extractDirectory" ); + + static Option loggerName = OptionBuilder.withArgName( "loggerName" ).hasArg().withDescription( + "logger to use: slf4j to use slf4j bridge on top of jul" ).create( "loggerName" ); + + static Option uriEncoding = OptionBuilder.withArgName( "uriEncoding" ).hasArg().withDescription( + "connector uriEncoding default ISO-8859-1" ).create( "uriEncoding" ); + + static Options options = new Options(); + + static + { + options.addOption( httpPort ) // + .addOption( httpsPort ) // + .addOption( ajpPort ) // + .addOption( serverXmlPath ) // + .addOption( resetExtract ) // + .addOption( help ) // + .addOption( debug ) // + .addOption( sysProps ) // + .addOption( httpProtocol ) // + .addOption( clientAuth ) // + .addOption( keyAlias ) // + .addOption( obfuscate ) // + .addOption( extractDirectory ) // + .addOption( loggerName ) // + .addOption( uriEncoding ) // + .addOption( maxPostSize ); + } + + + public static void main( String[] args ) + throws Exception + { + CommandLineParser parser = new GnuParser(); + CommandLine line = null; + try + { + line = parser.parse(Tomcat9RunnerCli.options, args ); + } + catch ( ParseException e ) + { + System.err.println( "Parsing failed. Reason: " + e.getMessage() ); + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp(getCmdLineSyntax(), Tomcat9RunnerCli.options ); + System.exit( 1 ); + } + + if ( line.hasOption( help.getOpt() ) ) + { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp(getCmdLineSyntax(), Tomcat9RunnerCli.options ); + System.exit( 0 ); + } + + if ( line.hasOption( obfuscate.getOpt() ) ) + { + System.out.println( PasswordUtil.obfuscate( line.getOptionValue( obfuscate.getOpt() ) ) ); + System.exit( 0 ); + } + Tomcat9Runner tomcat9Runner = new Tomcat9Runner(); + + tomcat9Runner.runtimeProperties = buildStandaloneProperties(); + + if ( line.hasOption( serverXmlPath.getOpt() ) ) + { + tomcat9Runner.serverXmlPath = line.getOptionValue( serverXmlPath.getOpt() ); + } + + String port = tomcat9Runner.runtimeProperties.getProperty( Tomcat9Runner.HTTP_PORT_KEY ); + if ( port != null ) + { + tomcat9Runner.httpPort = Integer.parseInt( port ); + } + + // cli win for the port + if ( line.hasOption( httpPort.getOpt() ) ) + { + tomcat9Runner.httpPort = Integer.parseInt( line.getOptionValue( httpPort.getOpt() ) ); + } + + if ( line.hasOption( maxPostSize.getOpt() ) ) + { + tomcat9Runner.maxPostSize = Integer.parseInt( line.getOptionValue( maxPostSize.getOpt() ) ); + } + + if ( line.hasOption( httpsPort.getOpt() ) ) + { + tomcat9Runner.httpsPort = Integer.parseInt( line.getOptionValue( httpsPort.getOpt() ) ); + } + if ( line.hasOption( ajpPort.getOpt() ) ) + { + tomcat9Runner.ajpPort = Integer.parseInt( line.getOptionValue( ajpPort.getOpt() ) ); + } + if ( line.hasOption( resetExtract.getOpt() ) ) + { + tomcat9Runner.resetExtract = true; + } + if ( line.hasOption( debug.getOpt() ) ) + { + tomcat9Runner.debug = true; + } + + if ( line.hasOption( httpProtocol.getOpt() ) ) + { + tomcat9Runner.httpProtocol = line.getOptionValue( httpProtocol.getOpt() ); + } + + if ( line.hasOption( sysProps.getOpt() ) ) + { + Properties systemProperties = line.getOptionProperties( sysProps.getOpt() ); + if ( systemProperties != null && !systemProperties.isEmpty() ) + { + for ( Map.Entry sysProp : systemProperties.entrySet() ) + { + System.setProperty( (String) sysProp.getKey(), (String) sysProp.getValue() ); + } + } + } + if ( line.hasOption( clientAuth.getOpt() ) ) + { + tomcat9Runner.clientAuth = clientAuth.getOpt(); + } + if ( line.hasOption( keyAlias.getOpt() ) ) + { + tomcat9Runner.keyAlias = line.getOptionValue( keyAlias.getOpt() ); + } + + if ( line.hasOption( extractDirectory.getOpt() ) ) + { + tomcat9Runner.extractDirectory = line.getOptionValue( extractDirectory.getOpt() ); + } + + if ( line.hasOption( loggerName.getOpt() ) ) + { + tomcat9Runner.loggerName = line.getOptionValue( loggerName.getOpt() ); + } + + if ( line.hasOption( uriEncoding.getOpt() ) ) + { + tomcat9Runner.uriEncoding = line.getOptionValue( uriEncoding.getOpt() ); + } + + // here we go + tomcat9Runner.run(); + } + + private static Properties buildStandaloneProperties() + throws IOException + { + InputStream is = + Thread.currentThread().getContextClassLoader().getResourceAsStream( STAND_ALONE_PROPERTIES_FILENAME ); + Properties properties = new Properties(); + properties.load( is ); + return properties; + } + + public static String getCmdLineSyntax() + { + return "java -jar [path to your exec war jar]"; + } +}