Merge branch 'jetty-9' into jetty-9-aggregation
This commit is contained in:
commit
d9eae6d4a2
|
@ -0,0 +1,5 @@
|
|||
.classpath
|
||||
.project
|
||||
.settings
|
||||
target
|
||||
*.swp
|
|
@ -0,0 +1,139 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<packaging>maven-plugin</packaging>
|
||||
<name>Jetty :: Jetty Maven Plugin</name>
|
||||
<properties>
|
||||
<mavenVersion>3.0.3</mavenVersion>
|
||||
<pluginToolsVersion>2.9</pluginToolsVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
<verbose>false</verbose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-plugin-plugin</artifactId>
|
||||
<version>${pluginToolsVersion}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>exec-plugin-doc</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>xdoc</goal>
|
||||
<goal>helpmojo</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
<version>${mavenVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-artifact</artifactId>
|
||||
<version>${mavenVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-core</artifactId>
|
||||
<version>${mavenVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-tools</groupId>
|
||||
<artifactId>maven-plugin-tools-api</artifactId>
|
||||
<version>${pluginToolsVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jndi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!--dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency-->
|
||||
<!-- dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency-->
|
||||
</dependencies>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<configuration>
|
||||
<dependencyLocationEnabled>false</dependencyLocationEnabled>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>project-team</report>
|
||||
<report>mailing-list</report>
|
||||
<report>cim</report>
|
||||
<report>issue-tracking</report>
|
||||
<report>license</report>
|
||||
<report>scm</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</project>
|
|
@ -0,0 +1,995 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.util.FileUtils;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* AbstractJettyMojo
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractJettyMojo extends AbstractMojo
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope>
|
||||
* Use WITH CAUTION as you may wind up with duplicate jars/classes.
|
||||
*
|
||||
* @since jetty-7.5.2
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean useProvidedScope;
|
||||
|
||||
|
||||
/**
|
||||
* List of goals that are NOT to be used
|
||||
*
|
||||
* @since jetty-7.5.2
|
||||
* @parameter
|
||||
*/
|
||||
protected String[] excludedGoals;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of connectors to use. If none are configured
|
||||
* then the default is a single SelectChannelConnector at port 8080. You can
|
||||
* override this default port number by using the system property jetty.port
|
||||
* on the command line, eg: mvn -Djetty.port=9999 jetty:run. Consider using instead
|
||||
* the <jettyXml> element to specify external jetty xml config file.
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected Connector[] connectors;
|
||||
|
||||
|
||||
/**
|
||||
* List of other contexts to set up. Consider using instead
|
||||
* the <jettyXml> element to specify external jetty xml config file.
|
||||
* Optional.
|
||||
*
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected ContextHandler[] contextHandlers;
|
||||
|
||||
|
||||
/**
|
||||
* List of security realms to set up. Consider using instead
|
||||
* the <jettyXml> element to specify external jetty xml config file.
|
||||
* Optional.
|
||||
*
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected LoginService[] loginServices;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A RequestLog implementation to use for the webapp at runtime.
|
||||
* Consider using instead the <jettyXml> element to specify external jetty xml config file.
|
||||
* Optional.
|
||||
*
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected RequestLog requestLog;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An instance of org.eclipse.jetty.webapp.WebAppContext that represents the webapp.
|
||||
* Use any of its setters to configure the webapp. This is the preferred and most
|
||||
* flexible method of configuration, rather than using the (deprecated) individual
|
||||
* parameters like "tmpDirectory", "contextPath" etc.
|
||||
*
|
||||
* @parameter alias="webAppConfig"
|
||||
*/
|
||||
protected JettyWebAppContext webApp;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The context path for the webapp. Defaults to the
|
||||
* name of the webapp's artifact.
|
||||
*
|
||||
* @deprecated Use <webApp><contextPath> instead.
|
||||
* @parameter expression="/${project.artifactId}"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected String contextPath;
|
||||
|
||||
|
||||
/**
|
||||
* The temporary directory to use for the webapp.
|
||||
* Defaults to target/tmp.
|
||||
*
|
||||
* @deprecated Use %lt;webApp><tempDirectory> instead.
|
||||
* @parameter expression="${project.build.directory}/tmp"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected File tmpDirectory;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The interval in seconds to scan the webapp for changes
|
||||
* and restart the context if necessary. Ignored if reload
|
||||
* is enabled. Disabled by default.
|
||||
*
|
||||
* @parameter expression="${jetty.scanIntervalSeconds}" default-value="0"
|
||||
* @required
|
||||
*/
|
||||
protected int scanIntervalSeconds;
|
||||
|
||||
|
||||
/**
|
||||
* reload can be set to either 'automatic' or 'manual'
|
||||
*
|
||||
* if 'manual' then the context can be reloaded by a linefeed in the console
|
||||
* if 'automatic' then traditional reloading on changed files is enabled.
|
||||
*
|
||||
* @parameter expression="${jetty.reload}" default-value="automatic"
|
||||
*/
|
||||
protected String reload;
|
||||
|
||||
/**
|
||||
* File containing system properties to be set before execution
|
||||
*
|
||||
* Note that these properties will NOT override System properties
|
||||
* that have been set on the command line, by the JVM, or directly
|
||||
* in the POM via systemProperties. Optional.
|
||||
*
|
||||
* @parameter expression="${jetty.systemPropertiesFile}"
|
||||
*/
|
||||
protected File systemPropertiesFile;
|
||||
|
||||
/**
|
||||
* System properties to set before execution.
|
||||
* Note that these properties will NOT override System properties
|
||||
* that have been set on the command line or by the JVM. They WILL
|
||||
* override System properties that have been set via systemPropertiesFile.
|
||||
* Optional.
|
||||
* @parameter
|
||||
*/
|
||||
protected SystemProperties systemProperties;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Comma separated list of a jetty xml configuration files whose contents
|
||||
* will be applied before any plugin configuration. Optional.
|
||||
*
|
||||
*
|
||||
* @parameter alias="jettyConfig"
|
||||
*/
|
||||
protected String jettyXml;
|
||||
|
||||
|
||||
/**
|
||||
* Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort>
|
||||
* -DSTOP.KEY=<stopKey> -jar start.jar --stop
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected int stopPort;
|
||||
|
||||
/**
|
||||
* Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
|
||||
* -DSTOP.PORT=<stopPort> -jar start.jar --stop
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
protected String stopKey;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Determines whether or not the server blocks when started. The default
|
||||
* behavior (daemon = false) will cause the server to pause other processes
|
||||
* while it continues to handle web requests. This is useful when starting the
|
||||
* server with the intent to work with it interactively.
|
||||
* </p><p>
|
||||
* Often, it is desirable to let the server start and continue running subsequent
|
||||
* processes in an automated build environment. This can be facilitated by setting
|
||||
* daemon to true.
|
||||
* </p>
|
||||
*
|
||||
* @parameter expression="${jetty.daemon}" default-value="false"
|
||||
*/
|
||||
protected boolean daemon;
|
||||
|
||||
/**
|
||||
* Skip this mojo execution.
|
||||
*
|
||||
* @parameter expression="${jetty.skip}" default-value="false"
|
||||
*/
|
||||
protected boolean skip;
|
||||
|
||||
|
||||
/**
|
||||
* Location of a context xml configuration file whose contents
|
||||
* will be applied to the webapp AFTER anything in <webApp>.Optional.
|
||||
*
|
||||
*
|
||||
* @parameter alias="webAppXml"
|
||||
*/
|
||||
protected String contextXml;
|
||||
|
||||
|
||||
/**
|
||||
* The maven project.
|
||||
*
|
||||
* @parameter expression="${project}"
|
||||
* @readonly
|
||||
*/
|
||||
protected MavenProject project;
|
||||
|
||||
|
||||
/**
|
||||
* The artifacts for the project.
|
||||
*
|
||||
* @parameter expression="${project.artifacts}"
|
||||
* @readonly
|
||||
*/
|
||||
protected Set projectArtifacts;
|
||||
|
||||
|
||||
/**
|
||||
* @parameter expression="${mojoExecution}"
|
||||
* @readonly
|
||||
*/
|
||||
private org.apache.maven.plugin.MojoExecution execution;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The artifacts for the plugin itself.
|
||||
*
|
||||
* @parameter expression="${plugin.artifacts}"
|
||||
* @readonly
|
||||
*/
|
||||
private List pluginArtifacts;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper for the Server object
|
||||
*/
|
||||
protected JettyServer server;
|
||||
|
||||
/**
|
||||
* A scanner to check for changes to the webapp
|
||||
*/
|
||||
protected Scanner scanner;
|
||||
|
||||
/**
|
||||
* List of files and directories to scan
|
||||
*/
|
||||
protected ArrayList<File> scanList;
|
||||
|
||||
/**
|
||||
* List of Listeners for the scanner
|
||||
*/
|
||||
protected ArrayList<Scanner.BulkListener> scannerListeners;
|
||||
|
||||
|
||||
/**
|
||||
* A scanner to check ENTER hits on the console
|
||||
*/
|
||||
protected Thread consoleScanner;
|
||||
|
||||
|
||||
public String PORT_SYSPROPERTY = "jetty.port";
|
||||
|
||||
|
||||
public abstract void restartWebApp(boolean reconfigureScanner) throws Exception;
|
||||
|
||||
public abstract void checkPomConfiguration() throws MojoExecutionException;
|
||||
|
||||
public abstract void configureScanner () throws MojoExecutionException;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
getLog().info("Configuring Jetty for project: " + getProject().getName());
|
||||
if (skip)
|
||||
{
|
||||
getLog().info("Skipping Jetty start: jetty.skip==true");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExcluded(execution.getMojoDescriptor().getGoal()))
|
||||
{
|
||||
getLog().info("The goal \""+execution.getMojoDescriptor().getFullGoalName()+
|
||||
"\" has been made unavailable for this web application by an <excludedGoal> configuration.");
|
||||
return;
|
||||
}
|
||||
|
||||
configurePluginClasspath();
|
||||
PluginLog.setLog(getLog());
|
||||
checkPomConfiguration();
|
||||
startJetty();
|
||||
}
|
||||
|
||||
|
||||
public void configurePluginClasspath() throws MojoExecutionException
|
||||
{
|
||||
//if we are configured to include the provided dependencies on the plugin's classpath
|
||||
//(which mimics being on jetty's classpath vs being on the webapp's classpath), we first
|
||||
//try and filter out ones that will clash with jars that are plugin dependencies, then
|
||||
//create a new classloader that we setup in the parent chain.
|
||||
if (useProvidedScope)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<URL> provided = new ArrayList<URL>();
|
||||
URL[] urls = null;
|
||||
|
||||
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = iter.next();
|
||||
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact))
|
||||
{
|
||||
provided.add(artifact.getFile().toURI().toURL());
|
||||
if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);}
|
||||
}
|
||||
}
|
||||
|
||||
if (!provided.isEmpty())
|
||||
{
|
||||
urls = new URL[provided.size()];
|
||||
provided.toArray(urls);
|
||||
URLClassLoader loader = new URLClassLoader(urls, getClass().getClassLoader());
|
||||
Thread.currentThread().setContextClassLoader(loader);
|
||||
getLog().info("Plugin classpath augmented with <scope>provided</scope> dependencies: "+Arrays.toString(urls));
|
||||
}
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw new MojoExecutionException("Invalid url", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isPluginArtifact(Artifact artifact)
|
||||
{
|
||||
if (pluginArtifacts == null || pluginArtifacts.isEmpty())
|
||||
return false;
|
||||
|
||||
boolean isPluginArtifact = false;
|
||||
for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext() && !isPluginArtifact; )
|
||||
{
|
||||
Artifact pluginArtifact = iter.next();
|
||||
if (getLog().isDebugEnabled()) { getLog().debug("Checking "+pluginArtifact);}
|
||||
if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId()))
|
||||
isPluginArtifact = true;
|
||||
}
|
||||
|
||||
return isPluginArtifact;
|
||||
}
|
||||
|
||||
public void finishConfigurationBeforeStart() throws Exception
|
||||
{
|
||||
HandlerCollection contexts = (HandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||
if (contexts==null)
|
||||
contexts = (HandlerCollection)server.getChildHandlerByClass(HandlerCollection.class);
|
||||
|
||||
for (int i=0; (this.contextHandlers != null) && (i < this.contextHandlers.length); i++)
|
||||
{
|
||||
contexts.addHandler(this.contextHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void applyJettyXml() throws Exception
|
||||
{
|
||||
if (getJettyXmlFiles() == null)
|
||||
return;
|
||||
|
||||
for ( File xmlFile : getJettyXmlFiles() )
|
||||
{
|
||||
getLog().info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() );
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile));
|
||||
xmlConfiguration.configure(this.server);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void startJetty () throws MojoExecutionException
|
||||
{
|
||||
try
|
||||
{
|
||||
getLog().debug("Starting Jetty Server ...");
|
||||
|
||||
printSystemProperties();
|
||||
this.server = new JettyServer();
|
||||
setServer(this.server);
|
||||
|
||||
//apply any config from a jetty.xml file first which is able to
|
||||
//be overwritten by config in the pom.xml
|
||||
applyJettyXml ();
|
||||
|
||||
|
||||
|
||||
// if the user hasn't configured their project's pom to use a
|
||||
// different set of connectors,
|
||||
// use the default
|
||||
Connector[] connectors = this.server.getConnectors();
|
||||
if (connectors == null|| connectors.length == 0)
|
||||
{
|
||||
//try using ones configured in pom
|
||||
this.server.setConnectors(this.connectors);
|
||||
|
||||
connectors = this.server.getConnectors();
|
||||
if (connectors == null || connectors.length == 0)
|
||||
{
|
||||
//if a SystemProperty -Djetty.port=<portnum> has been supplied, use that as the default port
|
||||
this.connectors = new Connector[] { this.server.createDefaultConnector(server, System.getProperty(PORT_SYSPROPERTY, null)) };
|
||||
this.server.setConnectors(this.connectors);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//set up a RequestLog if one is provided
|
||||
if (this.requestLog != null)
|
||||
getServer().setRequestLog(this.requestLog);
|
||||
|
||||
//set up the webapp and any context provided
|
||||
this.server.configureHandlers();
|
||||
configureWebApplication();
|
||||
this.server.addWebApplication(webApp);
|
||||
|
||||
// set up security realms
|
||||
for (int i = 0; (this.loginServices != null) && i < this.loginServices.length; i++)
|
||||
{
|
||||
getLog().debug(this.loginServices[i].getClass().getName() + ": "+ this.loginServices[i].toString());
|
||||
getServer().addBean(this.loginServices[i]);
|
||||
}
|
||||
|
||||
//do any other configuration required by the
|
||||
//particular Jetty version
|
||||
finishConfigurationBeforeStart();
|
||||
|
||||
// start Jetty
|
||||
this.server.start();
|
||||
|
||||
getLog().info("Started Jetty Server");
|
||||
|
||||
if(stopPort>0 && stopKey!=null)
|
||||
{
|
||||
Monitor monitor = new Monitor(stopPort, stopKey, new Server[]{server}, !daemon);
|
||||
monitor.start();
|
||||
}
|
||||
|
||||
// start the scanner thread (if necessary) on the main webapp
|
||||
configureScanner ();
|
||||
startScanner();
|
||||
|
||||
// start the new line scanner thread if necessary
|
||||
startConsoleScanner();
|
||||
|
||||
// keep the thread going if not in daemon mode
|
||||
if (!daemon )
|
||||
{
|
||||
server.join();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MojoExecutionException("Failure", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!daemon )
|
||||
{
|
||||
getLog().info("Jetty server exiting.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses should invoke this to setup basic info
|
||||
* on the webapp
|
||||
*
|
||||
* @throws MojoExecutionException
|
||||
*/
|
||||
public void configureWebApplication () throws Exception
|
||||
{
|
||||
//As of jetty-7, you must use a <webAppConfig> element
|
||||
if (webApp == null)
|
||||
webApp = new JettyWebAppContext();
|
||||
|
||||
//Apply any context xml file to set up the webapp
|
||||
//CAUTION: if you've defined a <webAppConfig> element then the
|
||||
//context xml file can OVERRIDE those settings
|
||||
if (contextXml != null)
|
||||
{
|
||||
File file = FileUtils.getFile(contextXml);
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(file));
|
||||
getLog().info("Applying context xml file "+contextXml);
|
||||
xmlConfiguration.configure(webApp);
|
||||
}
|
||||
|
||||
|
||||
//If no contextPath was specified, go with our default
|
||||
String cp = webApp.getContextPath();
|
||||
if (cp == null || "".equals(cp))
|
||||
{
|
||||
webApp.setContextPath((contextPath.startsWith("/") ? contextPath : "/"+ contextPath));
|
||||
}
|
||||
|
||||
//If no tmp directory was specified, and we have one, use it
|
||||
if (webApp.getTempDirectory() == null && tmpDirectory != null)
|
||||
{
|
||||
if (!tmpDirectory.exists())
|
||||
tmpDirectory.mkdirs();
|
||||
|
||||
webApp.setTempDirectory(tmpDirectory);
|
||||
}
|
||||
|
||||
getLog().info("Context path = " + webApp.getContextPath());
|
||||
getLog().info("Tmp directory = "+ (webApp.getTempDirectory()== null? " determined at runtime": webApp.getTempDirectory()));
|
||||
getLog().info("Web defaults = "+(webApp.getDefaultsDescriptor()==null?" jetty default":webApp.getDefaultsDescriptor()));
|
||||
getLog().info("Web overrides = "+(webApp.getOverrideDescriptor()==null?" none":webApp.getOverrideDescriptor()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a scanner thread on the given list of files and directories, calling
|
||||
* stop/start on the given list of LifeCycle objects if any of the watched
|
||||
* files change.
|
||||
*
|
||||
*/
|
||||
private void startScanner() throws Exception
|
||||
{
|
||||
// check if scanning is enabled
|
||||
if (getScanIntervalSeconds() <= 0) return;
|
||||
|
||||
// check if reload is manual. It disables file scanning
|
||||
if ( "manual".equalsIgnoreCase( reload ) )
|
||||
{
|
||||
// issue a warning if both scanIntervalSeconds and reload
|
||||
// are enabled
|
||||
getLog().warn("scanIntervalSeconds is set to " + scanIntervalSeconds + " but will be IGNORED due to manual reloading");
|
||||
return;
|
||||
}
|
||||
|
||||
scanner = new Scanner();
|
||||
scanner.setReportExistingFilesOnStartup(false);
|
||||
scanner.setScanInterval(getScanIntervalSeconds());
|
||||
scanner.setScanDirs(getScanList());
|
||||
scanner.setRecursive(true);
|
||||
List listeners = getScannerListeners();
|
||||
Iterator itor = (listeners==null?null:listeners.iterator());
|
||||
while (itor!=null && itor.hasNext())
|
||||
scanner.addListener((Scanner.Listener)itor.next());
|
||||
getLog().info("Starting scanner at interval of " + getScanIntervalSeconds()+ " seconds.");
|
||||
scanner.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a thread that monitors the console input to detect ENTER hits.
|
||||
*/
|
||||
protected void startConsoleScanner() throws Exception
|
||||
{
|
||||
if ( "manual".equalsIgnoreCase( reload ) )
|
||||
{
|
||||
getLog().info("Console reloading is ENABLED. Hit ENTER on the console to restart the context.");
|
||||
consoleScanner = new ConsoleScanner(this);
|
||||
consoleScanner.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void printSystemProperties ()
|
||||
{
|
||||
// print out which system properties were set up
|
||||
if (getLog().isDebugEnabled())
|
||||
{
|
||||
if (systemProperties != null)
|
||||
{
|
||||
Iterator itor = systemProperties.getSystemProperties().iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
SystemProperty prop = (SystemProperty)itor.next();
|
||||
getLog().debug("Property "+prop.getName()+"="+prop.getValue()+" was "+ (prop.isSet() ? "set" : "skipped"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and find a jetty-web.xml file, using some
|
||||
* historical naming conventions if necessary.
|
||||
* @param webInfDir
|
||||
* @return the jetty web xml file
|
||||
*/
|
||||
public File findJettyWebXmlFile (File webInfDir)
|
||||
{
|
||||
if (webInfDir == null)
|
||||
return null;
|
||||
if (!webInfDir.exists())
|
||||
return null;
|
||||
|
||||
File f = new File (webInfDir, "jetty-web.xml");
|
||||
if (f.exists())
|
||||
return f;
|
||||
|
||||
//try some historical alternatives
|
||||
f = new File (webInfDir, "web-jetty.xml");
|
||||
if (f.exists())
|
||||
return f;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Scanner getScanner ()
|
||||
{
|
||||
return scanner;
|
||||
}
|
||||
|
||||
public MavenProject getProject()
|
||||
{
|
||||
return this.project;
|
||||
}
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public File getTmpDirectory()
|
||||
{
|
||||
return this.tmpDirectory;
|
||||
}
|
||||
|
||||
public void setTmpDirectory(File tmpDirectory) {
|
||||
this.tmpDirectory = tmpDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the contextPath.
|
||||
*/
|
||||
public String getContextPath()
|
||||
{
|
||||
return this.contextPath;
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the scanIntervalSeconds.
|
||||
*/
|
||||
public int getScanIntervalSeconds()
|
||||
{
|
||||
return this.scanIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setScanIntervalSeconds(int scanIntervalSeconds) {
|
||||
this.scanIntervalSeconds = scanIntervalSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the path to the systemPropertiesFile
|
||||
*/
|
||||
public File getSystemPropertiesFile()
|
||||
{
|
||||
return this.systemPropertiesFile;
|
||||
}
|
||||
|
||||
public void setSystemPropertiesFile(File file) throws Exception
|
||||
{
|
||||
this.systemPropertiesFile = file;
|
||||
FileInputStream propFile = new FileInputStream(systemPropertiesFile);
|
||||
Properties properties = new Properties();
|
||||
properties.load(propFile);
|
||||
|
||||
if (this.systemProperties == null )
|
||||
this.systemProperties = new SystemProperties();
|
||||
|
||||
for (Enumeration keys = properties.keys(); keys.hasMoreElements(); )
|
||||
{
|
||||
String key = (String)keys.nextElement();
|
||||
if ( ! systemProperties.containsSystemProperty(key) )
|
||||
{
|
||||
SystemProperty prop = new SystemProperty();
|
||||
prop.setKey(key);
|
||||
prop.setValue(properties.getProperty(key));
|
||||
|
||||
this.systemProperties.setSystemProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setSystemProperties(SystemProperties systemProperties)
|
||||
{
|
||||
if (this.systemProperties == null)
|
||||
this.systemProperties = systemProperties;
|
||||
else
|
||||
{
|
||||
Iterator itor = systemProperties.getSystemProperties().iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
SystemProperty prop = (SystemProperty)itor.next();
|
||||
this.systemProperties.setSystemProperty(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SystemProperties getSystemProperties ()
|
||||
{
|
||||
return this.systemProperties;
|
||||
}
|
||||
|
||||
public List<File> getJettyXmlFiles()
|
||||
{
|
||||
if ( this.jettyXml == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<File> jettyXmlFiles = new ArrayList<File>();
|
||||
|
||||
if ( this.jettyXml.indexOf(',') == -1 )
|
||||
{
|
||||
jettyXmlFiles.add( new File( this.jettyXml ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] files = this.jettyXml.split(",");
|
||||
|
||||
for ( String file : files )
|
||||
{
|
||||
jettyXmlFiles.add( new File(file) );
|
||||
}
|
||||
}
|
||||
|
||||
return jettyXmlFiles;
|
||||
}
|
||||
|
||||
|
||||
public JettyServer getServer ()
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
|
||||
public void setServer (JettyServer server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
|
||||
public void setScanList (ArrayList<File> list)
|
||||
{
|
||||
this.scanList = new ArrayList<File>(list);
|
||||
}
|
||||
|
||||
public ArrayList<File> getScanList ()
|
||||
{
|
||||
return this.scanList;
|
||||
}
|
||||
|
||||
|
||||
public void setScannerListeners (ArrayList<Scanner.BulkListener> listeners)
|
||||
{
|
||||
this.scannerListeners = new ArrayList<Scanner.BulkListener>(listeners);
|
||||
}
|
||||
|
||||
public ArrayList getScannerListeners()
|
||||
{
|
||||
return this.scannerListeners;
|
||||
}
|
||||
|
||||
public JettyWebAppContext getWebAppConfig()
|
||||
{
|
||||
return webApp;
|
||||
}
|
||||
|
||||
public void setWebAppConfig(JettyWebAppContext webAppConfig)
|
||||
{
|
||||
this.webApp = webAppConfig;
|
||||
}
|
||||
|
||||
public RequestLog getRequestLog()
|
||||
{
|
||||
return requestLog;
|
||||
}
|
||||
|
||||
public void setRequestLog(RequestLog requestLog)
|
||||
{
|
||||
this.requestLog = requestLog;
|
||||
}
|
||||
|
||||
public LoginService[] getLoginServices()
|
||||
{
|
||||
return loginServices;
|
||||
}
|
||||
|
||||
public void setLoginServices(LoginService[] loginServices)
|
||||
{
|
||||
this.loginServices = loginServices;
|
||||
}
|
||||
|
||||
public ContextHandler[] getContextHandlers()
|
||||
{
|
||||
return contextHandlers;
|
||||
}
|
||||
|
||||
public void setContextHandlers(ContextHandler[] contextHandlers)
|
||||
{
|
||||
this.contextHandlers = contextHandlers;
|
||||
}
|
||||
|
||||
public Connector[] getConnectors()
|
||||
{
|
||||
return connectors;
|
||||
}
|
||||
|
||||
public void setConnectors(Connector[] connectors)
|
||||
{
|
||||
this.connectors = connectors;
|
||||
}
|
||||
|
||||
public String getReload()
|
||||
{
|
||||
return reload;
|
||||
}
|
||||
|
||||
public void setReload(String reload)
|
||||
{
|
||||
this.reload = reload;
|
||||
}
|
||||
|
||||
public String getJettyConfig()
|
||||
{
|
||||
return jettyXml;
|
||||
}
|
||||
|
||||
public void setJettyConfig(String jettyConfig)
|
||||
{
|
||||
this.jettyXml = jettyConfig;
|
||||
}
|
||||
|
||||
public String getWebAppXml()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setWebAppXml(String webAppXml)
|
||||
{
|
||||
this.contextXml = webAppXml;
|
||||
}
|
||||
|
||||
public boolean isSkip()
|
||||
{
|
||||
return skip;
|
||||
}
|
||||
|
||||
public void setSkip(boolean skip)
|
||||
{
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
public boolean isDaemon()
|
||||
{
|
||||
return daemon;
|
||||
}
|
||||
|
||||
public void setDaemon(boolean daemon)
|
||||
{
|
||||
this.daemon = daemon;
|
||||
}
|
||||
|
||||
public String getStopKey()
|
||||
{
|
||||
return stopKey;
|
||||
}
|
||||
|
||||
public void setStopKey(String stopKey)
|
||||
{
|
||||
this.stopKey = stopKey;
|
||||
}
|
||||
|
||||
public int getStopPort()
|
||||
{
|
||||
return stopPort;
|
||||
}
|
||||
|
||||
public void setStopPort(int stopPort)
|
||||
{
|
||||
this.stopPort = stopPort;
|
||||
}
|
||||
|
||||
public List getPluginArtifacts()
|
||||
{
|
||||
return pluginArtifacts;
|
||||
}
|
||||
|
||||
public void setPluginArtifacts(List pluginArtifacts)
|
||||
{
|
||||
this.pluginArtifacts = pluginArtifacts;
|
||||
}
|
||||
|
||||
|
||||
public boolean isExcluded (String goal)
|
||||
{
|
||||
if (excludedGoals == null || goal == null)
|
||||
return false;
|
||||
|
||||
goal = goal.trim();
|
||||
if ("".equals(goal))
|
||||
return false;
|
||||
|
||||
boolean excluded = false;
|
||||
for (int i=0; i<excludedGoals.length && !excluded; i++)
|
||||
{
|
||||
if (excludedGoals[i].equalsIgnoreCase(goal))
|
||||
excluded = true;
|
||||
}
|
||||
|
||||
return excluded;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.maven.plugin.AbstractJettyMojo;
|
||||
|
||||
public class ConsoleScanner extends Thread
|
||||
{
|
||||
|
||||
private final AbstractJettyMojo mojo;
|
||||
|
||||
public ConsoleScanner(AbstractJettyMojo mojo)
|
||||
{
|
||||
this.mojo = mojo;
|
||||
setName("Console scanner");
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
checkSystemInput();
|
||||
getSomeSleep();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
mojo.getLog().warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void getSomeSleep()
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(500);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
mojo.getLog().debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSystemInput() throws IOException
|
||||
{
|
||||
while (System.in.available() > 0) {
|
||||
int inputByte = System.in.read();
|
||||
if (inputByte >= 0)
|
||||
{
|
||||
char c = (char)inputByte;
|
||||
if (c == '\n') {
|
||||
restartWebApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip buffered bytes of system console.
|
||||
*/
|
||||
private void clearInputBuffer()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (System.in.available() > 0)
|
||||
{
|
||||
// System.in.skip doesn't work properly. I don't know why
|
||||
long available = System.in.available();
|
||||
for (int i = 0; i < available; i++)
|
||||
{
|
||||
if (System.in.read() == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
mojo.getLog().warn("Error discarding console input buffer", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void restartWebApp()
|
||||
{
|
||||
try
|
||||
{
|
||||
mojo.restartWebApp(false);
|
||||
// Clear input buffer to discard anything entered on the console
|
||||
// while the application was being restarted.
|
||||
clearInputBuffer();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mojo.getLog().error(
|
||||
"Error reconfiguring/restarting webapp after a new line on the console",
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This goal is used to run Jetty with a pre-assembled war.
|
||||
* </p>
|
||||
* <p>
|
||||
* It accepts exactly the same options as the <a href="run-war-mojo.html">run-war</a> goal.
|
||||
* However, it doesn't assume that the current artifact is a
|
||||
* webapp and doesn't try to assemble it into a war before its execution.
|
||||
* So using it makes sense only when used in conjunction with the
|
||||
* <a href="run-war-mojo.html#webApp">webApp</a> configuration parameter pointing to a pre-built WAR.
|
||||
* </p>
|
||||
* <p>
|
||||
* This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested
|
||||
* HTTP client components.
|
||||
* </p>
|
||||
*
|
||||
* @goal deploy-war
|
||||
* @requiresDependencyResolution runtime
|
||||
* @execute phase="validate"
|
||||
* @description Deploy a pre-assembled war
|
||||
*
|
||||
*/
|
||||
public class JettyDeployWar extends JettyRunWarMojo
|
||||
{
|
||||
}
|
|
@ -0,0 +1,827 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugin.descriptor.PluginDescriptor;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.component.repository.ComponentDependency;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This goal is used to assemble your webapp into a war and automatically deploy it to Jetty in a forked JVM.
|
||||
* </p>
|
||||
* <p>
|
||||
* You need to define a jetty.xml file to configure connectors etc and a context xml file that sets up anything special
|
||||
* about your webapp. This plugin will fill in the:
|
||||
* <ul>
|
||||
* <li>context path
|
||||
* <li>classes
|
||||
* <li>web.xml
|
||||
* <li>root of the webapp
|
||||
* </ul>
|
||||
* Based on a combination of information that you supply and the location of files in your unassembled webapp.
|
||||
* </p>
|
||||
* <p>
|
||||
* There is a <a href="run-war-mojo.html">reference guide</a> to the configuration parameters for this plugin, and more detailed information
|
||||
* with examples in the <a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin/">Configuration Guide</a>.
|
||||
* </p>
|
||||
*
|
||||
* @goal run-forked
|
||||
* @requiresDependencyResolution compile+runtime
|
||||
* @execute phase="test-compile"
|
||||
* @description Runs Jetty in forked JVM on an unassembled webapp
|
||||
*
|
||||
*/
|
||||
public class JettyRunForkedMojo extends AbstractMojo
|
||||
{
|
||||
public String PORT_SYSPROPERTY = "jetty.port";
|
||||
|
||||
/**
|
||||
* Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope>
|
||||
* Use WITH CAUTION as you may wind up with duplicate jars/classes.
|
||||
* @parameter default-value="false"
|
||||
*/
|
||||
protected boolean useProvidedScope;
|
||||
|
||||
|
||||
/**
|
||||
* The maven project.
|
||||
*
|
||||
* @parameter expression="${project}"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
private MavenProject project;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If true, the <testOutputDirectory>
|
||||
* and the dependencies of <scope>test<scope>
|
||||
* will be put first on the runtime classpath.
|
||||
* @parameter alias="useTestClasspath" default-value="false"
|
||||
*/
|
||||
private boolean useTestScope;
|
||||
|
||||
|
||||
/**
|
||||
* The default location of the web.xml file. Will be used
|
||||
* if <webAppConfig><descriptor> is not set.
|
||||
*
|
||||
* @parameter expression="${basedir}/src/main/webapp/WEB-INF/web.xml"
|
||||
* @readonly
|
||||
*/
|
||||
private String webXml;
|
||||
|
||||
/**
|
||||
* The target directory
|
||||
*
|
||||
* @parameter expression="${project.build.directory}"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected File target;
|
||||
|
||||
|
||||
/**
|
||||
* The temporary directory to use for the webapp.
|
||||
* Defaults to target/tmp
|
||||
*
|
||||
* @parameter expression="${project.build.directory}/tmp"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
protected File tmpDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* The directory containing generated classes.
|
||||
*
|
||||
* @parameter expression="${project.build.outputDirectory}"
|
||||
* @required
|
||||
*
|
||||
*/
|
||||
private File classesDirectory;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The directory containing generated test classes.
|
||||
*
|
||||
* @parameter expression="${project.build.testOutputDirectory}"
|
||||
* @required
|
||||
*/
|
||||
private File testClassesDirectory;
|
||||
|
||||
/**
|
||||
* Root directory for all html/jsp etc files
|
||||
*
|
||||
* @parameter expression="${basedir}/src/main/webapp"
|
||||
*
|
||||
*/
|
||||
private File webAppSourceDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* Directories that contain static resources
|
||||
* for the webapp. Optional.
|
||||
*
|
||||
* @parameter
|
||||
*/
|
||||
private File[] resourceBases;
|
||||
|
||||
|
||||
/**
|
||||
* If true, the webAppSourceDirectory will be first on the list of
|
||||
* resources that form the resource base for the webapp. If false,
|
||||
* it will be last.
|
||||
*
|
||||
* @parameter default-value="true"
|
||||
*/
|
||||
private boolean baseAppFirst;
|
||||
|
||||
|
||||
/**
|
||||
* Location of jetty xml configuration files whose contents
|
||||
* will be applied before any plugin configuration. Optional.
|
||||
* @parameter
|
||||
*/
|
||||
private String jettyXml;
|
||||
|
||||
/**
|
||||
* The context path for the webapp. Defaults to the
|
||||
* name of the webapp's artifact.
|
||||
*
|
||||
* @parameter expression="/${project.artifactId}"
|
||||
* @required
|
||||
* @readonly
|
||||
*/
|
||||
private String contextPath;
|
||||
|
||||
|
||||
/**
|
||||
* Location of a context xml configuration file whose contents
|
||||
* will be applied to the webapp AFTER anything in <webAppConfig>.Optional.
|
||||
* @parameter
|
||||
*/
|
||||
private String contextXml;
|
||||
|
||||
|
||||
/**
|
||||
* @parameter expression="${jetty.skip}" default-value="false"
|
||||
*/
|
||||
private boolean skip;
|
||||
|
||||
/**
|
||||
* Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort>
|
||||
* -DSTOP.KEY=<stopKey> -jar start.jar --stop
|
||||
* @parameter
|
||||
* @required
|
||||
*/
|
||||
protected int stopPort;
|
||||
|
||||
/**
|
||||
* Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
|
||||
* -DSTOP.PORT=<stopPort> -jar start.jar --stop
|
||||
* @parameter
|
||||
* @required
|
||||
*/
|
||||
protected String stopKey;
|
||||
|
||||
|
||||
/**
|
||||
* Arbitrary jvm args to pass to the forked process
|
||||
* @parameter
|
||||
*/
|
||||
private String jvmArgs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @parameter expression="${plugin.artifacts}"
|
||||
* @readonly
|
||||
*/
|
||||
private List pluginArtifacts;
|
||||
|
||||
|
||||
/**
|
||||
* @parameter expression="${plugin}"
|
||||
* @readonly
|
||||
*/
|
||||
private PluginDescriptor plugin;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @parameter expression="true" default-value="true"
|
||||
*/
|
||||
private boolean waitForChild;
|
||||
|
||||
|
||||
private Process forkedProcess;
|
||||
|
||||
private Random random;
|
||||
|
||||
|
||||
|
||||
public class ShutdownThread extends Thread
|
||||
{
|
||||
public ShutdownThread()
|
||||
{
|
||||
super("RunForkedShutdown");
|
||||
}
|
||||
|
||||
public void run ()
|
||||
{
|
||||
if (forkedProcess != null && waitForChild)
|
||||
{
|
||||
forkedProcess.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.maven.plugin.Mojo#execute()
|
||||
*/
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
getLog().info("Configuring Jetty for project: " + project.getName());
|
||||
if (skip)
|
||||
{
|
||||
getLog().info("Skipping Jetty start: jetty.skip==true");
|
||||
return;
|
||||
}
|
||||
PluginLog.setLog(getLog());
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownThread());
|
||||
random = new Random();
|
||||
startJettyRunner();
|
||||
}
|
||||
|
||||
|
||||
public List<String> getProvidedJars() throws MojoExecutionException
|
||||
{
|
||||
//if we are configured to include the provided dependencies on the plugin's classpath
|
||||
//(which mimics being on jetty's classpath vs being on the webapp's classpath), we first
|
||||
//try and filter out ones that will clash with jars that are plugin dependencies, then
|
||||
//create a new classloader that we setup in the parent chain.
|
||||
if (useProvidedScope)
|
||||
{
|
||||
|
||||
List<String> provided = new ArrayList<String>();
|
||||
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = iter.next();
|
||||
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact))
|
||||
{
|
||||
provided.add(artifact.getFile().getAbsolutePath());
|
||||
if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);}
|
||||
}
|
||||
}
|
||||
return provided;
|
||||
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public File prepareConfiguration() throws MojoExecutionException
|
||||
{
|
||||
try
|
||||
{
|
||||
//work out the configuration based on what is configured in the pom
|
||||
File propsFile = new File (target, "fork.props");
|
||||
if (propsFile.exists())
|
||||
propsFile.delete();
|
||||
|
||||
propsFile.createNewFile();
|
||||
//propsFile.deleteOnExit();
|
||||
|
||||
Properties props = new Properties();
|
||||
|
||||
|
||||
//web.xml
|
||||
if (webXml != null)
|
||||
props.put("web.xml", webXml);
|
||||
|
||||
//sort out the context path
|
||||
if (contextPath != null)
|
||||
props.put("context.path", contextPath);
|
||||
|
||||
//sort out the tmp directory (make it if it doesn't exist)
|
||||
if (tmpDirectory != null)
|
||||
{
|
||||
if (!tmpDirectory.exists())
|
||||
tmpDirectory.mkdirs();
|
||||
props.put("tmp.dir", tmpDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
//sort out base dir of webapp
|
||||
if (webAppSourceDirectory != null)
|
||||
props.put("base.dir", webAppSourceDirectory.getAbsolutePath());
|
||||
|
||||
//sort out the resource base directories of the webapp
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (baseAppFirst)
|
||||
{
|
||||
add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder);
|
||||
if (resourceBases != null)
|
||||
{
|
||||
for (File resDir:resourceBases)
|
||||
add(resDir.getAbsolutePath(), builder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resourceBases != null)
|
||||
{
|
||||
for (File resDir:resourceBases)
|
||||
add(resDir.getAbsolutePath(), builder);
|
||||
}
|
||||
add((webAppSourceDirectory==null?null:webAppSourceDirectory.getAbsolutePath()), builder);
|
||||
}
|
||||
props.put("res.dirs", builder.toString());
|
||||
|
||||
|
||||
//web-inf classes
|
||||
List<File> classDirs = getClassesDirs();
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
for (int i=0; i<classDirs.size(); i++)
|
||||
{
|
||||
File f = classDirs.get(i);
|
||||
strbuff.append(f.getAbsolutePath());
|
||||
if (i < classDirs.size()-1)
|
||||
strbuff.append(",");
|
||||
}
|
||||
|
||||
if (classesDirectory != null)
|
||||
{
|
||||
props.put("classes.dir", classesDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
if (useTestScope && testClassesDirectory != null)
|
||||
{
|
||||
props.put("testClasses.dir", testClassesDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
//web-inf lib
|
||||
List<File> deps = getDependencyFiles();
|
||||
strbuff.setLength(0);
|
||||
for (int i=0; i<deps.size(); i++)
|
||||
{
|
||||
File d = deps.get(i);
|
||||
strbuff.append(d.getAbsolutePath());
|
||||
if (i < deps.size()-1)
|
||||
strbuff.append(",");
|
||||
}
|
||||
props.put("lib.jars", strbuff.toString());
|
||||
|
||||
//any overlays
|
||||
List<File> overlays = getOverlays();
|
||||
strbuff.setLength(0);
|
||||
for (int i=0; i<overlays.size(); i++)
|
||||
{
|
||||
File f = overlays.get(i);
|
||||
strbuff.append(f.getAbsolutePath());
|
||||
if (i < overlays.size()-1)
|
||||
strbuff.append(",");
|
||||
}
|
||||
props.put("overlay.files", strbuff.toString());
|
||||
|
||||
props.store(new BufferedOutputStream(new FileOutputStream(propsFile)), "properties for forked webapp");
|
||||
return propsFile;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MojoExecutionException("Prepare webapp configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void add (String string, StringBuilder builder)
|
||||
{
|
||||
if (string == null)
|
||||
return;
|
||||
if (builder.length() > 0)
|
||||
builder.append(",");
|
||||
builder.append(string);
|
||||
}
|
||||
|
||||
private List<File> getClassesDirs ()
|
||||
{
|
||||
List<File> classesDirs = new ArrayList<File>();
|
||||
|
||||
//if using the test classes, make sure they are first
|
||||
//on the list
|
||||
if (useTestScope && (testClassesDirectory != null))
|
||||
classesDirs.add(testClassesDirectory);
|
||||
|
||||
if (classesDirectory != null)
|
||||
classesDirs.add(classesDirectory);
|
||||
|
||||
return classesDirs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<File> getOverlays()
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
List<File> overlays = new ArrayList<File>();
|
||||
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = (Artifact) iter.next();
|
||||
|
||||
if (artifact.getType().equals("war"))
|
||||
overlays.add(artifact.getFile());
|
||||
}
|
||||
|
||||
return overlays;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<File> getDependencyFiles ()
|
||||
{
|
||||
List<File> dependencyFiles = new ArrayList<File>();
|
||||
|
||||
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = (Artifact) iter.next();
|
||||
|
||||
if (((!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) && (!Artifact.SCOPE_TEST.equals( artifact.getScope())))
|
||||
||
|
||||
(useTestScope && Artifact.SCOPE_TEST.equals( artifact.getScope())))
|
||||
{
|
||||
dependencyFiles.add(artifact.getFile());
|
||||
getLog().debug( "Adding artifact " + artifact.getFile().getName() + " for WEB-INF/lib " );
|
||||
}
|
||||
}
|
||||
|
||||
return dependencyFiles;
|
||||
}
|
||||
|
||||
public boolean isPluginArtifact(Artifact artifact)
|
||||
{
|
||||
if (pluginArtifacts == null || pluginArtifacts.isEmpty())
|
||||
return false;
|
||||
|
||||
boolean isPluginArtifact = false;
|
||||
for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext() && !isPluginArtifact; )
|
||||
{
|
||||
Artifact pluginArtifact = iter.next();
|
||||
if (getLog().isDebugEnabled()) { getLog().debug("Checking "+pluginArtifact);}
|
||||
if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId()))
|
||||
isPluginArtifact = true;
|
||||
}
|
||||
|
||||
return isPluginArtifact;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Set<Artifact> getExtraJars()
|
||||
throws Exception
|
||||
{
|
||||
Set<Artifact> extraJars = new HashSet<Artifact>();
|
||||
|
||||
|
||||
List l = pluginArtifacts;
|
||||
Artifact pluginArtifact = null;
|
||||
|
||||
if (l != null)
|
||||
{
|
||||
Iterator itor = l.iterator();
|
||||
while (itor.hasNext() && pluginArtifact == null)
|
||||
{
|
||||
Artifact a = (Artifact)itor.next();
|
||||
if (a.getArtifactId().equals(plugin.getArtifactId())) //get the jetty-maven-plugin jar
|
||||
{
|
||||
extraJars.add(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return extraJars;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void startJettyRunner() throws MojoExecutionException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
File props = prepareConfiguration();
|
||||
|
||||
List<String> cmd = new ArrayList<String>();
|
||||
cmd.add(getJavaBin());
|
||||
|
||||
if (jvmArgs != null)
|
||||
{
|
||||
String[] args = jvmArgs.split(" ");
|
||||
for (int i=0;args != null && i<args.length;i++)
|
||||
{
|
||||
if (args[i] !=null && !"".equals(args[i]))
|
||||
cmd.add(args[i].trim());
|
||||
}
|
||||
}
|
||||
|
||||
String classPath = getClassPath();
|
||||
if (classPath != null && classPath.length() > 0)
|
||||
{
|
||||
cmd.add("-cp");
|
||||
cmd.add(classPath);
|
||||
}
|
||||
cmd.add(Starter.class.getCanonicalName());
|
||||
|
||||
if (stopPort > 0 && stopKey != null)
|
||||
{
|
||||
cmd.add("--stop-port");
|
||||
cmd.add(Integer.toString(stopPort));
|
||||
cmd.add("--stop-key");
|
||||
cmd.add(stopKey);
|
||||
}
|
||||
if (jettyXml != null)
|
||||
{
|
||||
cmd.add("--jetty-xml");
|
||||
cmd.add(jettyXml);
|
||||
}
|
||||
|
||||
if (contextXml != null)
|
||||
{
|
||||
cmd.add("--context-xml");
|
||||
cmd.add(contextXml);
|
||||
}
|
||||
|
||||
cmd.add("--props");
|
||||
cmd.add(props.getAbsolutePath());
|
||||
|
||||
String token = createToken();
|
||||
cmd.add("--token");
|
||||
cmd.add(token);
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(cmd);
|
||||
builder.directory(project.getBasedir());
|
||||
|
||||
if (PluginLog.getLog().isDebugEnabled())
|
||||
PluginLog.getLog().debug(Arrays.toString(cmd.toArray()));
|
||||
|
||||
forkedProcess = builder.start();
|
||||
PluginLog.getLog().info("Forked process starting");
|
||||
|
||||
if (waitForChild)
|
||||
{
|
||||
startPump("STDOUT",forkedProcess.getInputStream());
|
||||
startPump("STDERR",forkedProcess.getErrorStream());
|
||||
int exitcode = forkedProcess.waitFor();
|
||||
PluginLog.getLog().info("Forked execution exit: "+exitcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
//wait for the child to be ready before terminating.
|
||||
//child indicates it has finished starting by printing on stdout the token passed to it
|
||||
try
|
||||
{
|
||||
LineNumberReader reader = new LineNumberReader(new InputStreamReader(forkedProcess.getInputStream()));
|
||||
String line = null;
|
||||
int attempts = 10; //max lines we'll read trying to get token
|
||||
do
|
||||
{
|
||||
--attempts;
|
||||
line = reader.readLine();
|
||||
if (line != null && line.startsWith(token))
|
||||
break;
|
||||
}
|
||||
while (line != null && attempts>0);
|
||||
reader.close();
|
||||
|
||||
if (line != null && line.trim().equals(token))
|
||||
PluginLog.getLog().info("Forked process started.");
|
||||
else
|
||||
{
|
||||
String err = (line==null?"":line.substring(token.length()));
|
||||
PluginLog.getLog().info("Forked process startup errors "+(!"".equals(err)?":"+err:""));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MojoExecutionException ("Problem determining if forked process is ready: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
if (forkedProcess != null && waitForChild)
|
||||
forkedProcess.destroy();
|
||||
|
||||
throw new MojoExecutionException("Failed to start Jetty within time limit");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (forkedProcess != null && waitForChild)
|
||||
forkedProcess.destroy();
|
||||
|
||||
throw new MojoExecutionException("Failed to create Jetty process", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getClassPath() throws Exception
|
||||
{
|
||||
StringBuilder classPath = new StringBuilder();
|
||||
for (Object obj : pluginArtifacts)
|
||||
{
|
||||
Artifact artifact = (Artifact) obj;
|
||||
if ("jar".equals(artifact.getType()))
|
||||
{
|
||||
if (classPath.length() > 0)
|
||||
{
|
||||
classPath.append(File.pathSeparator);
|
||||
}
|
||||
classPath.append(artifact.getFile().getAbsolutePath());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Any jars that we need from the plugin environment (like the ones containing Starter class)
|
||||
Set<Artifact> extraJars = getExtraJars();
|
||||
for (Artifact a:extraJars)
|
||||
{
|
||||
classPath.append(File.pathSeparator);
|
||||
classPath.append(a.getFile().getAbsolutePath());
|
||||
}
|
||||
|
||||
|
||||
//Any jars that we need from the project's dependencies because we're useProvided
|
||||
List<String> providedJars = getProvidedJars();
|
||||
if (providedJars != null && !providedJars.isEmpty())
|
||||
{
|
||||
for (String jar:providedJars)
|
||||
{
|
||||
classPath.append(File.pathSeparator);
|
||||
classPath.append(jar);
|
||||
if (getLog().isDebugEnabled()) getLog().debug("Adding provided jar: "+jar);
|
||||
}
|
||||
}
|
||||
|
||||
return classPath.toString();
|
||||
}
|
||||
|
||||
private String getJavaBin()
|
||||
{
|
||||
String javaexes[] = new String[]
|
||||
{ "java", "java.exe" };
|
||||
|
||||
File javaHomeDir = new File(System.getProperty("java.home"));
|
||||
for (String javaexe : javaexes)
|
||||
{
|
||||
File javabin = new File(javaHomeDir,fileSeparators("bin/" + javaexe));
|
||||
if (javabin.exists() && javabin.isFile())
|
||||
{
|
||||
return javabin.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
return "java";
|
||||
}
|
||||
|
||||
public static String fileSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (char c : path.toCharArray())
|
||||
{
|
||||
if ((c == '/') || (c == '\\'))
|
||||
{
|
||||
ret.append(File.separatorChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
public static String pathSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (char c : path.toCharArray())
|
||||
{
|
||||
if ((c == ',') || (c == ':'))
|
||||
{
|
||||
ret.append(File.pathSeparatorChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
|
||||
private String createToken ()
|
||||
{
|
||||
return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
private void startPump(String mode, InputStream inputStream)
|
||||
{
|
||||
ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
|
||||
Thread thread = new Thread(pump,"ConsoleStreamer/" + mode);
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple streamer for the console output from a Process
|
||||
*/
|
||||
private static class ConsoleStreamer implements Runnable
|
||||
{
|
||||
private String mode;
|
||||
private BufferedReader reader;
|
||||
|
||||
public ConsoleStreamer(String mode, InputStream is)
|
||||
{
|
||||
this.mode = mode;
|
||||
this.reader = new BufferedReader(new InputStreamReader(is));
|
||||
}
|
||||
|
||||
|
||||
public void run()
|
||||
{
|
||||
String line;
|
||||
try
|
||||
{
|
||||
while ((line = reader.readLine()) != (null))
|
||||
{
|
||||
System.out.println("[" + mode + "] " + line);
|
||||
}
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.close(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,601 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.codehaus.plexus.util.FileUtils;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This goal is used in-situ on a Maven project without first requiring that the project
|
||||
* is assembled into a war, saving time during the development cycle.
|
||||
* The plugin forks a parallel lifecycle to ensure that the "compile" phase has been completed before invoking Jetty. This means
|
||||
* that you do not need to explicity execute a "mvn compile" first. It also means that a "mvn clean jetty:run" will ensure that
|
||||
* a full fresh compile is done before invoking Jetty.
|
||||
* </p>
|
||||
* <p>
|
||||
* Once invoked, the plugin can be configured to run continuously, scanning for changes in the project and automatically performing a
|
||||
* hot redeploy when necessary. This allows the developer to concentrate on coding changes to the project using their IDE of choice and have those changes
|
||||
* immediately and transparently reflected in the running web container, eliminating development time that is wasted on rebuilding, reassembling and redeploying.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration.
|
||||
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
|
||||
* </p>
|
||||
* <p>
|
||||
* There is a <a href="run-mojo.html">reference guide</a> to the configuration parameters for this plugin, and more detailed information
|
||||
* with examples in the <a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin">Configuration Guide</a>.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @goal run
|
||||
* @requiresDependencyResolution test
|
||||
* @execute phase="test-compile"
|
||||
* @description Runs jetty directly from a maven project
|
||||
*/
|
||||
public class JettyRunMojo extends AbstractJettyMojo
|
||||
{
|
||||
/**
|
||||
* If true, the <testOutputDirectory>
|
||||
* and the dependencies of <scope>test<scope>
|
||||
* will be put first on the runtime classpath.
|
||||
*
|
||||
* @parameter alias="useTestClasspath" default-value="false"
|
||||
*/
|
||||
private boolean useTestScope;
|
||||
|
||||
|
||||
/**
|
||||
* The default location of the web.xml file. Will be used
|
||||
* if <webApp><descriptor> is not set.
|
||||
*
|
||||
* @parameter expression="${maven.war.webxml}"
|
||||
* @readonly
|
||||
*/
|
||||
private String webXml;
|
||||
|
||||
|
||||
/**
|
||||
* The directory containing generated classes.
|
||||
*
|
||||
* @parameter expression="${project.build.outputDirectory}"
|
||||
* @required
|
||||
*
|
||||
*/
|
||||
private File classesDirectory;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The directory containing generated test classes.
|
||||
*
|
||||
* @parameter expression="${project.build.testOutputDirectory}"
|
||||
* @required
|
||||
*/
|
||||
private File testClassesDirectory;
|
||||
|
||||
/**
|
||||
* Root directory for all html/jsp etc files
|
||||
*
|
||||
* @parameter expression="${maven.war.src}"
|
||||
*
|
||||
*/
|
||||
private File webAppSourceDirectory;
|
||||
|
||||
|
||||
/**
|
||||
* List of files or directories to additionally periodically scan for changes. Optional.
|
||||
* @parameter
|
||||
*/
|
||||
private File[] scanTargets;
|
||||
|
||||
|
||||
/**
|
||||
* List of directories with ant-style <include> and <exclude> patterns
|
||||
* for extra targets to periodically scan for changes. Can be used instead of,
|
||||
* or in conjunction with <scanTargets>.Optional.
|
||||
* @parameter
|
||||
*/
|
||||
private ScanTargetPattern[] scanTargetPatterns;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extra scan targets as a list
|
||||
*/
|
||||
private List<File> extraScanTargets;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Verify the configuration given in the pom.
|
||||
*
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration()
|
||||
*/
|
||||
public void checkPomConfiguration () throws MojoExecutionException
|
||||
{
|
||||
// check the location of the static content/jsps etc
|
||||
try
|
||||
{
|
||||
if ((getWebAppSourceDirectory() == null) || !getWebAppSourceDirectory().exists())
|
||||
{
|
||||
webAppSourceDirectory = new File (project.getBasedir(), "src"+File.separator+"main"+File.separator+"webapp");
|
||||
getLog().info("webAppSourceDirectory "+getWebAppSourceDirectory() +" does not exist. Defaulting to "+webAppSourceDirectory.getAbsolutePath());
|
||||
}
|
||||
else
|
||||
getLog().info( "Webapp source directory = " + getWebAppSourceDirectory().getCanonicalPath());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MojoExecutionException("Webapp source directory does not exist", e);
|
||||
}
|
||||
|
||||
// check reload mechanic
|
||||
if ( !"automatic".equalsIgnoreCase( reload ) && !"manual".equalsIgnoreCase( reload ) )
|
||||
{
|
||||
throw new MojoExecutionException( "invalid reload mechanic specified, must be 'automatic' or 'manual'" );
|
||||
}
|
||||
else
|
||||
{
|
||||
getLog().info("Reload Mechanic: " + reload );
|
||||
}
|
||||
|
||||
|
||||
// check the classes to form a classpath with
|
||||
try
|
||||
{
|
||||
//allow a webapp with no classes in it (just jsps/html)
|
||||
if (getClassesDirectory() != null)
|
||||
{
|
||||
if (!getClassesDirectory().exists())
|
||||
getLog().info( "Classes directory "+ getClassesDirectory().getCanonicalPath()+ " does not exist");
|
||||
else
|
||||
getLog().info("Classes = " + getClassesDirectory().getCanonicalPath());
|
||||
}
|
||||
else
|
||||
getLog().info("Classes directory not set");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MojoExecutionException("Location of classesDirectory does not exist");
|
||||
}
|
||||
|
||||
|
||||
setExtraScanTargets(new ArrayList<File>());
|
||||
if (scanTargets != null)
|
||||
{
|
||||
for (int i=0; i< scanTargets.length; i++)
|
||||
{
|
||||
getLog().info("Added extra scan target:"+ scanTargets[i]);
|
||||
getExtraScanTargets().add(scanTargets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (scanTargetPatterns!=null)
|
||||
{
|
||||
for (int i=0;i<scanTargetPatterns.length; i++)
|
||||
{
|
||||
Iterator itor = scanTargetPatterns[i].getIncludes().iterator();
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
strbuff.append((String)itor.next());
|
||||
if (itor.hasNext())
|
||||
strbuff.append(",");
|
||||
}
|
||||
String includes = strbuff.toString();
|
||||
|
||||
itor = scanTargetPatterns[i].getExcludes().iterator();
|
||||
strbuff= new StringBuffer();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
strbuff.append((String)itor.next());
|
||||
if (itor.hasNext())
|
||||
strbuff.append(",");
|
||||
}
|
||||
String excludes = strbuff.toString();
|
||||
|
||||
try
|
||||
{
|
||||
List<File> files = FileUtils.getFiles(scanTargetPatterns[i].getDirectory(), includes, excludes);
|
||||
itor = files.iterator();
|
||||
while (itor.hasNext())
|
||||
getLog().info("Adding extra scan target from pattern: "+itor.next());
|
||||
List<File> currentTargets = getExtraScanTargets();
|
||||
if(currentTargets!=null && !currentTargets.isEmpty())
|
||||
currentTargets.addAll(files);
|
||||
else
|
||||
setExtraScanTargets(files);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MojoExecutionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void configureWebApplication() throws Exception
|
||||
{
|
||||
super.configureWebApplication();
|
||||
|
||||
//Set up the location of the webapp.
|
||||
//There are 2 parts to this: setWar() and setBaseResource(). On standalone jetty,
|
||||
//the former could be the location of a packed war, while the latter is the location
|
||||
//after any unpacking. With this mojo, you are running an unpacked, unassembled webapp,
|
||||
//so the two locations should be equal.
|
||||
Resource webAppSourceDirectoryResource = Resource.newResource(webAppSourceDirectory.getCanonicalPath());
|
||||
if (webApp.getWar() == null)
|
||||
webApp.setWar(webAppSourceDirectoryResource.toString());
|
||||
|
||||
if (webApp.getBaseResource() == null)
|
||||
webApp.setBaseResource(webAppSourceDirectoryResource);
|
||||
|
||||
if (getClassesDirectory() != null)
|
||||
webApp.setClasses (getClassesDirectory());
|
||||
if (useTestScope && (testClassesDirectory != null))
|
||||
webApp.setTestClasses (testClassesDirectory);
|
||||
webApp.setWebInfLib (getDependencyFiles());
|
||||
|
||||
|
||||
//if we have not already set web.xml location, need to set one up
|
||||
if (webApp.getDescriptor() == null)
|
||||
{
|
||||
//Has an explicit web.xml file been configured to use?
|
||||
if (webXml != null)
|
||||
{
|
||||
Resource r = Resource.newResource(webXml);
|
||||
if (r.exists() && !r.isDirectory())
|
||||
{
|
||||
webApp.setDescriptor(r.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//Still don't have a web.xml file: try the resourceBase of the webapp, if it is set
|
||||
if (webApp.getDescriptor() == null && webApp.getBaseResource() != null)
|
||||
{
|
||||
Resource r = webApp.getBaseResource().addPath("WEB-INF/web.xml");
|
||||
if (r.exists() && !r.isDirectory())
|
||||
{
|
||||
webApp.setDescriptor(r.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//Still don't have a web.xml file: finally try the configured static resource directory if there is one
|
||||
if (webApp.getDescriptor() == null && (webAppSourceDirectory != null))
|
||||
{
|
||||
File f = new File (new File (webAppSourceDirectory, "WEB-INF"), "web.xml");
|
||||
if (f.exists() && f.isFile())
|
||||
{
|
||||
webApp.setDescriptor(f.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
getLog().info( "web.xml file = "+webApp.getDescriptor());
|
||||
getLog().info("Webapp directory = " + getWebAppSourceDirectory().getCanonicalPath());
|
||||
}
|
||||
|
||||
public void configureScanner ()
|
||||
throws MojoExecutionException
|
||||
{
|
||||
// start the scanner thread (if necessary) on the main webapp
|
||||
final ArrayList<File> scanList = new ArrayList<File>();
|
||||
if (webApp.getDescriptor() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource r = Resource.newResource(webApp.getDescriptor());
|
||||
scanList.add(r.getFile());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MojoExecutionException("Problem configuring scanner for web.xml", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (webApp.getJettyEnvXml() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource r = Resource.newResource(webApp.getJettyEnvXml());
|
||||
scanList.add(r.getFile());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MojoExecutionException("Problem configuring scanner for jetty-env.xml", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (webApp.getDefaultsDescriptor() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!WebAppContext.WEB_DEFAULTS_XML.equals(webApp.getDefaultsDescriptor()))
|
||||
{
|
||||
Resource r = Resource.newResource(webApp.getDefaultsDescriptor());
|
||||
scanList.add(r.getFile());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MojoExecutionException("Problem configuring scanner for webdefaults.xml", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (webApp.getOverrideDescriptor() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource r = Resource.newResource(webApp.getOverrideDescriptor());
|
||||
scanList.add(r.getFile());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new MojoExecutionException("Problem configuring scanner for webdefaults.xml", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File jettyWebXmlFile = findJettyWebXmlFile(new File(getWebAppSourceDirectory(),"WEB-INF"));
|
||||
if (jettyWebXmlFile != null)
|
||||
scanList.add(jettyWebXmlFile);
|
||||
scanList.addAll(getExtraScanTargets());
|
||||
scanList.add(getProject().getFile());
|
||||
if (webApp.getTestClasses() != null)
|
||||
scanList.add(webApp.getTestClasses());
|
||||
if (webApp.getClasses() != null)
|
||||
scanList.add(webApp.getClasses());
|
||||
scanList.addAll(webApp.getWebInfLib());
|
||||
setScanList(scanList);
|
||||
ArrayList<Scanner.BulkListener> listeners = new ArrayList<Scanner.BulkListener>();
|
||||
listeners.add(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged (List changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
|
||||
restartWebApp(reconfigure);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
getLog().error("Error reconfiguring/restarting webapp after change in watched files",e);
|
||||
}
|
||||
}
|
||||
});
|
||||
setScannerListeners(listeners);
|
||||
}
|
||||
|
||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||
{
|
||||
getLog().info("restarting "+webApp);
|
||||
getLog().debug("Stopping webapp ...");
|
||||
webApp.stop();
|
||||
getLog().debug("Reconfiguring webapp ...");
|
||||
|
||||
checkPomConfiguration();
|
||||
configureWebApplication();
|
||||
|
||||
// check if we need to reconfigure the scanner,
|
||||
// which is if the pom changes
|
||||
if (reconfigureScanner)
|
||||
{
|
||||
getLog().info("Reconfiguring scanner after change to pom.xml ...");
|
||||
scanList.clear();
|
||||
scanList.add(new File(webApp.getDescriptor()));
|
||||
if (webApp.getJettyEnvXml() != null)
|
||||
scanList.add(new File(webApp.getJettyEnvXml()));
|
||||
scanList.addAll(getExtraScanTargets());
|
||||
scanList.add(getProject().getFile());
|
||||
if (webApp.getTestClasses() != null)
|
||||
scanList.add(webApp.getTestClasses());
|
||||
if (webApp.getClasses() != null)
|
||||
scanList.add(webApp.getClasses());
|
||||
scanList.addAll(webApp.getWebInfLib());
|
||||
getScanner().setScanDirs(scanList);
|
||||
}
|
||||
|
||||
getLog().debug("Restarting webapp ...");
|
||||
webApp.start();
|
||||
getLog().info("Restart completed at "+new Date().toString());
|
||||
}
|
||||
|
||||
private List<File> getDependencyFiles ()
|
||||
{
|
||||
List<File> dependencyFiles = new ArrayList<File>();
|
||||
List<Resource> overlays = new ArrayList<Resource>();
|
||||
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
|
||||
{
|
||||
Artifact artifact = (Artifact) iter.next();
|
||||
// Include runtime and compile time libraries, and possibly test libs too
|
||||
if(artifact.getType().equals("war"))
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource r=Resource.newResource("jar:"+Resource.toURL(artifact.getFile()).toString()+"!/");
|
||||
overlays.add(r);
|
||||
getExtraScanTargets().add(artifact.getFile());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
|
||||
continue; //never add dependencies of scope=provided to the webapp's classpath (see also <useProvidedScope> param)
|
||||
|
||||
if (Artifact.SCOPE_TEST.equals(artifact.getScope()) && !useTestScope)
|
||||
continue; //only add dependencies of scope=test if explicitly required
|
||||
|
||||
dependencyFiles.add(artifact.getFile());
|
||||
getLog().debug( "Adding artifact " + artifact.getFile().getName() + " with scope "+artifact.getScope()+" for WEB-INF/lib " );
|
||||
}
|
||||
|
||||
webApp.setOverlays(overlays);
|
||||
|
||||
return dependencyFiles;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private List<File> setUpClassPath(File webInfClasses, File testClasses, List<File> webInfJars)
|
||||
{
|
||||
List<File> classPathFiles = new ArrayList<File>();
|
||||
if (webInfClasses != null)
|
||||
classPathFiles.add(webInfClasses);
|
||||
if (testClasses != null)
|
||||
classPathFiles.add(testClasses);
|
||||
classPathFiles.addAll(webInfJars);
|
||||
|
||||
if (getLog().isDebugEnabled())
|
||||
{
|
||||
for (int i = 0; i < classPathFiles.size(); i++)
|
||||
{
|
||||
getLog().debug("classpath element: "+ ((File) classPathFiles.get(i)).getName());
|
||||
}
|
||||
}
|
||||
return classPathFiles;
|
||||
}
|
||||
|
||||
private List<File> getClassesDirs ()
|
||||
{
|
||||
List<File> classesDirs = new ArrayList<File>();
|
||||
|
||||
//if using the test classes, make sure they are first
|
||||
//on the list
|
||||
if (useTestScope && (testClassesDirectory != null))
|
||||
classesDirs.add(testClassesDirectory);
|
||||
|
||||
if (getClassesDirectory() != null)
|
||||
classesDirs.add(getClassesDirectory());
|
||||
|
||||
return classesDirs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
|
||||
super.execute();
|
||||
}
|
||||
|
||||
|
||||
public String getWebXml()
|
||||
{
|
||||
return this.webXml;
|
||||
}
|
||||
|
||||
public void setWebXml(String webXml) {
|
||||
this.webXml = webXml;
|
||||
}
|
||||
|
||||
public File getClassesDirectory()
|
||||
{
|
||||
return this.classesDirectory;
|
||||
}
|
||||
|
||||
public void setClassesDirectory(File classesDirectory) {
|
||||
this.classesDirectory = classesDirectory;
|
||||
}
|
||||
|
||||
public File getWebAppSourceDirectory()
|
||||
{
|
||||
return this.webAppSourceDirectory;
|
||||
}
|
||||
|
||||
public void setWebAppSourceDirectory(File webAppSourceDirectory)
|
||||
{
|
||||
this.webAppSourceDirectory = webAppSourceDirectory;
|
||||
}
|
||||
|
||||
public List<File> getExtraScanTargets()
|
||||
{
|
||||
return this.extraScanTargets;
|
||||
}
|
||||
|
||||
public void setExtraScanTargets(List<File> list)
|
||||
{
|
||||
this.extraScanTargets = list;
|
||||
}
|
||||
|
||||
public boolean isUseTestClasspath()
|
||||
{
|
||||
return useTestScope;
|
||||
}
|
||||
|
||||
public void setUseTestClasspath(boolean useTestClasspath)
|
||||
{
|
||||
this.useTestScope = useTestClasspath;
|
||||
}
|
||||
|
||||
public File getTestClassesDirectory()
|
||||
{
|
||||
return testClassesDirectory;
|
||||
}
|
||||
|
||||
public void setTestClassesDirectory(File testClassesDirectory)
|
||||
{
|
||||
this.testClassesDirectory = testClassesDirectory;
|
||||
}
|
||||
|
||||
public File[] getScanTargets()
|
||||
{
|
||||
return scanTargets;
|
||||
}
|
||||
|
||||
public void setScanTargets(File[] scanTargets)
|
||||
{
|
||||
this.scanTargets = scanTargets;
|
||||
}
|
||||
|
||||
public ScanTargetPattern[] getScanTargetPatterns()
|
||||
{
|
||||
return scanTargetPatterns;
|
||||
}
|
||||
|
||||
public void setScanTargetPatterns(ScanTargetPattern[] scanTargetPatterns)
|
||||
{
|
||||
this.scanTargetPatterns = scanTargetPatterns;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* This goal is used to assemble your webapp into an exploded war and automatically deploy it to Jetty.
|
||||
* </p>
|
||||
* <p>
|
||||
* Once invoked, the plugin can be configured to run continuously, scanning for changes in the pom.xml and
|
||||
* to WEB-INF/web.xml, WEB-INF/classes or WEB-INF/lib and hot redeploy when a change is detected.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration.
|
||||
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
|
||||
* </p>
|
||||
* <p>
|
||||
* There is a <a href="run-exploded-mojo.html">reference guide</a> to the configuration parameters for this plugin, and more detailed information
|
||||
* with examples in the <a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin">Configuration Guide</a>.
|
||||
* </p>
|
||||
*
|
||||
*@goal run-exploded
|
||||
*@requiresDependencyResolution compile+runtime
|
||||
*@execute phase=package
|
||||
*/
|
||||
public class JettyRunWarExplodedMojo extends AbstractJettyMojo
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The location of the war file.
|
||||
*
|
||||
* @parameter alias="webApp" expression="${project.build.directory}/${project.build.finalName}"
|
||||
* @required
|
||||
*/
|
||||
private File war;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration()
|
||||
*/
|
||||
public void checkPomConfiguration() throws MojoExecutionException
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner()
|
||||
*/
|
||||
public void configureScanner() throws MojoExecutionException
|
||||
{
|
||||
final ArrayList<File> scanList = new ArrayList<File>();
|
||||
scanList.add(getProject().getFile());
|
||||
File webInfDir = new File(war,"WEB-INF");
|
||||
scanList.add(new File(webInfDir, "web.xml"));
|
||||
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
|
||||
if (jettyWebXmlFile != null)
|
||||
scanList.add(jettyWebXmlFile);
|
||||
File jettyEnvXmlFile = new File(webInfDir, "jetty-env.xml");
|
||||
if (jettyEnvXmlFile.exists())
|
||||
scanList.add(jettyEnvXmlFile);
|
||||
scanList.add(new File(webInfDir, "classes"));
|
||||
scanList.add(new File(webInfDir, "lib"));
|
||||
setScanList(scanList);
|
||||
|
||||
ArrayList<Scanner.BulkListener> listeners = new ArrayList<Scanner.BulkListener>();
|
||||
listeners.add(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(List changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
|
||||
restartWebApp(reconfigure);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
getLog().error("Error reconfiguring/restarting webapp after change in watched files",e);
|
||||
}
|
||||
}
|
||||
});
|
||||
setScannerListeners(listeners);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||
{
|
||||
getLog().info("Restarting webapp");
|
||||
getLog().debug("Stopping webapp ...");
|
||||
webApp.stop();
|
||||
getLog().debug("Reconfiguring webapp ...");
|
||||
|
||||
checkPomConfiguration();
|
||||
|
||||
// check if we need to reconfigure the scanner,
|
||||
// which is if the pom changes
|
||||
if (reconfigureScanner)
|
||||
{
|
||||
getLog().info("Reconfiguring scanner after change to pom.xml ...");
|
||||
ArrayList<File> scanList = getScanList();
|
||||
scanList.clear();
|
||||
scanList.add(getProject().getFile());
|
||||
File webInfDir = new File(war,"WEB-INF");
|
||||
scanList.add(new File(webInfDir, "web.xml"));
|
||||
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
|
||||
if (jettyWebXmlFile != null)
|
||||
scanList.add(jettyWebXmlFile);
|
||||
File jettyEnvXmlFile = new File(webInfDir, "jetty-env.xml");
|
||||
if (jettyEnvXmlFile.exists())
|
||||
scanList.add(jettyEnvXmlFile);
|
||||
scanList.add(new File(webInfDir, "classes"));
|
||||
scanList.add(new File(webInfDir, "lib"));
|
||||
setScanList(scanList);
|
||||
getScanner().setScanDirs(scanList);
|
||||
}
|
||||
|
||||
getLog().debug("Restarting webapp ...");
|
||||
webApp.start();
|
||||
getLog().info("Restart completed.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void configureWebApplication () throws Exception
|
||||
{
|
||||
super.configureWebApplication();
|
||||
webApp.setWar(war.getCanonicalPath());
|
||||
}
|
||||
|
||||
public void execute () throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
super.execute();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This goal is used to assemble your webapp into a war and automatically deploy it to Jetty.
|
||||
* </p>
|
||||
* <p>
|
||||
* Once invoked, the plugin can be configured to run continuously, scanning for changes in the project and to the
|
||||
* war file and automatically performing a
|
||||
* hot redeploy when necessary.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration.
|
||||
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
|
||||
* </p>
|
||||
* <p>
|
||||
* There is a <a href="run-war-mojo.html">reference guide</a> to the configuration parameters for this plugin, and more detailed information
|
||||
* with examples in the <a href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin/">Configuration Guide</a>.
|
||||
* </p>
|
||||
*
|
||||
* @goal run-war
|
||||
* @requiresDependencyResolution compile+runtime
|
||||
* @execute phase="package"
|
||||
* @description Runs jetty on a war file
|
||||
*
|
||||
*/
|
||||
public class JettyRunWarMojo extends AbstractJettyMojo
|
||||
{
|
||||
|
||||
/**
|
||||
* The location of the war file.
|
||||
* @parameter expression="${project.build.directory}/${project.build.finalName}.war"
|
||||
* @required
|
||||
*/
|
||||
private File war;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.maven.plugin.Mojo#execute()
|
||||
*/
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
super.execute();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void configureWebApplication () throws Exception
|
||||
{
|
||||
super.configureWebApplication();
|
||||
|
||||
webApp.setWar(war.getCanonicalPath());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPomConfiguration()
|
||||
*/
|
||||
public void checkPomConfiguration() throws MojoExecutionException
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.server.plugin.AbstractJettyMojo#configureScanner()
|
||||
*/
|
||||
public void configureScanner() throws MojoExecutionException
|
||||
{
|
||||
final ArrayList scanList = new ArrayList();
|
||||
scanList.add(getProject().getFile());
|
||||
scanList.add(war);
|
||||
setScanList(scanList);
|
||||
|
||||
ArrayList listeners = new ArrayList();
|
||||
listeners.add(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(List changes)
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
|
||||
restartWebApp(reconfigure);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
getLog().error("Error reconfiguring/restarting webapp after change in watched files",e);
|
||||
}
|
||||
}
|
||||
});
|
||||
setScannerListeners(listeners);
|
||||
}
|
||||
|
||||
|
||||
public void restartWebApp(boolean reconfigureScanner) throws Exception
|
||||
{
|
||||
getLog().info("Restarting webapp ...");
|
||||
getLog().debug("Stopping webapp ...");
|
||||
webApp.stop();
|
||||
getLog().debug("Reconfiguring webapp ...");
|
||||
|
||||
checkPomConfiguration();
|
||||
|
||||
// check if we need to reconfigure the scanner,
|
||||
// which is if the pom changes
|
||||
if (reconfigureScanner)
|
||||
{
|
||||
getLog().info("Reconfiguring scanner after change to pom.xml ...");
|
||||
ArrayList scanList = getScanList();
|
||||
scanList.clear();
|
||||
scanList.add(getProject().getFile());
|
||||
scanList.add(war);
|
||||
setScanList(scanList);
|
||||
getScanner().setScanDirs(scanList);
|
||||
}
|
||||
|
||||
getLog().debug("Restarting webapp ...");
|
||||
webApp.start();
|
||||
getLog().info("Restart completed.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* JettyServer
|
||||
*
|
||||
* Maven jetty plugin version of a wrapper for the Server class.
|
||||
*
|
||||
*/
|
||||
public class JettyServer extends org.eclipse.jetty.server.Server
|
||||
{
|
||||
public static int DEFAULT_PORT = 8080;
|
||||
public static int DEFAULT_MAX_IDLE_TIME = 30000;
|
||||
|
||||
|
||||
private RequestLog requestLog;
|
||||
private ContextHandlerCollection contexts;
|
||||
|
||||
|
||||
public JettyServer()
|
||||
{
|
||||
super();
|
||||
setStopAtShutdown(true);
|
||||
//make sure Jetty does not use URLConnection caches with the plugin
|
||||
Resource.setDefaultUseCaches(false);
|
||||
}
|
||||
|
||||
|
||||
public void setRequestLog (RequestLog requestLog)
|
||||
{
|
||||
this.requestLog = requestLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.Server#doStart()
|
||||
*/
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.handler.HandlerCollection#addHandler(org.eclipse.jetty.server.Handler)
|
||||
*/
|
||||
public void addWebApplication(WebAppContext webapp) throws Exception
|
||||
{
|
||||
contexts.addHandler (webapp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up the handler structure to receive a webapp.
|
||||
* Also put in a DefaultHandler so we get a nice page
|
||||
* than a 404 if we hit the root and the webapp's
|
||||
* context isn't at root.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void configureHandlers () throws Exception
|
||||
{
|
||||
DefaultHandler defaultHandler = new DefaultHandler();
|
||||
RequestLogHandler requestLogHandler = new RequestLogHandler();
|
||||
if (this.requestLog != null)
|
||||
requestLogHandler.setRequestLog(this.requestLog);
|
||||
|
||||
contexts = (ContextHandlerCollection)super.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||
if (contexts==null)
|
||||
{
|
||||
contexts = new ContextHandlerCollection();
|
||||
HandlerCollection handlers = (HandlerCollection)super.getChildHandlerByClass(HandlerCollection.class);
|
||||
if (handlers==null)
|
||||
{
|
||||
handlers = new HandlerCollection();
|
||||
super.setHandler(handlers);
|
||||
handlers.setHandlers(new Handler[]{contexts, defaultHandler, requestLogHandler});
|
||||
}
|
||||
else
|
||||
{
|
||||
handlers.addHandler(contexts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public Connector createDefaultConnector(Server server, String portnum) throws Exception
|
||||
{
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server);
|
||||
int port = ((portnum==null||portnum.equals(""))?DEFAULT_PORT:Integer.parseInt(portnum.trim()));
|
||||
connector.setPort(port);
|
||||
connector.setIdleTimeout(DEFAULT_MAX_IDLE_TIME);
|
||||
|
||||
return connector;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This goal is similar to the jetty:run goal, EXCEPT that it is designed to be bound to an execution inside your pom, rather
|
||||
* than being run from the command line.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using it, be careful to ensure that you bind it to a phase in which all necessary generated files and classes for the webapp
|
||||
* will have been created. If you run it from the command line, then also ensure that all necessary generated files and classes for
|
||||
* the webapp already exist.
|
||||
* </p>
|
||||
*
|
||||
* @goal start
|
||||
* @requiresDependencyResolution test
|
||||
* @execute phase="validate"
|
||||
* @description Runs jetty directly from a maven project from a binding to an execution in your pom
|
||||
*/
|
||||
public class JettyStartMojo extends JettyRunMojo
|
||||
{
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
|
||||
/**
|
||||
* JettyStopMojo - stops a running instance of jetty.
|
||||
* The ff are required:
|
||||
* -DstopKey=someKey
|
||||
* -DstopPort=somePort
|
||||
*
|
||||
* @goal stop
|
||||
* @description Stops jetty that is configured with <stopKey> and <stopPort>.
|
||||
*/
|
||||
|
||||
public class JettyStopMojo extends AbstractMojo
|
||||
{
|
||||
|
||||
/**
|
||||
* Port to listen to stop jetty on sending stop command
|
||||
* @parameter
|
||||
* @required
|
||||
*/
|
||||
protected int stopPort;
|
||||
|
||||
/**
|
||||
* Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
|
||||
* -DSTOP.PORT=<stopPort> -jar start.jar --stop
|
||||
* @parameter
|
||||
* @required
|
||||
*/
|
||||
protected String stopKey;
|
||||
|
||||
public void execute() throws MojoExecutionException, MojoFailureException
|
||||
{
|
||||
if (stopPort <= 0)
|
||||
throw new MojoExecutionException("Please specify a valid port");
|
||||
if (stopKey == null)
|
||||
throw new MojoExecutionException("Please specify a valid stopKey");
|
||||
|
||||
try
|
||||
{
|
||||
Socket s=new Socket(InetAddress.getByName("127.0.0.1"),stopPort);
|
||||
s.setSoLinger(false, 0);
|
||||
|
||||
OutputStream out=s.getOutputStream();
|
||||
out.write((stopKey+"\r\nstop\r\n").getBytes());
|
||||
out.flush();
|
||||
s.close();
|
||||
}
|
||||
catch (ConnectException e)
|
||||
{
|
||||
getLog().info("Jetty not running!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
getLog().error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getStopPort() {
|
||||
return stopPort;
|
||||
}
|
||||
|
||||
public void setStopPort(int stopPort) {
|
||||
this.stopPort = stopPort;
|
||||
}
|
||||
|
||||
public String getStopKey() {
|
||||
return stopKey;
|
||||
}
|
||||
|
||||
public void setStopKey(String stopKey) {
|
||||
this.stopKey = stopKey;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,394 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.FragmentConfiguration;
|
||||
import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
|
||||
import org.eclipse.jetty.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.TagLibConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.webapp.WebXmlConfiguration;
|
||||
|
||||
/**
|
||||
* JettyWebAppContext
|
||||
*
|
||||
* Extends the WebAppContext to specialize for the maven environment.
|
||||
* We pass in the list of files that should form the classpath for
|
||||
* the webapp when executing in the plugin, and any jetty-env.xml file
|
||||
* that may have been configured.
|
||||
*
|
||||
*/
|
||||
public class JettyWebAppContext extends WebAppContext
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyWebAppContext.class);
|
||||
|
||||
private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes";
|
||||
private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib";
|
||||
|
||||
private File classes = null;
|
||||
private File testClasses = null;
|
||||
private final List<File> webInfClasses = new ArrayList<File>();
|
||||
private final List<File> webInfJars = new ArrayList<File>();
|
||||
private final Map<String, File> webInfJarMap = new HashMap<String, File>();
|
||||
private final EnvConfiguration envConfig;
|
||||
private List<File> classpathFiles; //webInfClasses+testClasses+webInfJars
|
||||
private String jettyEnvXml;
|
||||
private List<Resource> overlays;
|
||||
|
||||
/**
|
||||
* @deprecated The value of this parameter will be ignored by the plugin. Overlays will always be unpacked.
|
||||
*/
|
||||
private boolean unpackOverlays;
|
||||
|
||||
/**
|
||||
* @deprecated The value of this parameter will be ignored by the plugin. This option will be always disabled.
|
||||
*/
|
||||
private boolean copyWebInf;
|
||||
|
||||
private boolean baseAppFirst = true;
|
||||
|
||||
public JettyWebAppContext ()
|
||||
throws Exception
|
||||
{
|
||||
super();
|
||||
setConfigurations(new Configuration[]{
|
||||
new MavenWebInfConfiguration(),
|
||||
new WebXmlConfiguration(),
|
||||
new MetaInfConfiguration(),
|
||||
new FragmentConfiguration(),
|
||||
envConfig = new EnvConfiguration(),
|
||||
new AnnotationConfiguration(),
|
||||
new org.eclipse.jetty.plus.webapp.PlusConfiguration(),
|
||||
new JettyWebXmlConfiguration(),
|
||||
new TagLibConfiguration()
|
||||
});
|
||||
// Turn off copyWebInf option as it is not applicable for plugin.
|
||||
super.setCopyWebInf(false);
|
||||
}
|
||||
|
||||
public boolean getUnpackOverlays()
|
||||
{
|
||||
return unpackOverlays;
|
||||
}
|
||||
|
||||
public void setUnpackOverlays(boolean unpackOverlays)
|
||||
{
|
||||
this.unpackOverlays = unpackOverlays;
|
||||
}
|
||||
|
||||
public List<File> getClassPathFiles()
|
||||
{
|
||||
return this.classpathFiles;
|
||||
}
|
||||
|
||||
public void setOverlays (List<Resource> overlays)
|
||||
{
|
||||
this.overlays = overlays;
|
||||
}
|
||||
|
||||
public List<Resource> getOverlays ()
|
||||
{
|
||||
return this.overlays;
|
||||
}
|
||||
|
||||
public void setJettyEnvXml (String jettyEnvXml)
|
||||
{
|
||||
this.jettyEnvXml = jettyEnvXml;
|
||||
}
|
||||
|
||||
public String getJettyEnvXml()
|
||||
{
|
||||
return this.jettyEnvXml;
|
||||
}
|
||||
|
||||
|
||||
public void setClasses(File dir)
|
||||
{
|
||||
classes = dir;
|
||||
}
|
||||
|
||||
public File getClasses()
|
||||
{
|
||||
return classes;
|
||||
}
|
||||
|
||||
public void setWebInfLib (List<File> jars)
|
||||
{
|
||||
webInfJars.addAll(jars);
|
||||
}
|
||||
|
||||
|
||||
public void setTestClasses (File dir)
|
||||
{
|
||||
testClasses = dir;
|
||||
}
|
||||
|
||||
|
||||
public File getTestClasses ()
|
||||
{
|
||||
return testClasses;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setCopyWebInf(boolean value)
|
||||
{
|
||||
copyWebInf = value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isCopyWebInf()
|
||||
{
|
||||
return copyWebInf;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setBaseAppFirst(boolean value)
|
||||
{
|
||||
baseAppFirst = value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean getBaseAppFirst()
|
||||
{
|
||||
return baseAppFirst;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* This method is provided as a convenience for jetty maven plugin configuration
|
||||
* @param resourceBases Array of resources strings to set as a {@link ResourceCollection}. Each resource string may be a comma separated list of resources
|
||||
* @see Resource
|
||||
*/
|
||||
public void setResourceBases(String[] resourceBases)
|
||||
{
|
||||
List<String> resources = new ArrayList<String>();
|
||||
for (String rl:resourceBases)
|
||||
{
|
||||
String[] rs = rl.split(" *, *");
|
||||
for (String r:rs)
|
||||
resources.add(r);
|
||||
}
|
||||
|
||||
setBaseResource(new ResourceCollection(resources.toArray(new String[resources.size()])));
|
||||
}
|
||||
|
||||
public List<File> getWebInfLib()
|
||||
{
|
||||
return webInfJars;
|
||||
}
|
||||
|
||||
public void doStart () throws Exception
|
||||
{
|
||||
//Set up the pattern that tells us where the jars are that need scanning for
|
||||
//stuff like taglibs so we can tell jasper about it (see TagLibConfiguration)
|
||||
String tmp = (String)getAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern");
|
||||
|
||||
tmp = addPattern(tmp, ".*/.*jsp-api-[^/]*\\.jar$");
|
||||
tmp = addPattern(tmp, ".*/.*jsp-[^/]*\\.jar$");
|
||||
tmp = addPattern(tmp, ".*/.*taglibs[^/]*\\.jar$");
|
||||
tmp = addPattern(tmp, ".*/.*jstl[^/]*\\.jar$");
|
||||
tmp = addPattern(tmp, ".*/.*jsf-impl-[^/]*\\.jar$"); // add in 2 most popular jsf impls
|
||||
tmp = addPattern(tmp, ".*/.*javax.faces-[^/]*\\.jar$");
|
||||
tmp = addPattern(tmp, ".*/.*myfaces-impl-[^/]*\\.jar$");
|
||||
|
||||
setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", tmp);
|
||||
|
||||
//Set up the classes dirs that comprises the equivalent of WEB-INF/classes
|
||||
if (testClasses != null)
|
||||
webInfClasses.add(testClasses);
|
||||
if (classes != null)
|
||||
webInfClasses.add(classes);
|
||||
|
||||
// Set up the classpath
|
||||
classpathFiles = new ArrayList<File>();
|
||||
classpathFiles.addAll(webInfClasses);
|
||||
classpathFiles.addAll(webInfJars);
|
||||
|
||||
|
||||
// Initialize map containing all jars in /WEB-INF/lib
|
||||
webInfJarMap.clear();
|
||||
for (File file : webInfJars)
|
||||
{
|
||||
// Return all jar files from class path
|
||||
String fileName = file.getName();
|
||||
if (fileName.endsWith(".jar"))
|
||||
webInfJarMap.put(fileName, file);
|
||||
}
|
||||
|
||||
if (this.jettyEnvXml != null)
|
||||
envConfig.setJettyEnvXml(Resource.toURL(new File(this.jettyEnvXml)));
|
||||
|
||||
//setShutdown(false);
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
public void doStop () throws Exception
|
||||
{
|
||||
//setShutdown(true);
|
||||
//just wait a little while to ensure no requests are still being processed
|
||||
Thread.currentThread().sleep(500L);
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String uriInContext) throws MalformedURLException
|
||||
{
|
||||
Resource resource = null;
|
||||
// Try to get regular resource
|
||||
resource = super.getResource(uriInContext);
|
||||
|
||||
// If no regular resource exists check for access to /WEB-INF/lib or /WEB-INF/classes
|
||||
if ((resource == null || !resource.exists()) && uriInContext != null && classes != null)
|
||||
{
|
||||
String uri = URIUtil.canonicalPath(uriInContext);
|
||||
if (uri == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Replace /WEB-INF/classes with candidates for the classpath
|
||||
if (uri.startsWith(WEB_INF_CLASSES_PREFIX))
|
||||
{
|
||||
if (uri.equalsIgnoreCase(WEB_INF_CLASSES_PREFIX) || uri.equalsIgnoreCase(WEB_INF_CLASSES_PREFIX+"/"))
|
||||
{
|
||||
//exact match for a WEB-INF/classes, so preferentially return the resource matching the web-inf classes
|
||||
//rather than the test classes
|
||||
if (classes != null)
|
||||
return Resource.newResource(classes);
|
||||
else if (testClasses != null)
|
||||
return Resource.newResource(testClasses);
|
||||
}
|
||||
else
|
||||
{
|
||||
//try matching
|
||||
Resource res = null;
|
||||
int i=0;
|
||||
while (res == null && (i < webInfClasses.size()))
|
||||
{
|
||||
String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath());
|
||||
res = Resource.newResource(newPath);
|
||||
if (!res.exists())
|
||||
{
|
||||
res = null;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else if (uri.startsWith(WEB_INF_LIB_PREFIX))
|
||||
{
|
||||
// Return the real jar file for all accesses to
|
||||
// /WEB-INF/lib/*.jar
|
||||
String jarName = uri.replace(WEB_INF_LIB_PREFIX, "");
|
||||
if (jarName.startsWith("/") || jarName.startsWith("\\"))
|
||||
jarName = jarName.substring(1);
|
||||
if (jarName.length()==0)
|
||||
return null;
|
||||
File jarFile = webInfJarMap.get(jarName);
|
||||
if (jarFile != null)
|
||||
return Resource.newResource(jarFile.getPath());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResourcePaths(String path)
|
||||
{
|
||||
// Try to get regular resource paths
|
||||
Set<String> paths = super.getResourcePaths(path);
|
||||
|
||||
// If no paths are returned check for virtual paths /WEB-INF/classes and /WEB-INF/lib
|
||||
if (paths.isEmpty() && path != null)
|
||||
{
|
||||
path = URIUtil.canonicalPath(path);
|
||||
if (path.startsWith(WEB_INF_LIB_PREFIX))
|
||||
{
|
||||
paths = new TreeSet<String>();
|
||||
for (String fileName : webInfJarMap.keySet())
|
||||
{
|
||||
// Return all jar files from class path
|
||||
paths.add(WEB_INF_LIB_PREFIX + "/" + fileName);
|
||||
}
|
||||
}
|
||||
else if (path.startsWith(WEB_INF_CLASSES_PREFIX))
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (paths.isEmpty() && (i < webInfClasses.size()))
|
||||
{
|
||||
String newPath = path.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath());
|
||||
paths = super.getResourcePaths(newPath);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
public String addPattern (String s, String pattern)
|
||||
{
|
||||
if (s == null)
|
||||
s = "";
|
||||
else
|
||||
s = s.trim();
|
||||
|
||||
if (!s.contains(pattern))
|
||||
{
|
||||
if (s.length() != 0)
|
||||
s = s + "|";
|
||||
s = s + pattern;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.webapp.WebAppClassLoader;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.webapp.WebInfConfiguration;
|
||||
|
||||
public class MavenWebInfConfiguration extends WebInfConfiguration
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MavenWebInfConfiguration.class);
|
||||
|
||||
protected Resource _originalResourceBase;
|
||||
protected Resource[] _unpackedOverlays;
|
||||
|
||||
|
||||
public void configure(WebAppContext context) throws Exception
|
||||
{
|
||||
JettyWebAppContext jwac = (JettyWebAppContext)context;
|
||||
if (jwac.getClassPathFiles() != null)
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Setting up classpath ...");
|
||||
|
||||
//put the classes dir and all dependencies into the classpath
|
||||
Iterator itor = jwac.getClassPathFiles().iterator();
|
||||
while (itor.hasNext())
|
||||
((WebAppClassLoader)context.getClassLoader()).addClassPath(((File)itor.next()).getCanonicalPath());
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Classpath = "+((URLClassLoader)context.getClassLoader()).getURLs());
|
||||
}
|
||||
super.configure(context);
|
||||
|
||||
// knock out environmental maven and plexus classes from webAppContext
|
||||
String[] existingServerClasses = context.getServerClasses();
|
||||
String[] newServerClasses = new String[2+(existingServerClasses==null?0:existingServerClasses.length)];
|
||||
newServerClasses[0] = "org.apache.maven.";
|
||||
newServerClasses[1] = "org.codehaus.plexus.";
|
||||
System.arraycopy( existingServerClasses, 0, newServerClasses, 2, existingServerClasses.length );
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Server classes:");
|
||||
for (int i=0;i<newServerClasses.length;i++)
|
||||
LOG.debug(newServerClasses[i]);
|
||||
}
|
||||
context.setServerClasses( newServerClasses );
|
||||
}
|
||||
|
||||
|
||||
public void preConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
super.preConfigure(context);
|
||||
|
||||
_originalResourceBase = context.getBaseResource();
|
||||
JettyWebAppContext jwac = (JettyWebAppContext)context;
|
||||
|
||||
//Add in any overlaid wars as base resources
|
||||
if (jwac.getOverlays() != null && !jwac.getOverlays().isEmpty())
|
||||
{
|
||||
Resource[] origResources = null;
|
||||
int origSize = 0;
|
||||
|
||||
if (jwac.getBaseResource() != null)
|
||||
{
|
||||
if (jwac.getBaseResource() instanceof ResourceCollection)
|
||||
{
|
||||
origResources = ((ResourceCollection)jwac.getBaseResource()).getResources();
|
||||
origSize = origResources.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
origResources = new Resource[1];
|
||||
origResources[0] = jwac.getBaseResource();
|
||||
origSize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int overlaySize = jwac.getOverlays().size();
|
||||
Resource[] newResources = new Resource[origSize + overlaySize];
|
||||
|
||||
int offset = 0;
|
||||
if (origSize > 0)
|
||||
{
|
||||
if (jwac.getBaseAppFirst())
|
||||
{
|
||||
System.arraycopy(origResources,0,newResources,0,origSize);
|
||||
|
||||
offset = origSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.arraycopy(origResources,0,newResources,overlaySize,origSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Overlays are always unpacked
|
||||
_unpackedOverlays = new Resource[overlaySize];
|
||||
List<Resource> overlays = jwac.getOverlays();
|
||||
for (int idx=0; idx<overlaySize; idx++)
|
||||
{
|
||||
_unpackedOverlays[idx] = unpackOverlay(context, overlays.get(idx));
|
||||
newResources[idx+offset] = _unpackedOverlays[idx];
|
||||
|
||||
LOG.info("Adding overlay: " + _unpackedOverlays[idx]);
|
||||
}
|
||||
|
||||
jwac.setBaseResource(new ResourceCollection(newResources));
|
||||
}
|
||||
}
|
||||
|
||||
public void postConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
super.postConfigure(context);
|
||||
}
|
||||
|
||||
|
||||
public void deconfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
JettyWebAppContext jwac = (JettyWebAppContext)context;
|
||||
|
||||
//remove the unpacked wars
|
||||
if (_unpackedOverlays != null && _unpackedOverlays.length>0)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i=0; i<_unpackedOverlays.length; i++)
|
||||
{
|
||||
IO.delete(_unpackedOverlays[i].getFile());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
super.deconfigure(context);
|
||||
//restore whatever the base resource was before we might have included overlaid wars
|
||||
context.setBaseResource(_originalResourceBase);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the jars to examine from the files from which we have
|
||||
* synthesized the classpath. Note that the classpath is not
|
||||
* set at this point, so we cannot get them from the classpath.
|
||||
* @param context
|
||||
* @return the list of jars found
|
||||
*/
|
||||
protected List<Resource> findJars (WebAppContext context)
|
||||
throws Exception
|
||||
{
|
||||
List<Resource> list = new ArrayList<Resource>();
|
||||
JettyWebAppContext jwac = (JettyWebAppContext)context;
|
||||
if (jwac.getClassPathFiles() != null)
|
||||
{
|
||||
for (File f: jwac.getClassPathFiles())
|
||||
{
|
||||
if (f.getName().toLowerCase().endsWith(".jar"))
|
||||
{
|
||||
try
|
||||
{
|
||||
list.add(Resource.newResource(f.toURI()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Bad url ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Resource> superList = super.findJars(context);
|
||||
if (superList != null)
|
||||
list.addAll(superList);
|
||||
return list;
|
||||
}
|
||||
|
||||
protected Resource unpackOverlay (WebAppContext context, Resource overlay)
|
||||
throws IOException
|
||||
{
|
||||
//resolve if not already resolved
|
||||
resolveTempDirectory(context);
|
||||
|
||||
|
||||
//Get the name of the overlayed war and unpack it to a dir of the
|
||||
//same name in the temporary directory
|
||||
String name = overlay.getName();
|
||||
if (name.endsWith("!/"))
|
||||
name = name.substring(0,name.length()-2);
|
||||
int i = name.lastIndexOf('/');
|
||||
if (i>0)
|
||||
name = name.substring(i+1,name.length());
|
||||
name = name.replace('.', '_');
|
||||
File dir = new File(context.getTempDirectory(), name);
|
||||
overlay.copyTo(dir);
|
||||
Resource unpackedOverlay = Resource.newResource(dir.getCanonicalPath());
|
||||
return unpackedOverlay;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Monitor
|
||||
*
|
||||
* Listens for stop commands eg via mvn jetty:stop and
|
||||
* causes jetty to stop either by exiting the jvm, or
|
||||
* by stopping the Server instances. The choice of
|
||||
* behaviour is controlled by either passing true
|
||||
* (exit jvm) or false (stop Servers) in the constructor.
|
||||
*
|
||||
*/
|
||||
public class Monitor extends Thread
|
||||
{
|
||||
private String _key;
|
||||
private Server[] _servers;
|
||||
|
||||
ServerSocket _serverSocket;
|
||||
boolean _kill;
|
||||
|
||||
public Monitor(int port, String key, Server[] servers, boolean kill)
|
||||
throws UnknownHostException, IOException
|
||||
{
|
||||
if (port <= 0)
|
||||
throw new IllegalStateException ("Bad stop port");
|
||||
if (key==null)
|
||||
throw new IllegalStateException("Bad stop key");
|
||||
|
||||
_key = key;
|
||||
_servers = servers;
|
||||
_kill = kill;
|
||||
setDaemon(true);
|
||||
setName("StopJettyPluginMonitor");
|
||||
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
||||
_serverSocket=new ServerSocket();
|
||||
_serverSocket.setReuseAddress(true);
|
||||
try
|
||||
{
|
||||
_serverSocket.bind(address,1);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
System.out.println("Error binding to stop port 127.0.0.1:"+port);
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while (_serverSocket != null)
|
||||
{
|
||||
Socket socket = null;
|
||||
try
|
||||
{
|
||||
socket = _serverSocket.accept();
|
||||
socket.setSoLinger(false, 0);
|
||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String key = lin.readLine();
|
||||
if (!_key.equals(key)) continue;
|
||||
String cmd = lin.readLine();
|
||||
if ("stop".equals(cmd))
|
||||
{
|
||||
try{socket.close();}catch (Exception e){e.printStackTrace();}
|
||||
try{socket.close();}catch (Exception e){e.printStackTrace();}
|
||||
try{_serverSocket.close();}catch (Exception e){e.printStackTrace();}
|
||||
|
||||
_serverSocket = null;
|
||||
|
||||
if (_kill)
|
||||
{
|
||||
System.out.println("Killing Jetty");
|
||||
System.exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; _servers != null && i < _servers.length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("Stopping server "+i);
|
||||
_servers[i].stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
System.out.println("Unsupported monitor operation");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
|
||||
/**
|
||||
* PluginLog
|
||||
*
|
||||
* Convenience class to provide access to the plugin
|
||||
* Log for non-mojo classes.
|
||||
*
|
||||
*/
|
||||
public class PluginLog
|
||||
{
|
||||
private static Log log = null;
|
||||
|
||||
public static void setLog(Log l)
|
||||
{
|
||||
log = l;
|
||||
}
|
||||
|
||||
public static Log getLog()
|
||||
{
|
||||
return log;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ScanTargetPattern
|
||||
*
|
||||
* Utility class to provide the ability for the mvn jetty:run
|
||||
* mojo to be able to specify filesets of extra files to
|
||||
* regularly scan for changes in order to redeploy the webapp.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* <scanTargetPattern>
|
||||
* <directory>/some/place</directory>
|
||||
* <includes>
|
||||
* <include>some ant pattern here </include>
|
||||
* <include>some ant pattern here </include>
|
||||
* </includes>
|
||||
* <excludes>
|
||||
* <exclude>some ant pattern here </exclude>
|
||||
* <exclude>some ant pattern here </exclude>
|
||||
* </excludes>
|
||||
* </scanTargetPattern>
|
||||
*/
|
||||
public class ScanTargetPattern
|
||||
{
|
||||
private File _directory;
|
||||
private List _includes = Collections.EMPTY_LIST;
|
||||
private List _excludes = Collections.EMPTY_LIST;
|
||||
|
||||
/**
|
||||
* @return the _directory
|
||||
*/
|
||||
public File getDirectory()
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param directory the directory to set
|
||||
*/
|
||||
public void setDirectory(File directory)
|
||||
{
|
||||
this._directory = directory;
|
||||
}
|
||||
|
||||
public void setIncludes (List includes)
|
||||
{
|
||||
_includes= includes;
|
||||
}
|
||||
|
||||
public void setExcludes(List excludes)
|
||||
{
|
||||
_excludes = excludes;
|
||||
}
|
||||
|
||||
public List getIncludes()
|
||||
{
|
||||
return _includes;
|
||||
}
|
||||
|
||||
public List getExcludes()
|
||||
{
|
||||
return _excludes;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
public class Starter
|
||||
{
|
||||
public static final String PORT_SYSPROPERTY = "jetty.port";
|
||||
private static final Logger LOG = Log.getLogger(Starter.class);
|
||||
|
||||
private List<File> jettyXmls; // list of jetty.xml config files to apply - Mandatory
|
||||
private File contextXml; //name of context xml file to configure the webapp - Mandatory
|
||||
|
||||
private JettyServer server;
|
||||
private JettyWebAppContext webApp;
|
||||
private Monitor monitor;
|
||||
|
||||
private int stopPort=0;
|
||||
private String stopKey=null;
|
||||
private Properties props;
|
||||
private String token;
|
||||
|
||||
|
||||
|
||||
public void configureJetty () throws Exception
|
||||
{
|
||||
LOG.debug("Starting Jetty Server ...");
|
||||
|
||||
this.server = new JettyServer();
|
||||
|
||||
//apply any configs from jetty.xml files first
|
||||
applyJettyXml ();
|
||||
|
||||
// if the user hasn't configured a connector in the jetty.xml
|
||||
//then use a default
|
||||
Connector[] connectors = this.server.getConnectors();
|
||||
if (connectors == null|| connectors.length == 0)
|
||||
{
|
||||
//if a SystemProperty -Djetty.port=<portnum> has been supplied, use that as the default port
|
||||
connectors = new Connector[] { this.server.createDefaultConnector(server, System.getProperty(PORT_SYSPROPERTY, null)) };
|
||||
this.server.setConnectors(connectors);
|
||||
}
|
||||
|
||||
//check that everything got configured, and if not, make the handlers
|
||||
HandlerCollection handlers = (HandlerCollection) server.getChildHandlerByClass(HandlerCollection.class);
|
||||
if (handlers == null)
|
||||
{
|
||||
handlers = new HandlerCollection();
|
||||
server.setHandler(handlers);
|
||||
}
|
||||
|
||||
//check if contexts already configured, create if not
|
||||
this.server.configureHandlers();
|
||||
|
||||
webApp = new JettyWebAppContext();
|
||||
|
||||
//configure webapp from properties file describing unassembled webapp
|
||||
configureWebApp();
|
||||
|
||||
//set up the webapp from the context xml file provided
|
||||
//NOTE: just like jetty:run mojo this means that the context file can
|
||||
//potentially override settings made in the pom. Ideally, we'd like
|
||||
//the pom to override the context xml file, but as the other mojos all
|
||||
//configure a WebAppContext in the pom (the <webApp> element), it is
|
||||
//already configured by the time the context xml file is applied.
|
||||
if (contextXml != null)
|
||||
{
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(contextXml));
|
||||
xmlConfiguration.getIdMap().put("Server",server);
|
||||
xmlConfiguration.configure(webApp);
|
||||
}
|
||||
|
||||
this.server.addWebApplication(webApp);
|
||||
|
||||
System.err.println("STOP PORT="+stopPort+", STOP KEY="+stopKey);
|
||||
if(stopPort>0 && stopKey!=null)
|
||||
{
|
||||
monitor = new Monitor(stopPort, stopKey, new Server[]{server}, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void configureWebApp ()
|
||||
throws Exception
|
||||
{
|
||||
if (props == null)
|
||||
return;
|
||||
|
||||
//apply a properties file that defines the things that we configure in the jetty:run plugin:
|
||||
// - the context path
|
||||
String str = (String)props.get("context.path");
|
||||
if (str != null)
|
||||
webApp.setContextPath(str);
|
||||
|
||||
// - web.xml
|
||||
str = (String)props.get("web.xml");
|
||||
if (str != null)
|
||||
webApp.setDescriptor(str);
|
||||
|
||||
// - the tmp directory
|
||||
str = (String)props.getProperty("tmp.dir");
|
||||
if (str != null)
|
||||
webApp.setTempDirectory(new File(str.trim()));
|
||||
|
||||
// - the base directory
|
||||
str = (String)props.getProperty("base.dir");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
webApp.setWar(str);
|
||||
|
||||
// - the multiple comma separated resource dirs
|
||||
str = (String)props.getProperty("res.dirs");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
{
|
||||
ResourceCollection resources = new ResourceCollection(str);
|
||||
webApp.setBaseResource(resources);
|
||||
}
|
||||
|
||||
// - overlays
|
||||
str = (String)props.getProperty("overlay.files");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
{
|
||||
List<Resource> overlays = new ArrayList<Resource>();
|
||||
String[] names = str.split(",");
|
||||
for (int j=0; names != null && j < names.length; j++)
|
||||
overlays.add(Resource.newResource("jar:"+Resource.toURL(new File(names[j].trim())).toString()+"!/"));
|
||||
webApp.setOverlays(overlays);
|
||||
}
|
||||
|
||||
// - the equivalent of web-inf classes
|
||||
str = (String)props.getProperty("classes.dir");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
{
|
||||
webApp.setClasses(new File(str));
|
||||
}
|
||||
|
||||
str = (String)props.getProperty("testClasses.dir");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
{
|
||||
webApp.setTestClasses(new File(str));
|
||||
}
|
||||
|
||||
|
||||
// - the equivalent of web-inf lib
|
||||
str = (String)props.getProperty("lib.jars");
|
||||
if (str != null && !"".equals(str.trim()))
|
||||
{
|
||||
List<File> jars = new ArrayList<File>();
|
||||
String[] names = str.split(",");
|
||||
for (int j=0; names != null && j < names.length; j++)
|
||||
jars.add(new File(names[j].trim()));
|
||||
webApp.setWebInfLib(jars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void getConfiguration (String[] args)
|
||||
throws Exception
|
||||
{
|
||||
for (int i=0; i<args.length; i++)
|
||||
{
|
||||
//--stop-port
|
||||
if ("--stop-port".equals(args[i]))
|
||||
stopPort = Integer.parseInt(args[++i]);
|
||||
|
||||
//--stop-key
|
||||
if ("--stop-key".equals(args[i]))
|
||||
stopKey = args[++i];
|
||||
|
||||
//--jettyXml
|
||||
if ("--jetty-xml".equals(args[i]))
|
||||
{
|
||||
jettyXmls = new ArrayList<File>();
|
||||
String[] names = args[++i].split(",");
|
||||
for (int j=0; names!= null && j < names.length; j++)
|
||||
{
|
||||
jettyXmls.add(new File(names[j].trim()));
|
||||
}
|
||||
}
|
||||
|
||||
//--context-xml
|
||||
if ("--context-xml".equals(args[i]))
|
||||
{
|
||||
contextXml = new File(args[++i]);
|
||||
}
|
||||
|
||||
//--props
|
||||
if ("--props".equals(args[i]))
|
||||
{
|
||||
File f = new File(args[++i].trim());
|
||||
props = new Properties();
|
||||
props.load(new FileInputStream(f));
|
||||
}
|
||||
|
||||
//--token
|
||||
if ("--token".equals(args[i]))
|
||||
{
|
||||
token = args[++i].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void run() throws Exception
|
||||
{
|
||||
if (monitor != null)
|
||||
monitor.start();
|
||||
|
||||
LOG.info("Started Jetty Server");
|
||||
server.start();
|
||||
}
|
||||
|
||||
|
||||
public void join () throws Exception
|
||||
{
|
||||
server.join();
|
||||
}
|
||||
|
||||
|
||||
public void communicateStartupResult (Exception e)
|
||||
{
|
||||
if (token != null)
|
||||
{
|
||||
if (e==null)
|
||||
System.out.println(token);
|
||||
else
|
||||
System.out.println(token+"\t"+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void applyJettyXml() throws Exception
|
||||
{
|
||||
if (jettyXmls == null)
|
||||
return;
|
||||
|
||||
for ( File xmlFile : jettyXmls )
|
||||
{
|
||||
LOG.info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() );
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile));
|
||||
xmlConfiguration.configure(this.server);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected void prependHandler (Handler handler, HandlerCollection handlers)
|
||||
{
|
||||
if (handler == null || handlers == null)
|
||||
return;
|
||||
|
||||
Handler[] existing = handlers.getChildHandlers();
|
||||
Handler[] children = new Handler[existing.length + 1];
|
||||
children[0] = handler;
|
||||
System.arraycopy(existing, 0, children, 1, existing.length);
|
||||
handlers.setHandlers(children);
|
||||
}
|
||||
|
||||
|
||||
public static final void main(String[] args)
|
||||
{
|
||||
if (args == null)
|
||||
System.exit(1);
|
||||
|
||||
Starter starter = null;
|
||||
try
|
||||
{
|
||||
starter = new Starter();
|
||||
starter.getConfiguration(args);
|
||||
starter.configureJetty();
|
||||
starter.run();
|
||||
starter.communicateStartupResult(null);
|
||||
starter.join();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
starter.communicateStartupResult(e);
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SystemProperties
|
||||
*
|
||||
* Map of name to SystemProperty.
|
||||
*
|
||||
* When a SystemProperty instance is added, if it has not
|
||||
* been already set (eg via the command line java system property)
|
||||
* then it will be set.
|
||||
*/
|
||||
public class SystemProperties
|
||||
{
|
||||
Map properties;
|
||||
boolean force;
|
||||
|
||||
public SystemProperties()
|
||||
{
|
||||
properties = new HashMap();
|
||||
}
|
||||
|
||||
public void setForce (boolean force)
|
||||
{
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
public boolean getForce ()
|
||||
{
|
||||
return this.force;
|
||||
}
|
||||
|
||||
|
||||
public void setSystemProperty (SystemProperty prop)
|
||||
{
|
||||
properties.put(prop.getName(), prop);
|
||||
if (!force)
|
||||
prop.setIfNotSetAlready();
|
||||
else
|
||||
prop.setAnyway();
|
||||
}
|
||||
|
||||
public SystemProperty getSystemProperty(String name)
|
||||
{
|
||||
return (SystemProperty)properties.get(name);
|
||||
}
|
||||
|
||||
public boolean containsSystemProperty(String name)
|
||||
{
|
||||
return properties.containsKey(name);
|
||||
}
|
||||
|
||||
public List getSystemProperties ()
|
||||
{
|
||||
return new ArrayList(properties.values());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
/**
|
||||
* SystemProperty
|
||||
*
|
||||
* Provides the ability to set System properties
|
||||
* for the mojo execution. A value will only
|
||||
* be set if it is not set already. That is, if
|
||||
* it was set on the command line or by the system,
|
||||
* it won't be overridden by settings in the
|
||||
* plugin's configuration.
|
||||
*
|
||||
*/
|
||||
public class SystemProperty
|
||||
{
|
||||
|
||||
|
||||
private String name;
|
||||
private String value;
|
||||
private boolean isSet;
|
||||
|
||||
/**
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
/**
|
||||
* @param name The name to set.
|
||||
*/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getKey()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setKey (String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* @return Returns the value.
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
/**
|
||||
* @param value The value to set.
|
||||
*/
|
||||
public void setValue(String value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSet ()
|
||||
{
|
||||
return isSet;
|
||||
}
|
||||
|
||||
/** Set a System.property with this value
|
||||
* if it is not already set.
|
||||
*/
|
||||
void setIfNotSetAlready()
|
||||
{
|
||||
if (System.getProperty(getName()) == null)
|
||||
{
|
||||
System.setProperty(getName(), (getValue()==null?"":getValue()));
|
||||
isSet=true;
|
||||
}
|
||||
}
|
||||
|
||||
void setAnyway()
|
||||
{
|
||||
System.setProperty(getName(), (getValue()==null?"":getValue()));
|
||||
isSet=true;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue