Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,1614 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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.LifecycleException; +import org.apache.catalina.WebResource; +import org.apache.catalina.WebResourceSet; +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.FileResource; +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.tomcat8.AbstractTomcat7Mojo; +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; + +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 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; + +/** + * @author Olivier Lamy + * @since 2.0 + */ +public abstract class AbstractRunMojo + extends AbstractTomcat7Mojo +{ + // --------------------------------------------------------------------- + // 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: + * <ul> + * <li>org.apache.coyote.ajp.AjpProtocol - new blocking Java connector that supports an executor</li> + * <li>org.apache.coyote.ajp.AjpAprProtocol - the APR/native connector.</li> + * </ul> + * + * @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<String, String> 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 <b>Note if you use this you must configure in this file your webapp paths</b>. + * + * @since 1.0-alpha-2 + */ + @Parameter( property = "maven.tomcat.serverXml" ) + private File serverXml; + + /** + * overriding the providing web.xml to run tomcat + * <b>This override the global Tomcat web.xml located in $CATALINA_HOME/conf/</b> + * + * @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: + * <pre> + * <type>war</type> + * <scope>tomcat</scope> + * </pre> + * 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 <code>true</code> 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<Artifact> 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; + + /** + * <p> + * Enables or disables naming support for the embedded Tomcat server. + * </p> + * <p> + * <strong>Note:</strong> This setting is ignored if you provide a <code>server.xml</code> for your + * Tomcat. Instead please configure naming in the <code>server.xml</code>. + * </p> + * + * @see <a href="http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/startup/Embedded.html">org.apache.catalina.startup.Embedded</a> + * @see <a href="http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/startup/Tomcat.html">org.apache.catalina.startup.Tomcat</a> + * @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 <a href="http://tomcat.apache.org/tomcat-7.0-doc/config/context.html">http://tomcat.apache.org/tomcat-7.0-doc/config/context.html</a> + */ + @Parameter( property = "maven.tomcat.backgroundProcessorDelay", defaultValue = "-1" ) + protected int backgroundProcessorDelay = -1; + + + /** + * <p>The path of the Tomcat context XML file.</p> + * <p>Since release 2.0, the file is filtered as a maven resource so you can use + * interpolation tokens ${ }</p> + */ + @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 <a href="http://tomcat.apache.org/tomcat-7.0-doc/config/http.html">HTTP Connector</a> + * 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.<p> + * + * @see {@link Webapp} + * @since 2.0 + */ + @Parameter + private List<Webapp> 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 <code>null</code> 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 <a href="http://tomcat.apache.org/tomcat-7.0-doc/config/host.html#Host_Name_Aliases">Host Name aliases</a> + * + * @since 2.0 + */ + @Parameter + protected String[] aliases; + + /** + * enable client authentication for https (if configured) + * see <a href="http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#SSL_Support_-_BIO_and_NIO">http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#SSL_Support_-_BIO_and_NIO</a> + * + * @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 + */ + 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() ) + { + standardContext = parseContextFile( overriddenContextFile ); + } + else if ( defaultContextFile.exists() ) + { + 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 ); + + context.setResources( + new MyDirContext( new File( project.getBuild().getOutputDirectory() ).getAbsolutePath(), getPath() ) ); + + 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 ); + } + } + + + private static class MyDirContext + extends StandardRoot + { + String buildOutputDirectory; + + String webAppPath; + + WebResourceSet webResourceSet; + + MyDirContext( String buildOutputDirectory, String webAppPath ) + { + this.buildOutputDirectory = buildOutputDirectory; + this.webAppPath = webAppPath; + } + + @Override + public String[] list( String path ) + { + return super.list( path ); + } + + @Override + public WebResource getResource( String path ) + { + File file = new File( path ); + if ( file.exists() ) + { + return new FileResource( this, this.webAppPath, file, true ); + } + WebResource webResource = super.getResource( path ); + return webResource; + } + + @Override + public WebResource getClassLoaderResource( String path ) + { + if ( this.webResourceSet != null ) + { + WebResource webResource = this.webResourceSet.getResource( path ); + return webResource; + } + + return super.getClassLoaderResource( path ); + } + + @Override + public void addJarResources( WebResourceSet webResourceSet ) + { + this.webResourceSet = webResourceSet; + } + } + + /** + * 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() ); + webappLoader.setLoaderClass( MavenWebappClassLoader.class.getName() ); + } + } + else + { + if ( isContextReloadable() ) + { + webappLoader = + new ExternalRepositoriesReloadableWebappLoader( Thread.currentThread().getContextClassLoader(), + getLog() ); + } + else + { + webappLoader = new WebappLoader( Thread.currentThread().getContextClassLoader() ); + webappLoader.setLoaderClass( MavenWebappClassLoader.class.getName() ); + } + } + 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 tomcat7 + * 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 + { + + // 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<Webapp> 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 ( @SuppressWarnings( "rawtypes" ) Iterator i = pluginArtifacts.iterator(); i.hasNext(); ) + { + Artifact pluginArtifact = (Artifact) 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<Artifact> 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<Context> createDependencyContexts( Tomcat container ) + throws MojoExecutionException, MalformedURLException, ServletException, IOException + { + getLog().info( "Deploying dependency wars" ); + // Let's add other modules + List<Context> contexts = new ArrayList<Context>(); + + ScopeArtifactFilter filter = new ScopeArtifactFilter( "tomcat" ); + @SuppressWarnings( "unchecked" ) Set<Artifact> 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<Context> 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" ); + 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; + } +}
Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunMojo.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunWarMojo.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunWarMojo.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunWarMojo.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunWarMojo.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,66 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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 <markhob...@gmail.com> + * @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; + } +} Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunWarMojo.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractRunWarMojo.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractStandaloneWarMojo.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractStandaloneWarMojo.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractStandaloneWarMojo.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractStandaloneWarMojo.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,297 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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.Tomcat7Runner; +import org.apache.tomcat.maven.runner.Tomcat7RunnerCli; +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( Tomcat7Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY, + Long.toString( System.currentTimeMillis() ) ); + properties.put( Tomcat7Runner.ENABLE_NAMING_KEY, Boolean.toString( enableNaming ) ); + properties.put( Tomcat7Runner.ACCESS_LOG_VALVE_FORMAT_KEY, accessLogValveFormat ); + properties.put( Tomcat7Runner.HTTP_PROTOCOL_KEY, connectorHttpProtocol ); + properties.put( Tomcat7Runner.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( Tomcat7Runner.USE_SERVER_XML_KEY, Boolean.TRUE.toString() ); + } + else + { + properties.put( Tomcat7Runner.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( Tomcat7RunnerCli.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( "tomcat7-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 ); + } + + } +} Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractStandaloneWarMojo.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/AbstractStandaloneWarMojo.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarMojo.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarMojo.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarMojo.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarMojo.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,40 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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 <code>java -jar mywebapp.jar</code> to run your webapp without + * needing to install a Tomcat instance. + * More details <a href="http://tomcat.apache.org/maven-plugin-2.0/executable-war-jar.html">here</a>. + * + * @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 +} Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarMojo.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarMojo.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarOnlyMojo.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarOnlyMojo.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarOnlyMojo.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarOnlyMojo.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,34 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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 +} Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarOnlyMojo.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExecWarOnlyMojo.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtendedTomcat.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtendedTomcat.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtendedTomcat.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtendedTomcat.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,69 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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; + } +} Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtendedTomcat.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtendedTomcat.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraDependency.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraDependency.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraDependency.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraDependency.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,31 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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 +} Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraDependency.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraDependency.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraResource.java URL: http://svn.apache.org/viewvc/tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraResource.java?rev=1756441&view=auto ============================================================================== --- tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraResource.java (added) +++ tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraResource.java Tue Aug 16 01:03:14 2016 @@ -0,0 +1,31 @@ +package org.apache.tomcat.maven.plugin.tomcat8.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 +} + Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraResource.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/maven-plugin/trunk/tomcat8-maven-plugin/src/main/java/org/apache/tomcat/maven/plugin/tomcat8/run/ExtraResource.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org