JETTY-846 Support maven-war-plugin overlay configuration with jetty:run

This commit is contained in:
Jan Bartel 2012-11-19 12:06:26 +11:00
parent ccd35efd2c
commit fe773d22e1
13 changed files with 1825 additions and 784 deletions

View File

@ -54,11 +54,17 @@ import org.eclipse.jetty.xml.XmlConfiguration;
/**
* AbstractJettyMojo
*
*
* Common base class for most jetty mojos.
*
*
*/
public abstract class AbstractJettyMojo extends AbstractMojo
{
/**
*
*/
public String PORT_SYSPROPERTY = "jetty.port";
/**
* Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope>
@ -79,7 +85,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
protected String[] excludedGoals;
/**
* List of connectors to use. If none are configured
* then the default is a single SelectChannelConnector at port 8080. You can
@ -114,7 +119,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
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.
@ -126,7 +130,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
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
@ -138,32 +141,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
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
@ -184,6 +161,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
* @parameter expression="${jetty.reload}" default-value="automatic"
*/
protected String reload;
/**
* File containing system properties to be set before execution
@ -196,6 +174,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
*/
protected File systemPropertiesFile;
/**
* System properties to set before execution.
* Note that these properties will NOT override System properties
@ -207,7 +186,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
protected SystemProperties systemProperties;
/**
* Comma separated list of a jetty xml configuration files whose contents
* will be applied before any plugin configuration. Optional.
@ -226,6 +204,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
*/
protected int stopPort;
/**
* Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
* -DSTOP.PORT=<stopPort> -jar start.jar --stop
@ -234,6 +213,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
*/
protected String stopKey;
/**
* <p>
* Determines whether or not the server blocks when started. The default
@ -250,6 +230,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
*/
protected boolean daemon;
/**
* Skip this mojo execution.
*
@ -290,8 +271,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
* @parameter expression="${mojoExecution}"
* @readonly
*/
private org.apache.maven.plugin.MojoExecution execution;
protected org.apache.maven.plugin.MojoExecution execution;
/**
@ -300,8 +280,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
* @parameter expression="${plugin.artifacts}"
* @readonly
*/
private List pluginArtifacts;
protected List pluginArtifacts;
/**
@ -309,16 +288,19 @@ public abstract class AbstractJettyMojo extends AbstractMojo
*/
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
*/
@ -329,14 +311,17 @@ public abstract class AbstractJettyMojo extends AbstractMojo
* 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 checkPomConfiguration() throws MojoExecutionException;
public abstract void configureScanner () throws MojoExecutionException;
@ -344,9 +329,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
/**
* @see org.apache.maven.plugin.Mojo#execute()
*/
public void execute() throws MojoExecutionException, MojoFailureException
{
getLog().info("Configuring Jetty for project: " + getProject().getName());
getLog().info("Configuring Jetty for project: " + this.project.getName());
if (skip)
{
getLog().info("Skipping Jetty start: jetty.skip==true");
@ -367,6 +355,11 @@ public abstract class AbstractJettyMojo extends AbstractMojo
}
/**
* @throws MojoExecutionException
*/
public void configurePluginClasspath() throws MojoExecutionException
{
//if we are configured to include the provided dependencies on the plugin's classpath
@ -407,6 +400,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
}
/**
* @param artifact
* @return
*/
public boolean isPluginArtifact(Artifact artifact)
{
if (pluginArtifacts == null || pluginArtifacts.isEmpty())
@ -424,6 +423,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
return isPluginArtifact;
}
/**
* @throws Exception
*/
public void finishConfigurationBeforeStart() throws Exception
{
HandlerCollection contexts = (HandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class);
@ -439,6 +444,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
/**
* @throws Exception
*/
public void applyJettyXml() throws Exception
{
if (getJettyXmlFiles() == null)
@ -454,6 +462,10 @@ public abstract class AbstractJettyMojo extends AbstractMojo
/**
* @throws MojoExecutionException
*/
public void startJetty () throws MojoExecutionException
{
try
@ -462,13 +474,10 @@ public abstract class AbstractJettyMojo extends AbstractMojo
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 ();
applyJettyXml ();
// if the user hasn't configured their project's pom to use a
// different set of connectors,
@ -488,10 +497,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
}
}
//set up a RequestLog if one is provided
if (this.requestLog != null)
getServer().setRequestLog(this.requestLog);
this.server.setRequestLog(this.requestLog);
//set up the webapp and any context provided
this.server.configureHandlers();
@ -502,7 +510,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
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]);
this.server.addBean(this.loginServices[i]);
}
//do any other configuration required by the
@ -543,12 +551,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
{
getLog().info("Jetty server exiting.");
}
}
}
}
/**
* Subclasses should invoke this to setup basic info
* on the webapp
@ -571,22 +579,23 @@ public abstract class AbstractJettyMojo extends AbstractMojo
getLog().info("Applying context xml file "+contextXml);
xmlConfiguration.configure(webApp);
}
//If no contextPath was specified, go with our default
//If no contextPath was specified, go with default of project artifactid
String cp = webApp.getContextPath();
if (cp == null || "".equals(cp))
{
webApp.setContextPath((contextPath.startsWith("/") ? contextPath : "/"+ contextPath));
}
cp = "/"+project.getArtifactId();
webApp.setContextPath(cp);
}
//If no tmp directory was specified, and we have one, use it
if (webApp.getTempDirectory() == null && tmpDirectory != null)
if (webApp.getTempDirectory() == null)
{
if (!tmpDirectory.exists())
tmpDirectory.mkdirs();
webApp.setTempDirectory(tmpDirectory);
File target = new File(project.getBuild().getDirectory());
File tmp = new File(target,"tmp");
if (!tmp.exists())
tmp.mkdirs();
webApp.setTempDirectory(tmp);
}
getLog().info("Context path = " + webApp.getContextPath());
@ -595,6 +604,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
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
@ -604,7 +616,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo
private void startScanner() throws Exception
{
// check if scanning is enabled
if (getScanIntervalSeconds() <= 0) return;
if (scanIntervalSeconds <= 0) return;
// check if reload is manual. It disables file scanning
if ( "manual".equalsIgnoreCase( reload ) )
@ -617,17 +629,19 @@ public abstract class AbstractJettyMojo extends AbstractMojo
scanner = new Scanner();
scanner.setReportExistingFilesOnStartup(false);
scanner.setScanInterval(getScanIntervalSeconds());
scanner.setScanDirs(getScanList());
scanner.setScanInterval(scanIntervalSeconds);
scanner.setScanDirs(scanList);
scanner.setRecursive(true);
List listeners = getScannerListeners();
Iterator itor = (listeners==null?null:listeners.iterator());
Iterator itor = (this.scannerListeners==null?null:this.scannerListeners.iterator());
while (itor!=null && itor.hasNext())
scanner.addListener((Scanner.Listener)itor.next());
getLog().info("Starting scanner at interval of " + getScanIntervalSeconds()+ " seconds.");
getLog().info("Starting scanner at interval of " + scanIntervalSeconds + " seconds.");
scanner.start();
}
/**
* Run a thread that monitors the console input to detect ENTER hits.
*/
@ -641,6 +655,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
}
}
/**
*
*/
private void printSystemProperties ()
{
// print out which system properties were set up
@ -658,6 +678,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo
}
}
/**
* Try and find a jetty-web.xml file, using some
* historical naming conventions if necessary.
@ -684,61 +707,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
}
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.
* @param file
* @throws Exception
*/
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;
@ -760,10 +734,15 @@ public abstract class AbstractJettyMojo extends AbstractMojo
this.systemProperties.setSystemProperty(prop);
}
}
}
}
/**
* @param systemProperties
*/
public void setSystemProperties(SystemProperties systemProperties)
{
if (this.systemProperties == null)
@ -778,12 +757,16 @@ public abstract class AbstractJettyMojo extends AbstractMojo
}
}
}
public SystemProperties getSystemProperties ()
{
return this.systemProperties;
}
/**
* @return
*/
public List<File> getJettyXmlFiles()
{
if ( this.jettyXml == null )
@ -810,170 +793,12 @@ public abstract class AbstractJettyMojo extends AbstractMojo
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;
}
/**
* @param goal
* @return
*/
public boolean isExcluded (String goal)
{
if (excludedGoals == null || goal == null)

View File

@ -20,11 +20,26 @@ package org.eclipse.jetty.maven.plugin;
import java.io.IOException;
/**
* ConsoleScanner
*
* Read input from stdin
*/
public class ConsoleScanner extends Thread
{
private final AbstractJettyMojo mojo;
/**
* @param mojo
*/
public ConsoleScanner(AbstractJettyMojo mojo)
{
this.mojo = mojo;
@ -32,6 +47,12 @@ public class ConsoleScanner extends Thread
setDaemon(true);
}
/**
* @see java.lang.Thread#run()
*/
public void run()
{
try
@ -48,6 +69,12 @@ public class ConsoleScanner extends Thread
}
}
/**
*
*/
private void getSomeSleep()
{
try
@ -60,6 +87,12 @@ public class ConsoleScanner extends Thread
}
}
/**
* @throws IOException
*/
private void checkSystemInput() throws IOException
{
while (System.in.available() > 0) {
@ -75,6 +108,8 @@ public class ConsoleScanner extends Thread
}
/**
* Skip buffered bytes of system console.
*/
@ -101,6 +136,12 @@ public class ConsoleScanner extends Thread
}
}
/**
*
*/
private void restartWebApp()
{
try

View File

@ -18,33 +18,24 @@
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.Locale;
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;
@ -52,10 +43,7 @@ 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;
/**
@ -104,7 +92,6 @@ public class JettyRunForkedMojo extends AbstractMojo
* @readonly
*/
private MavenProject project;
/**
@ -125,6 +112,7 @@ public class JettyRunForkedMojo extends AbstractMojo
*/
private String webXml;
/**
* The target directory
*
@ -153,8 +141,7 @@ public class JettyRunForkedMojo extends AbstractMojo
* @required
*
*/
private File classesDirectory;
private File classesDirectory;
/**
@ -164,6 +151,7 @@ public class JettyRunForkedMojo extends AbstractMojo
* @required
*/
private File testClassesDirectory;
/**
* Root directory for all html/jsp etc files
@ -171,17 +159,8 @@ public class JettyRunForkedMojo extends AbstractMojo
* @parameter expression="${basedir}/src/main/webapp"
*
*/
private File webAppSourceDirectory;
/**
* Directories that contain static resources
* for the webapp. Optional.
*
* @parameter
*/
private File[] resourceBases;
private File webAppSourceDirectory;
/**
* If true, the webAppSourceDirectory will be first on the list of
@ -201,12 +180,9 @@ public class JettyRunForkedMojo extends AbstractMojo
private String jettyXml;
/**
* The context path for the webapp. Defaults to the
* name of the webapp's artifact.
* The context path for the webapp. Defaults to / for jetty-9
*
* @parameter expression="/${project.artifactId}"
* @required
* @readonly
* @parameter expression="/"
*/
private String contextPath;
@ -224,6 +200,7 @@ public class JettyRunForkedMojo extends AbstractMojo
*/
private boolean skip;
/**
* Port to listen to stop jetty on executing -DSTOP.PORT=&lt;stopPort&gt;
* -DSTOP.KEY=&lt;stopKey&gt; -jar start.jar --stop
@ -231,6 +208,7 @@ public class JettyRunForkedMojo extends AbstractMojo
* @required
*/
protected int stopPort;
/**
* Key to provide when stopping jetty on executing java -DSTOP.KEY=&lt;stopKey&gt;
@ -246,7 +224,6 @@ public class JettyRunForkedMojo extends AbstractMojo
* @parameter
*/
private String jvmArgs;
/**
@ -263,19 +240,33 @@ public class JettyRunForkedMojo extends AbstractMojo
private PluginDescriptor plugin;
/**
* @parameter expression="true" default-value="true"
*/
private boolean waitForChild;
/**
* The forked jetty instance
*/
private Process forkedProcess;
private Random random;
/**
* Random number generator
*/
private Random random;
/**
* ShutdownThread
*
*
*/
public class ShutdownThread extends Thread
{
public ShutdownThread()
@ -292,6 +283,51 @@ public class JettyRunForkedMojo extends AbstractMojo
}
}
/**
* ConsoleStreamer
*
* 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);
}
}
}
/**
* @see org.apache.maven.plugin.Mojo#execute()
*/
@ -310,6 +346,12 @@ public class JettyRunForkedMojo extends AbstractMojo
}
/**
* @return
* @throws MojoExecutionException
*/
public List<String> getProvidedJars() throws MojoExecutionException
{
//if we are configured to include the provided dependencies on the plugin's classpath
@ -336,7 +378,13 @@ public class JettyRunForkedMojo extends AbstractMojo
return null;
}
/* ------------------------------------------------------------ */
/**
* @return
* @throws MojoExecutionException
*/
public File prepareConfiguration() throws MojoExecutionException
{
try
@ -371,29 +419,10 @@ public class JettyRunForkedMojo extends AbstractMojo
//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());
StringBuilder builder = new StringBuilder();
props.put("base.first", Boolean.toString(baseAppFirst));
//web-inf classes
List<File> classDirs = getClassesDirs();
@ -428,18 +457,34 @@ public class JettyRunForkedMojo extends AbstractMojo
}
props.put("lib.jars", strbuff.toString());
//any overlays
List<File> overlays = getOverlays();
strbuff.setLength(0);
for (int i=0; i<overlays.size(); i++)
//any war files
List<Artifact> warArtifacts = getWarArtifacts();
for (int i=0; i<warArtifacts.size(); i++)
{
File f = overlays.get(i);
strbuff.append(f.getAbsolutePath());
if (i < overlays.size()-1)
strbuff.append(",");
strbuff.setLength(0);
Artifact a = warArtifacts.get(i);
strbuff.append(a.getGroupId()+",");
strbuff.append(a.getArtifactId()+",");
strbuff.append(a.getFile().getAbsolutePath());
props.put("maven.war.artifact."+i, strbuff.toString());
}
props.put("overlay.files", strbuff.toString());
//any overlay configuration
WarPluginInfo warPlugin = new WarPluginInfo(project);
//add in the war plugins default includes and excludes
props.put("maven.war.includes", toCSV(warPlugin.getDependentMavenWarIncludes()));
props.put("maven.war.excludes", toCSV(warPlugin.getDependentMavenWarExcludes()));
List<OverlayConfig> configs = warPlugin.getMavenWarOverlayConfigs();
int i=0;
for (OverlayConfig c:configs)
{
props.put("maven.war.overlay."+(i++), c.toString());
}
props.store(new BufferedOutputStream(new FileOutputStream(propsFile)), "properties for forked webapp");
return propsFile;
}
@ -449,15 +494,12 @@ public class JettyRunForkedMojo extends AbstractMojo
}
}
private void add (String string, StringBuilder builder)
{
if (string == null)
return;
if (builder.length() > 0)
builder.append(",");
builder.append(string);
}
/**
* @return
*/
private List<File> getClassesDirs ()
{
List<File> classesDirs = new ArrayList<File>();
@ -474,24 +516,34 @@ public class JettyRunForkedMojo extends AbstractMojo
}
private List<File> getOverlays()
/**
* @return
* @throws MalformedURLException
* @throws IOException
*/
private List<Artifact> getWarArtifacts()
throws MalformedURLException, IOException
{
List<File> overlays = new ArrayList<File>();
List<Artifact> warArtifacts = new ArrayList<Artifact>();
for ( Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
if (artifact.getType().equals("war"))
overlays.add(artifact.getFile());
warArtifacts.add(artifact);
}
return overlays;
return warArtifacts;
}
/**
* @return
*/
private List<File> getDependencyFiles ()
{
List<File> dependencyFiles = new ArrayList<File>();
@ -512,6 +564,13 @@ public class JettyRunForkedMojo extends AbstractMojo
return dependencyFiles;
}
/**
* @param artifact
* @return
*/
public boolean isPluginArtifact(Artifact artifact)
{
if (pluginArtifacts == null || pluginArtifacts.isEmpty())
@ -531,7 +590,12 @@ public class JettyRunForkedMojo extends AbstractMojo
private Set<Artifact> getExtraJars()
/**
* @return
* @throws Exception
*/
private Set<Artifact> getExtraJars()
throws Exception
{
Set<Artifact> extraJars = new HashSet<Artifact>();
@ -557,7 +621,11 @@ public class JettyRunForkedMojo extends AbstractMojo
}
/* ------------------------------------------------------------ */
/**
* @throws MojoExecutionException
*/
public void startJettyRunner() throws MojoExecutionException
{
try
@ -678,7 +746,12 @@ public class JettyRunForkedMojo extends AbstractMojo
}
/**
* @return
* @throws Exception
*/
public String getClassPath() throws Exception
{
StringBuilder classPath = new StringBuilder();
@ -720,6 +793,12 @@ public class JettyRunForkedMojo extends AbstractMojo
return classPath.toString();
}
/**
* @return
*/
private String getJavaBin()
{
String javaexes[] = new String[]
@ -738,6 +817,13 @@ public class JettyRunForkedMojo extends AbstractMojo
return "java";
}
/**
* @param path
* @return
*/
public static String fileSeparators(String path)
{
StringBuilder ret = new StringBuilder();
@ -755,6 +841,13 @@ public class JettyRunForkedMojo extends AbstractMojo
return ret.toString();
}
/**
* @param path
* @return
*/
public static String pathSeparators(String path)
{
StringBuilder ret = new StringBuilder();
@ -772,13 +865,24 @@ public class JettyRunForkedMojo extends AbstractMojo
return ret.toString();
}
/**
* @return
*/
private String createToken ()
{
return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH);
}
/**
* @param mode
* @param inputStream
*/
private void startPump(String mode, InputStream inputStream)
{
ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
@ -787,42 +891,25 @@ public class JettyRunForkedMojo extends AbstractMojo
thread.start();
}
/**
* Simple streamer for the console output from a Process
* @param strings
* @return
*/
private static class ConsoleStreamer implements Runnable
private String toCSV (List<String> strings)
{
private String mode;
private BufferedReader reader;
public ConsoleStreamer(String mode, InputStream is)
if (strings == null)
return "";
StringBuffer strbuff = new StringBuffer();
Iterator<String> itor = strings.iterator();
while (itor.hasNext())
{
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);
}
strbuff.append(itor.next());
if (itor.hasNext())
strbuff.append(",");
}
return strbuff.toString();
}
}

View File

@ -20,10 +20,13 @@ package org.eclipse.jetty.maven.plugin;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
@ -33,6 +36,7 @@ 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
@ -66,6 +70,7 @@ public class JettyRunMojo extends AbstractJettyMojo
public static final String DEFAULT_WEBAPP_SRC = "src"+File.separator+"main"+File.separator+"webapp";
/**
* If true, the &lt;testOutputDirectory&gt;
* and the dependencies of &lt;scope&gt;test&lt;scope&gt;
@ -73,7 +78,7 @@ public class JettyRunMojo extends AbstractJettyMojo
*
* @parameter alias="useTestClasspath" default-value="false"
*/
private boolean useTestScope;
protected boolean useTestScope;
/**
@ -83,7 +88,7 @@ public class JettyRunMojo extends AbstractJettyMojo
* @parameter expression="${maven.war.webxml}"
* @readonly
*/
private String webXml;
protected String webXml;
/**
@ -93,8 +98,7 @@ public class JettyRunMojo extends AbstractJettyMojo
* @required
*
*/
private File classesDirectory;
protected File classesDirectory;
/**
@ -103,7 +107,8 @@ public class JettyRunMojo extends AbstractJettyMojo
* @parameter expression="${project.build.testOutputDirectory}"
* @required
*/
private File testClassesDirectory;
protected File testClassesDirectory;
/**
* Root directory for all html/jsp etc files
@ -111,14 +116,14 @@ public class JettyRunMojo extends AbstractJettyMojo
* @parameter expression="${maven.war.src}"
*
*/
private File webAppSourceDirectory;
protected File webAppSourceDirectory;
/**
* List of files or directories to additionally periodically scan for changes. Optional.
* @parameter
*/
private File[] scanTargets;
protected File[] scanTargets;
/**
@ -127,15 +132,40 @@ public class JettyRunMojo extends AbstractJettyMojo
* or in conjunction with &lt;scanTargets&gt;.Optional.
* @parameter
*/
private ScanTargetPattern[] scanTargetPatterns;
protected ScanTargetPattern[] scanTargetPatterns;
/**
* Extra scan targets as a list
*/
private List<File> extraScanTargets;
protected List<File> extraScanTargets;
/**
* maven-war-plugin reference
*/
protected WarPluginInfo warPluginInfo;
/**
* List of deps that are wars
*/
protected List<Artifact> warArtifacts;
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute()
*/
@Override
public void execute() throws MojoExecutionException, MojoFailureException
{
warPluginInfo = new WarPluginInfo(project);
super.execute();
}
@ -150,14 +180,14 @@ public class JettyRunMojo extends AbstractJettyMojo
// check the location of the static content/jsps etc
try
{
if ((getWebAppSourceDirectory() == null) || !getWebAppSourceDirectory().exists())
if ((webAppSourceDirectory == null) || !webAppSourceDirectory.exists())
{
File defaultWebAppSrcDir = new File (project.getBasedir(), DEFAULT_WEBAPP_SRC);
getLog().info("webAppSourceDirectory"+(getWebAppSourceDirectory()==null?" not set.":" does not exist.")+" Defaulting to "+defaultWebAppSrcDir.getAbsolutePath());
getLog().info("webAppSourceDirectory"+(webAppSourceDirectory == null ? " not set." : " does not exist.")+" Defaulting to "+defaultWebAppSrcDir.getAbsolutePath());
webAppSourceDirectory = defaultWebAppSrcDir;
}
else
getLog().info( "Webapp source directory = " + getWebAppSourceDirectory().getCanonicalPath());
getLog().info( "Webapp source directory = " + webAppSourceDirectory.getCanonicalPath());
}
catch (IOException e)
{
@ -179,12 +209,12 @@ public class JettyRunMojo extends AbstractJettyMojo
try
{
//allow a webapp with no classes in it (just jsps/html)
if (getClassesDirectory() != null)
if (classesDirectory != null)
{
if (!getClassesDirectory().exists())
getLog().info( "Classes directory "+ getClassesDirectory().getCanonicalPath()+ " does not exist");
if (!classesDirectory.exists())
getLog().info( "Classes directory "+ classesDirectory.getCanonicalPath()+ " does not exist");
else
getLog().info("Classes = " + getClassesDirectory().getCanonicalPath());
getLog().info("Classes = " + classesDirectory.getCanonicalPath());
}
else
getLog().info("Classes directory not set");
@ -194,18 +224,16 @@ public class JettyRunMojo extends AbstractJettyMojo
throw new MojoExecutionException("Location of classesDirectory does not exist");
}
setExtraScanTargets(new ArrayList<File>());
extraScanTargets = 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]);
extraScanTargets.add(scanTargets[i]);
}
}
if (scanTargetPatterns!=null)
{
for (int i=0;i<scanTargetPatterns.length; i++)
@ -236,11 +264,11 @@ public class JettyRunMojo extends AbstractJettyMojo
itor = files.iterator();
while (itor.hasNext())
getLog().info("Adding extra scan target from pattern: "+itor.next());
List<File> currentTargets = getExtraScanTargets();
List<File> currentTargets = extraScanTargets;
if(currentTargets!=null && !currentTargets.isEmpty())
currentTargets.addAll(files);
else
setExtraScanTargets(files);
extraScanTargets = files;
}
catch (IOException e)
{
@ -253,7 +281,9 @@ public class JettyRunMojo extends AbstractJettyMojo
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication()
*/
public void configureWebApplication() throws Exception
{
super.configureWebApplication();
@ -270,13 +300,61 @@ public class JettyRunMojo extends AbstractJettyMojo
if (webApp.getBaseResource() == null)
webApp.setBaseResource(webAppSourceDirectoryResource);
if (getClassesDirectory() != null)
webApp.setClasses (getClassesDirectory());
if (classesDirectory != null)
webApp.setClasses (classesDirectory);
if (useTestScope && (testClassesDirectory != null))
webApp.setTestClasses (testClassesDirectory);
webApp.setWebInfLib (getDependencyFiles());
//get copy of a list of war artifacts
Set<Artifact> matchedWarArtifacts = new HashSet<Artifact>();
//make sure each of the war artifacts is added to the scanner
for (Artifact a:getWarArtifacts())
extraScanTargets.add(a.getFile());
//process any overlays and the war type artifacts
List<Overlay> overlays = new ArrayList<Overlay>();
for (OverlayConfig config:warPluginInfo.getMavenWarOverlayConfigs())
{
//overlays can be individually skipped
if (config.isSkip())
continue;
//an empty overlay refers to the current project - important for ordering
if (config.isCurrentProject())
{
Overlay overlay = new Overlay(config, null);
overlays.add(overlay);
continue;
}
//if a war matches an overlay config
Artifact a = getArtifactForOverlay(config, getWarArtifacts());
if (a != null)
{
matchedWarArtifacts.add(a);
SelectiveJarResource r = new SelectiveJarResource(new URL("jar:"+Resource.toURL(a.getFile()).toString()+"!/"));
r.setIncludes(config.getIncludes());
r.setExcludes(config.getExcludes());
Overlay overlay = new Overlay(config, r);
overlays.add(overlay);
}
}
//iterate over the left over war artifacts and unpack them (without include/exclude processing) as necessary
for (Artifact a: getWarArtifacts())
{
if (!matchedWarArtifacts.contains(a))
{
Overlay overlay = new Overlay(null, Resource.newResource(new URL("jar:"+Resource.toURL(a.getFile()).toString()+"!/")));
overlays.add(overlay);
}
}
webApp.setOverlays(overlays);
//if we have not already set web.xml location, need to set one up
if (webApp.getDescriptor() == null)
{
@ -311,14 +389,20 @@ public class JettyRunMojo extends AbstractJettyMojo
}
}
getLog().info( "web.xml file = "+webApp.getDescriptor());
getLog().info("Webapp directory = " + getWebAppSourceDirectory().getCanonicalPath());
getLog().info("Webapp directory = " + webAppSourceDirectory.getCanonicalPath());
}
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner()
*/
public void configureScanner ()
throws MojoExecutionException
{
// start the scanner thread (if necessary) on the main webapp
final ArrayList<File> scanList = new ArrayList<File>();
scanList = new ArrayList<File>();
if (webApp.getDescriptor() != null)
{
try
@ -375,25 +459,25 @@ public class JettyRunMojo extends AbstractJettyMojo
}
File jettyWebXmlFile = findJettyWebXmlFile(new File(getWebAppSourceDirectory(),"WEB-INF"));
File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory,"WEB-INF"));
if (jettyWebXmlFile != null)
scanList.add(jettyWebXmlFile);
scanList.addAll(getExtraScanTargets());
scanList.add(getProject().getFile());
scanList.addAll(extraScanTargets);
scanList.add(project.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()
scannerListeners = new ArrayList<Scanner.BulkListener>();
scannerListeners.add(new Scanner.BulkListener()
{
public void filesChanged (List changes)
{
try
{
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
restartWebApp(reconfigure);
}
catch (Exception e)
@ -402,9 +486,14 @@ public class JettyRunMojo extends AbstractJettyMojo
}
}
});
setScannerListeners(listeners);
}
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
*/
public void restartWebApp(boolean reconfigureScanner) throws Exception
{
getLog().info("restarting "+webApp);
@ -424,14 +513,14 @@ public class JettyRunMojo extends AbstractJettyMojo
scanList.add(new File(webApp.getDescriptor()));
if (webApp.getJettyEnvXml() != null)
scanList.add(new File(webApp.getJettyEnvXml()));
scanList.addAll(getExtraScanTargets());
scanList.add(getProject().getFile());
scanList.addAll(extraScanTargets);
scanList.add(project.getFile());
if (webApp.getTestClasses() != null)
scanList.add(webApp.getTestClasses());
if (webApp.getClasses() != null)
scanList.add(webApp.getClasses());
scanList.addAll(webApp.getWebInfLib());
getScanner().setScanDirs(scanList);
scanner.setScanDirs(scanList);
}
getLog().debug("Restarting webapp ...");
@ -439,10 +528,15 @@ public class JettyRunMojo extends AbstractJettyMojo
getLog().info("Restart completed at "+new Date().toString());
}
/**
* @return
*/
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();
@ -450,17 +544,6 @@ public class JettyRunMojo extends AbstractJettyMojo
// 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);
getLog().info("Adding overlay for war project artifact "+artifact.getId());
getExtraScanTargets().add(artifact.getFile());
}
catch(Exception e)
{
throw new RuntimeException(e);
}
continue;
}
@ -473,136 +556,79 @@ public class JettyRunMojo extends AbstractJettyMojo
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)
/**
* @return
*/
private List<Artifact> getWarArtifacts ()
{
List<File> classPathFiles = new ArrayList<File>();
if (webInfClasses != null)
classPathFiles.add(webInfClasses);
if (testClasses != null)
classPathFiles.add(testClasses);
classPathFiles.addAll(webInfJars);
if (getLog().isDebugEnabled())
if (warArtifacts != null)
return warArtifacts;
warArtifacts = new ArrayList<Artifact>();
for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
{
for (int i = 0; i < classPathFiles.size(); i++)
Artifact artifact = (Artifact) iter.next();
if (artifact.getType().equals("war"))
{
getLog().debug("classpath element: "+ ((File) classPathFiles.get(i)).getName());
try
{
warArtifacts.add(artifact);
getLog().info("Dependent war artifact "+artifact.getId());
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
}
return classPathFiles;
return warArtifacts;
}
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;
}
/**
* @param o
* @param warArtifacts
* @return
*/
protected Artifact getArtifactForOverlay (OverlayConfig o, List<Artifact> warArtifacts)
{
if (o == null || warArtifacts == null || warArtifacts.isEmpty())
return null;
for (Artifact a:warArtifacts)
{
if (overlayMatchesArtifact (o, a))
{
return a;
}
}
return null;
}
/**
* @param o
* @param a
* @return
*/
protected boolean overlayMatchesArtifact(OverlayConfig o, Artifact a)
{
if (((o.getGroupId() == null && a.getGroupId() == null) || (o.getGroupId() != null && o.getGroupId().equals(a.getGroupId())))
&& ((o.getArtifactId() == null && a.getArtifactId() == null) || (o.getArtifactId() != null && o.getArtifactId().equals(a.getArtifactId())))
&& ((o.getClassifier() == null) || (o.getClassifier().equals(a.getClassifier()))))
return true;
return false;
}
}

View File

@ -67,7 +67,17 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute()
*/
public void execute () throws MojoExecutionException, MojoFailureException
{
super.execute();
}
/**
*
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
@ -77,13 +87,16 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
return;
}
/**
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#configureScanner()
*/
public void configureScanner() throws MojoExecutionException
{
final ArrayList<File> scanList = new ArrayList<File>();
scanList.add(getProject().getFile());
scanList = new ArrayList<File>();
scanList.add(project.getFile());
File webInfDir = new File(war,"WEB-INF");
scanList.add(new File(webInfDir, "web.xml"));
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
@ -94,16 +107,15 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
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()
scannerListeners = new ArrayList<Scanner.BulkListener>();
scannerListeners.add(new Scanner.BulkListener()
{
public void filesChanged(List changes)
{
try
{
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
restartWebApp(reconfigure);
}
catch (Exception e)
@ -112,12 +124,14 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
}
}
});
setScannerListeners(listeners);
}
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
*/
public void restartWebApp(boolean reconfigureScanner) throws Exception
{
getLog().info("Restarting webapp");
@ -132,9 +146,8 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
if (reconfigureScanner)
{
getLog().info("Reconfiguring scanner after change to pom.xml ...");
ArrayList<File> scanList = getScanList();
scanList.clear();
scanList.add(getProject().getFile());
scanList.add(project.getFile());
File webInfDir = new File(war,"WEB-INF");
scanList.add(new File(webInfDir, "web.xml"));
File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
@ -145,8 +158,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
scanList.add(jettyEnvXmlFile);
scanList.add(new File(webInfDir, "classes"));
scanList.add(new File(webInfDir, "lib"));
setScanList(scanList);
getScanner().setScanDirs(scanList);
scanner.setScanDirs(scanList);
}
getLog().debug("Restarting webapp ...");
@ -155,19 +167,14 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo
}
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication()
*/
public void configureWebApplication () throws Exception
{
super.configureWebApplication();
webApp.setWar(war.getCanonicalPath());
}
public void execute () throws MojoExecutionException, MojoFailureException
{
super.execute();
}
}

View File

@ -64,7 +64,6 @@ public class JettyRunWarMojo extends AbstractJettyMojo
*/
private File war;
/**
* @see org.apache.maven.plugin.Mojo#execute()
@ -76,6 +75,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo
public void configureWebApplication () throws Exception
{
super.configureWebApplication();
@ -85,6 +85,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo
/**
* @see org.mortbay.jetty.plugin.AbstractJettyMojo#checkPomConfiguration()
*/
@ -95,24 +96,24 @@ public class JettyRunWarMojo extends AbstractJettyMojo
/* (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 = new ArrayList();
scanList.add(project.getFile());
scanList.add(war);
setScanList(scanList);
ArrayList listeners = new ArrayList();
listeners.add(new Scanner.BulkListener()
scannerListeners = new ArrayList();
scannerListeners.add(new Scanner.BulkListener()
{
public void filesChanged(List changes)
{
try
{
boolean reconfigure = changes.contains(getProject().getFile().getCanonicalPath());
boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
restartWebApp(reconfigure);
}
catch (Exception e)
@ -121,10 +122,14 @@ public class JettyRunWarMojo extends AbstractJettyMojo
}
}
});
setScannerListeners(listeners);
}
/**
* @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
*/
public void restartWebApp(boolean reconfigureScanner) throws Exception
{
getLog().info("Restarting webapp ...");
@ -139,12 +144,10 @@ public class JettyRunWarMojo extends AbstractJettyMojo
if (reconfigureScanner)
{
getLog().info("Reconfiguring scanner after change to pom.xml ...");
ArrayList scanList = getScanList();
scanList.clear();
scanList.add(getProject().getFile());
scanList.add(project.getFile());
scanList.add(war);
setScanList(scanList);
getScanner().setScanDirs(scanList);
scanner.setScanDirs(scanList);
}
getLog().debug("Restarting webapp ...");

View File

@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.maven.artifact.Artifact;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
@ -59,40 +60,40 @@ public class JettyWebAppContext extends WebAppContext
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;
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<Overlay> _overlays;
/**
* @deprecated The value of this parameter will be ignored by the plugin. Overlays will always be unpacked.
*/
private boolean unpackOverlays;
/**
* Set the "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" with a pattern for matching jars on
* container classpath to scan. This is analogous to the WebAppContext.setAttribute() call.
*/
private String containerIncludeJarPattern = null;
private String _containerIncludeJarPattern = null;
/**
* Set the "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern" with a pattern for matching jars on
* webapp's classpath to scan. This is analogous to the WebAppContext.setAttribute() call.
*/
private String webInfIncludeJarPattern = null;
private String _webInfIncludeJarPattern = null;
/**
* @deprecated The value of this parameter will be ignored by the plugin. This option will be always disabled.
* If there is no maven-war-plugin config for ordering of the current project in the
* sequence of overlays, use this to control whether the current project is added
* first or last in list of overlaid resources
*/
private boolean copyWebInf;
private boolean _baseAppFirst = true;
private boolean baseAppFirst = true;
public JettyWebAppContext ()
throws Exception
@ -103,7 +104,7 @@ public class JettyWebAppContext extends WebAppContext
new WebXmlConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
envConfig = new EnvConfiguration(),
_envConfig = new EnvConfiguration(),
new org.eclipse.jetty.plus.webapp.PlusConfiguration(),
new MavenAnnotationConfiguration(),
new JettyWebXmlConfiguration()
@ -113,114 +114,94 @@ public class JettyWebAppContext extends WebAppContext
}
public void setContainerIncludeJarPattern(String pattern)
{
containerIncludeJarPattern = pattern;
_containerIncludeJarPattern = pattern;
}
public String getContainerIncludeJarPattern()
{
return containerIncludeJarPattern;
return _containerIncludeJarPattern;
}
public String getWebInfIncludeJarPattern()
{
return webInfIncludeJarPattern;
return _webInfIncludeJarPattern;
}
public void setWebInfIncludeJarPattern(String pattern)
{
webInfIncludeJarPattern = pattern;
_webInfIncludeJarPattern = pattern;
}
public boolean getUnpackOverlays()
{
return unpackOverlays;
}
public void setUnpackOverlays(boolean unpackOverlays)
{
this.unpackOverlays = unpackOverlays;
}
public List<File> getClassPathFiles()
{
return this.classpathFiles;
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;
this._jettyEnvXml = jettyEnvXml;
}
public String getJettyEnvXml()
{
return this.jettyEnvXml;
return this._jettyEnvXml;
}
public void setClasses(File dir)
{
classes = dir;
_classes = dir;
}
public File getClasses()
{
return classes;
return _classes;
}
public void setWebInfLib (List<File> jars)
{
webInfJars.addAll(jars);
_webInfJars.addAll(jars);
}
public void setTestClasses (File dir)
{
testClasses = dir;
_testClasses = dir;
}
public File getTestClasses ()
{
return testClasses;
return _testClasses;
}
/* ------------------------------------------------------------ */
@Override
public void setCopyWebInf(boolean value)
/**
* Ordered list of wars to overlay on top of the current project. The list
* may contain an overlay that represents the current project.
* @param overlays
*/
public void setOverlays (List<Overlay> overlays)
{
copyWebInf = value;
_overlays = overlays;
}
/* ------------------------------------------------------------ */
@Override
public boolean isCopyWebInf()
public List<Overlay> getOverlays()
{
return copyWebInf;
return _overlays;
}
/* ------------------------------------------------------------ */
public void setBaseAppFirst(boolean value)
{
baseAppFirst = value;
_baseAppFirst = value;
}
/* ------------------------------------------------------------ */
public boolean getBaseAppFirst()
{
return baseAppFirst;
return _baseAppFirst;
}
/* ------------------------------------------------------------ */
@ -244,7 +225,7 @@ public class JettyWebAppContext extends WebAppContext
public List<File> getWebInfLib()
{
return webInfJars;
return _webInfJars;
}
public void doStart () throws Exception
@ -254,7 +235,7 @@ public class JettyWebAppContext extends WebAppContext
//Allow user to set up pattern for names of jars from the container classpath
//that will be scanned - note that by default NO jars are scanned
String tmp = containerIncludeJarPattern;
String tmp = _containerIncludeJarPattern;
if (tmp==null || "".equals(tmp))
tmp = (String)getAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN);
@ -264,32 +245,32 @@ public class JettyWebAppContext extends WebAppContext
//Allow user to set up pattern of jar names from WEB-INF that will be scanned.
//Note that by default ALL jars considered to be in WEB-INF will be scanned - setting
//a pattern restricts scanning
if (webInfIncludeJarPattern != null)
setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, webInfIncludeJarPattern);
if (_webInfIncludeJarPattern != null)
setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, _webInfIncludeJarPattern);
//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);
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);
_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)
_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);
_webInfJarMap.put(fileName, file);
}
if (this.jettyEnvXml != null)
envConfig.setJettyEnvXml(Resource.toURL(new File(this.jettyEnvXml)));
if (this._jettyEnvXml != null)
_envConfig.setJettyEnvXml(Resource.toURL(new File(this._jettyEnvXml)));
// CHECK setShutdown(false);
super.doStart();
@ -297,18 +278,18 @@ public class JettyWebAppContext extends WebAppContext
public void doStop () throws Exception
{
if (classpathFiles != null)
classpathFiles.clear();
classpathFiles = null;
if (_classpathFiles != null)
_classpathFiles.clear();
_classpathFiles = null;
classes = null;
testClasses = null;
_classes = null;
_testClasses = null;
if (webInfJarMap != null)
webInfJarMap.clear();
if (_webInfJarMap != null)
_webInfJarMap.clear();
webInfClasses.clear();
webInfJars.clear();
_webInfClasses.clear();
_webInfJars.clear();
@ -326,7 +307,7 @@ public class JettyWebAppContext extends WebAppContext
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)
if ((resource == null || !resource.exists()) && uriInContext != null && _classes != null)
{
String uri = URIUtil.canonicalPath(uriInContext);
if (uri == null)
@ -341,19 +322,19 @@ public class JettyWebAppContext extends WebAppContext
{
//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);
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()))
while (res == null && (i < _webInfClasses.size()))
{
String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath());
String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
res = Resource.newResource(newPath);
if (!res.exists())
{
@ -373,7 +354,7 @@ public class JettyWebAppContext extends WebAppContext
jarName = jarName.substring(1);
if (jarName.length()==0)
return null;
File jarFile = webInfJarMap.get(jarName);
File jarFile = _webInfJarMap.get(jarName);
if (jarFile != null)
return Resource.newResource(jarFile.getPath());
@ -406,7 +387,7 @@ public class JettyWebAppContext extends WebAppContext
//add in the dependency jars as a virtual WEB-INF/lib entry
if (path.startsWith(WEB_INF_LIB_PREFIX))
{
for (String fileName : webInfJarMap.keySet())
for (String fileName : _webInfJarMap.keySet())
{
// Return all jar files from class path
allPaths.add(WEB_INF_LIB_PREFIX + "/" + fileName);
@ -416,9 +397,9 @@ public class JettyWebAppContext extends WebAppContext
{
int i=0;
while (i < webInfClasses.size())
while (i < _webInfClasses.size())
{
String newPath = path.replace(WEB_INF_CLASSES_PREFIX, webInfClasses.get(i).getPath());
String newPath = path.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
allPaths.addAll(super.getResourcePaths(newPath));
i++;
}

View File

@ -20,14 +20,14 @@ package org.eclipse.jetty.maven.plugin;
import java.io.File;
import java.io.IOException;
import java.net.URLClassLoader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.apache.maven.artifact.Artifact;
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;
@ -36,29 +36,43 @@ import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
/**
* MavenWebInfConfiguration
*
* WebInfConfiguration to take account of overlaid wars expressed as project dependencies and
* potentiall configured via the maven-war-plugin.
*
*/
public class MavenWebInfConfiguration extends WebInfConfiguration
{
private static final Logger LOG = Log.getLogger(MavenWebInfConfiguration.class);
private static final Logger LOG = Log.getLogger(WebInfConfiguration.class);
protected static int COUNTER = 0;
protected Resource _originalResourceBase;
protected Resource[] _unpackedOverlays;
protected List<Resource> _unpackedOverlayResources;
/**
* @see org.eclipse.jetty.webapp.WebInfConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
*/
public void configure(WebAppContext context) throws Exception
{
JettyWebAppContext jwac = (JettyWebAppContext)context;
//put the classes dir and all dependencies into the classpath
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 = "+LazyList.array2List(((URLClassLoader)context.getClassLoader()).getURLs()));
}
super.configure(context);
// knock out environmental maven and plexus classes from webAppContext
@ -76,31 +90,45 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
context.setServerClasses( newServerClasses );
}
/**
* @see org.eclipse.jetty.webapp.WebInfConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
*/
public void preConfigure(WebAppContext context) throws Exception
{
super.preConfigure(context);
}
/**
* @see org.eclipse.jetty.webapp.AbstractConfiguration#postConfigure(org.eclipse.jetty.webapp.WebAppContext)
*/
public void postConfigure(WebAppContext context) throws Exception
{
super.postConfigure(context);
}
/**
* @see org.eclipse.jetty.webapp.WebInfConfiguration#deconfigure(org.eclipse.jetty.webapp.WebAppContext)
*/
public void deconfigure(WebAppContext context) throws Exception
{
JettyWebAppContext jwac = (JettyWebAppContext)context;
{
//remove the unpacked wars
if (_unpackedOverlays != null && _unpackedOverlays.length>0)
if (_unpackedOverlayResources != null && !_unpackedOverlayResources.isEmpty())
{
try
{
for (int i=0; i<_unpackedOverlays.length; i++)
for (Resource r:_unpackedOverlayResources)
{
IO.delete(_unpackedOverlays[i].getFile());
IO.delete(r.getFile());
}
}
catch (IOException e)
@ -111,12 +139,11 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
super.deconfigure(context);
//restore whatever the base resource was before we might have included overlaid wars
context.setBaseResource(_originalResourceBase);
}
/**
* @see org.eclipse.jetty.webapp.WebInfConfiguration#unpack(org.eclipse.jetty.webapp.WebAppContext)
*/
@ -126,62 +153,49 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
//Unpack and find base resource as normal
super.unpack(context);
//Add in any overlays as a resource collection for the base
//Get the base resource for the "virtual" webapp
_originalResourceBase = context.getBaseResource();
JettyWebAppContext jwac = (JettyWebAppContext)context;
//Add in any overlaid wars as base resources
if (jwac.getOverlays() != null && !jwac.getOverlays().isEmpty())
//determine sequencing of overlays
_unpackedOverlayResources = new ArrayList<Resource>();
if (!jwac.getOverlays().isEmpty())
{
Resource[] origResources = null;
int origSize = 0;
List<Resource> resourceBaseCollection = new ArrayList<Resource>();
if (jwac.getBaseResource() != null)
for (Overlay o:jwac.getOverlays())
{
if (jwac.getBaseResource() instanceof ResourceCollection)
//can refer to the current project in list of overlays for ordering purposes
if (o.getConfig() != null && o.getConfig().isCurrentProject())
{
origResources = ((ResourceCollection)jwac.getBaseResource()).getResources();
origSize = origResources.length;
resourceBaseCollection.add(_originalResourceBase);
continue;
}
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)
Resource unpacked = unpackOverlay(jwac,o);
_unpackedOverlayResources.add(unpacked); //remember the unpacked overlays for later so we can delete the tmp files
resourceBaseCollection.add(unpacked); //add in the selectively unpacked overlay in the correct order to the webapps resource base
}
if (!resourceBaseCollection.contains(_originalResourceBase))
{
if (jwac.getBaseAppFirst())
{
System.arraycopy(origResources,0,newResources,0,origSize);
offset = origSize;
LOG.info("Adding virtual project first in resource base list");
resourceBaseCollection.add(0, _originalResourceBase);
}
else
{
System.arraycopy(origResources,0,newResources,overlaySize,origSize);
LOG.info("Adding virtual project last in resource base list");
resourceBaseCollection.add(_originalResourceBase);
}
}
// Overlays are always unpacked
_unpackedOverlays = new Resource[overlaySize];
List<Resource> overlays = jwac.getOverlays();
for (int idx=0; idx<overlaySize; idx++)
{
LOG.info("Unpacking overlay: " + overlays.get(idx));
_unpackedOverlays[idx] = unpackOverlay(context, overlays.get(idx));
newResources[idx+offset] = _unpackedOverlays[idx];
LOG.info("Adding overlay: " + _unpackedOverlays[idx]);
}
jwac.setBaseResource(new ResourceCollection(newResources));
jwac.setBaseResource(new ResourceCollection(resourceBaseCollection.toArray(new Resource[resourceBaseCollection.size()])));
}
}
@ -225,25 +239,68 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
protected Resource unpackOverlay (WebAppContext context, Resource overlay)
protected Resource unpackOverlay (WebAppContext context, Overlay overlay)
throws IOException
{
LOG.info("Unpacking overlay: " + overlay);
//resolve if not already resolved
resolveTempDirectory(context);
if (overlay.getResource() == null)
return null; //nothing to unpack
//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();
String name = overlay.getResource().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);
name = name+(++COUNTER); //add some digits to ensure uniqueness
File dir = new File(context.getTempDirectory(), name);
//if specified targetPath, unpack to that subdir instead
File unpackDir = dir;
if (overlay.getConfig() != null && overlay.getConfig().getTargetPath() != null)
unpackDir = new File (dir, overlay.getConfig().getTargetPath());
overlay.getResource().copyTo(unpackDir);
//use top level of unpacked content
Resource unpackedOverlay = Resource.newResource(dir.getCanonicalPath());
LOG.info("Unpacked overlay: "+overlay+" to "+unpackedOverlay);
return unpackedOverlay;
}
protected Artifact getArtifactForOverlay (OverlayConfig o, List<Artifact> warArtifacts)
{
if (o == null || warArtifacts == null || warArtifacts.isEmpty())
return null;
for (Artifact a:warArtifacts)
{
if (overlayMatchesArtifact (o, a))
{
return a;
}
}
return null;
}
protected boolean overlayMatchesArtifact(OverlayConfig o, Artifact a)
{
if ((o.getGroupId() == null && a.getGroupId() == null) || (o.getGroupId() != null && o.getGroupId().equals(a.getGroupId())))
{
if ((o.getArtifactId() == null && a.getArtifactId() == null) || (o.getArtifactId() != null && o.getArtifactId().equals(a.getArtifactId())))
{
if ((o.getClassifier() == null) || (o.getClassifier().equals(a.getClassifier())))
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,74 @@
//
// ========================================================================
// 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.util.resource.Resource;
/**
* Overlay
*
*
*/
public class Overlay
{
private OverlayConfig _config;
private Resource _resource;
public Overlay (OverlayConfig config, Resource resource)
{
_config = config;
_resource = resource;
}
public Overlay (OverlayConfig config)
{
_config = config;
}
public void setResource (Resource r)
{
_resource = r;
}
public Resource getResource ()
{
return _resource;
}
public OverlayConfig getConfig ()
{
return _config;
}
public String toString()
{
StringBuffer strbuff = new StringBuffer();
if (_resource != null)
strbuff.append(_resource);
if (_config != null)
{
strbuff.append(" [");
strbuff.append(_config);
strbuff.append("]");
}
return strbuff.toString();
}
}

View File

@ -0,0 +1,304 @@
//
// ========================================================================
// 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.Iterator;
import java.util.List;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import edu.emory.mathcs.backport.java.util.Arrays;
/**
* OverlayConfig
*
*
*/
public class OverlayConfig
{
private String targetPath;
private String groupId;
private String artifactId;
private String classifier;
private List<String> includes;
private List<String> excludes;
private boolean skip;
private boolean filtered;
public OverlayConfig() {}
public OverlayConfig(String fmt, List<String> defaultIncludes, List<String> defaultExcludes)
{
if (fmt == null)
return;
String[] atoms = fmt.split(",");
for (int i=0;i<atoms.length;i++)
{
String s = atoms[i].trim();
switch (i)
{
case 0:
{
if (!"".equals(s))
groupId = s;
break;
}
case 1:
{
if (!"".equals(s))
artifactId = s;
break;
}
case 2:
{
if (!"".equals(s))
classifier = s;
break;
}
case 3:
{
if (!"".equals(s))
targetPath = s;
break;
}
case 4:
{
if ("".equals(s))
skip = false;
else
skip = Boolean.valueOf(s);
break;
}
case 5:
{
if ("".equals(s))
filtered = false;
else
filtered = Boolean.valueOf(s);
break;
}
case 6:
{
if ("".equals(s))
break;
String[] incs = s.split(";");
if (incs.length > 0)
includes = Arrays.asList(incs);
break;
}
case 7:
{
if ("".equals(s))
break;
String[] exs = s.split(";");
if (exs.length > 0)
excludes = Arrays.asList(exs);
break;
}
}
}
}
public OverlayConfig(Xpp3Dom root, List<String> defaultIncludes, List<String> defaultExcludes)
{
Xpp3Dom node = root.getChild("groupId");
setGroupId(node==null?null:node.getValue());
node = root.getChild("artifactId");
setArtifactId(node==null?null:node.getValue());
node = root.getChild("classifier");
setClassifier(node==null?null:node.getValue());
node = root.getChild("targetPath");
setTargetPath(node==null?null:node.getValue());
node = root.getChild("skip");
setSkip(node==null?false:Boolean.valueOf(node.getValue()));
node = root.getChild("filtered");
setFiltered(node==null?false:Boolean.valueOf(node.getValue()));
node = root.getChild("includes");
List<String> includes = null;
if (node != null && node.getChildCount() > 0)
{
Xpp3Dom[] list = node.getChildren("include");
for (int j=0; list != null && j < list.length;j++)
{
if (includes == null)
includes = new ArrayList<String>();
includes.add(list[j].getValue());
}
}
if (includes == null && defaultIncludes != null)
{
includes = new ArrayList<String>();
includes.addAll(defaultIncludes);
}
setIncludes(includes);
node = root.getChild("excludes");
List<String> excludes = null;
if (node != null && node.getChildCount() > 0)
{
Xpp3Dom[] list = node.getChildren("exclude");
for (int j=0; list != null && j < list.length;j++)
{
if (excludes == null)
excludes = new ArrayList<String>();
excludes.add(list[j].getValue());
}
}
if (excludes == null && defaultExcludes != null)
{
excludes = new ArrayList<String>();
excludes.addAll(defaultExcludes);
}
setExcludes(excludes);
}
public String getTargetPath()
{
return targetPath;
}
public void setTargetPath(String targetPath)
{
this.targetPath = targetPath;
}
public String getGroupId()
{
return groupId;
}
public void setGroupId(String groupId)
{
this.groupId = groupId;
}
public String getArtifactId()
{
return artifactId;
}
public void setArtifactId(String artifactId)
{
this.artifactId = artifactId;
}
public String getClassifier()
{
return classifier;
}
public void setClassifier(String classifier)
{
this.classifier = classifier;
}
public List<String> getIncludes()
{
return includes;
}
public void setIncludes(List<String> includes)
{
this.includes = includes;
}
public List<String> getExcludes()
{
return excludes;
}
public void setExcludes(List<String> excludes)
{
this.excludes = excludes;
}
public boolean isSkip()
{
return skip;
}
public void setSkip(boolean skip)
{
this.skip = skip;
}
public boolean isFiltered()
{
return filtered;
}
public void setFiltered(boolean filtered)
{
this.filtered = filtered;
}
public boolean isCurrentProject()
{
if (this.groupId == null && this.artifactId == null)
return true;
return false;
}
public String toString()
{
StringBuffer strbuff = new StringBuffer();
strbuff.append((groupId != null ? groupId : "")+",");
strbuff.append((artifactId != null ? artifactId : "")+",");
strbuff.append((classifier != null ? classifier : "")+",");
strbuff.append((targetPath != null ? targetPath : "")+",");
strbuff.append(""+skip+",");
strbuff.append(""+filtered+",");
if (includes != null)
{
Iterator<String> itor = includes.iterator();
while (itor.hasNext())
{
strbuff.append(itor.next());
if (itor.hasNext())
strbuff.append(";");
}
}
strbuff.append(", ");
if (excludes != null)
{
Iterator<String> itor = excludes.iterator();
while (itor.hasNext())
{
strbuff.append(itor.next());
if (itor.hasNext())
strbuff.append(";");
}
}
return strbuff.toString();
}
}

View File

@ -0,0 +1,236 @@
//
// ========================================================================
// 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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.codehaus.plexus.util.SelectorUtils;
import org.eclipse.jetty.util.IO;
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.JarResource;
/**
* SelectiveJarResource
*
* Selectively copies resources from a jar file based on includes/excludes.
*
*/
public class SelectiveJarResource extends JarResource
{
private static final Logger LOG = Log.getLogger(SelectiveJarResource.class);
public static final List<String> DEFAULT_INCLUDES = Arrays.asList(new String[]{"**"});// No includes supplied, so set it to 'matches all'
public static final List<String> DEFAULT_EXCLUDES = Collections.emptyList(); //No includes, set to no exclusions
List<String> _includes = null;
List<String> _excludes = null;
boolean _caseSensitive = false;
/**
* @param url
*/
public SelectiveJarResource(URL url)
{
super(url);
}
/**
* @param url
* @param useCaches
*/
public SelectiveJarResource(URL url, boolean useCaches)
{
super(url, useCaches);
}
public void setCaseSensitive (boolean caseSensitive)
{
_caseSensitive = caseSensitive;
}
public void setIncludes (List<String> patterns)
{
_includes = patterns;
}
public void setExcludes (List<String> patterns)
{
_excludes = patterns;
}
protected boolean isIncluded (String name)
{
for (String include:_includes)
{
if (SelectorUtils.matchPath(include, name, _caseSensitive))
{
return true;
}
}
return false;
}
protected boolean isExcluded (String name)
{
for (String exclude:_excludes)
{
if (SelectorUtils.matchPath (exclude, name, _caseSensitive))
{
return true;
}
}
return false;
}
/**
* @see org.eclipse.jetty.util.resource.JarResource#copyTo(java.io.File)
*/
@Override
public void copyTo(File directory) throws IOException
{
if (_includes == null)
_includes = DEFAULT_INCLUDES;
if (_excludes == null)
_excludes = DEFAULT_EXCLUDES;
//Copy contents of the jar file to the given directory,
//using the includes and excludes patterns to control which
//parts of the jar file are copied
if (!exists())
return;
String urlString = this.getURL().toExternalForm().trim();
int endOfJarUrl = urlString.indexOf("!/");
int startOfJarUrl = (endOfJarUrl >= 0?4:0);
if (endOfJarUrl < 0)
throw new IOException("Not a valid jar url: "+urlString);
URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl));
InputStream is = jarFileURL.openConnection().getInputStream();
JarInputStream jin = new JarInputStream(is);
JarEntry entry;
while((entry=jin.getNextJarEntry())!=null)
{
String entryName = entry.getName();
LOG.debug("Looking at "+entryName);
String dotCheck = entryName.replace('\\', '/');
dotCheck = URIUtil.canonicalPath(dotCheck);
if (dotCheck == null)
{
LOG.info("Invalid entry: "+entryName);
continue;
}
File file=new File(directory,entryName);
if (entry.isDirectory())
{
if (isIncluded(entryName))
{
if (!isExcluded(entryName))
{
// Make directory
if (!file.exists())
file.mkdirs();
}
else
LOG.debug("{} dir is excluded", entryName);
}
else
LOG.debug("{} dir is NOT included", entryName);
}
else
{
//entry is a file, is it included?
if (isIncluded(entryName))
{
if (!isExcluded(entryName))
{
// make directory (some jars don't list dirs)
File dir = new File(file.getParent());
if (!dir.exists())
dir.mkdirs();
// Make file
FileOutputStream fout = null;
try
{
fout = new FileOutputStream(file);
IO.copy(jin,fout);
}
finally
{
IO.close(fout);
}
// touch the file.
if (entry.getTime()>=0)
file.setLastModified(entry.getTime());
}
else
LOG.debug("{} file is excluded", entryName);
}
else
LOG.debug("{} file is NOT included", entryName);
}
}
Manifest manifest = jin.getManifest();
if (manifest != null)
{
if (isIncluded("META-INF") && !isExcluded("META-INF"))
{
File metaInf = new File (directory, "META-INF");
metaInf.mkdir();
File f = new File(metaInf, "MANIFEST.MF");
FileOutputStream fout = new FileOutputStream(f);
manifest.write(fout);
fout.close();
}
}
IO.close(jin);
}
}

View File

@ -20,24 +20,33 @@ package org.eclipse.jetty.maven.plugin;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Set;
import java.util.TreeMap;
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;
/**
* Starter
*
* Class which is exec'ed to create a new jetty process. Used by the JettyRunForked mojo.
*
*/
public class Starter
{
public static final String PORT_SYSPROPERTY = "jetty.port";
@ -56,7 +65,57 @@ public class Starter
private String token;
/**
* Artifact
*
* A mock maven Artifact class as the maven jars are not put onto the classpath for the
* execution of this class.
*
*/
public class Artifact
{
public String gid;
public String aid;
public String path;
public Resource resource;
public Artifact (String csv)
{
if (csv != null && !"".equals(csv))
{
String[] atoms = csv.split(",");
if (atoms.length >= 3)
{
gid = atoms[0].trim();
aid = atoms[1].trim();
path = atoms[2].trim();
}
}
}
public Artifact (String gid, String aid, String path)
{
this.gid = gid;
this.aid = aid;
this.path = path;
}
public boolean equals(Object o)
{
if (!(o instanceof Artifact))
return false;
Artifact ao = (Artifact)o;
return (((gid == null && ao.gid == null) || (gid != null && gid.equals(ao.gid)))
&& ((aid == null && ao.aid == null) || (aid != null && aid.equals(ao.aid))));
}
}
/**
* @throws Exception
*/
public void configureJetty () throws Exception
{
LOG.debug("Starting Jetty Server ...");
@ -115,6 +174,9 @@ public class Starter
}
/**
* @throws Exception
*/
public void configureWebApp ()
throws Exception
{
@ -127,39 +189,105 @@ public class Starter
if (str != null)
webApp.setContextPath(str);
// - web.xml
str = (String)props.get("web.xml");
if (str != null)
webApp.setDescriptor(str);
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);
webApp.setWar(str);
webApp.setBaseResource(Resource.newResource(str));
}
// - overlays
str = (String)props.getProperty("overlay.files");
// - put virtual webapp base resource first on resource path or not
str = (String)props.getProperty("base.first");
if (str != null && !"".equals(str.trim()))
webApp.setBaseAppFirst(Boolean.getBoolean(str));
//For overlays
str = (String)props.getProperty("maven.war.includes");
List<String> defaultWarIncludes = fromCSV(str);
str = (String)props.getProperty("maven.war.excludes");
List<String> defaultWarExcludes = fromCSV(str);
//List of war artifacts
List<Artifact> wars = new ArrayList<Artifact>();
//List of OverlayConfigs
TreeMap<String, OverlayConfig> orderedConfigs = new TreeMap<String, OverlayConfig>();
Enumeration<String> pnames = (Enumeration<String>)props.propertyNames();
while (pnames.hasMoreElements())
{
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);
String n = pnames.nextElement();
if (n.startsWith("maven.war.artifact"))
{
Artifact a = new Artifact((String)props.get(n));
a.resource = Resource.newResource("jar:"+Resource.toURL(new File(a.path)).toString()+"!/");
wars.add(a);
}
else if (n.startsWith("maven.war.overlay"))
{
OverlayConfig c = new OverlayConfig ((String)props.get(n), defaultWarIncludes, defaultWarExcludes);
orderedConfigs.put(n,c);
}
}
Set<Artifact> matchedWars = new HashSet<Artifact>();
//process any overlays and the war type artifacts
List<Overlay> overlays = new ArrayList<Overlay>();
for (OverlayConfig config:orderedConfigs.values())
{
//overlays can be individually skipped
if (config.isSkip())
continue;
//an empty overlay refers to the current project - important for ordering
if (config.isCurrentProject())
{
Overlay overlay = new Overlay(config, null);
overlays.add(overlay);
continue;
}
//if a war matches an overlay config
Artifact a = getArtifactForOverlayConfig(config, wars);
if (a != null)
{
matchedWars.add(a);
SelectiveJarResource r = new SelectiveJarResource(new URL("jar:"+Resource.toURL(new File(a.path)).toString()+"!/"));
r.setIncludes(config.getIncludes());
r.setExcludes(config.getExcludes());
Overlay overlay = new Overlay(config, r);
overlays.add(overlay);
}
}
//iterate over the left over war artifacts and unpack them (without include/exclude processing) as necessary
for (Artifact a: wars)
{
if (!matchedWars.contains(a))
{
Overlay overlay = new Overlay(null, a.resource);
overlays.add(overlay);
}
}
webApp.setOverlays(overlays);
// - the equivalent of web-inf classes
str = (String)props.getProperty("classes.dir");
@ -188,6 +316,10 @@ public class Starter
}
/**
* @param args
* @throws Exception
*/
public void getConfiguration (String[] args)
throws Exception
{
@ -235,6 +367,9 @@ public class Starter
}
/**
* @throws Exception
*/
public void run() throws Exception
{
if (monitor != null)
@ -245,12 +380,18 @@ public class Starter
}
/**
* @throws Exception
*/
public void join () throws Exception
{
server.join();
}
/**
* @param e
*/
public void communicateStartupResult (Exception e)
{
if (token != null)
@ -263,6 +404,9 @@ public class Starter
}
/**
* @throws Exception
*/
public void applyJettyXml() throws Exception
{
if (jettyXmls == null)
@ -279,6 +423,10 @@ public class Starter
/**
* @param handler
* @param handlers
*/
protected void prependHandler (Handler handler, HandlerCollection handlers)
{
if (handler == null || handlers == null)
@ -292,6 +440,55 @@ public class Starter
}
/**
* @param c
* @param wars
* @return
*/
protected Artifact getArtifactForOverlayConfig (OverlayConfig c, List<Artifact> wars)
{
if (wars == null || wars.isEmpty() || c == null)
return null;
Artifact war = null;
Iterator<Artifact> itor = wars.iterator();
while(itor.hasNext() && war == null)
{
Artifact a = itor.next();
if (((c.getGroupId() == null && a.gid == null) || (c.getGroupId() != null && c.getGroupId().equals(a.gid)))
&& ((c.getArtifactId() == null && a.aid == null) || (c.getArtifactId() != null && c.getArtifactId().equals(a.aid)))
&& ((c.getClassifier() == null) || (c.getClassifier().equals(a.aid))))
{
war = a;
}
}
return war;
}
/**
* @param csv
* @return
*/
private List<String> fromCSV (String csv)
{
if (csv == null || "".equals(csv.trim()))
return null;
String[] atoms = csv.split(",");
List<String> list = new ArrayList<String>();
for (String a:atoms)
{
list.add(a.trim());
}
return list;
}
/**
* @param args
*/
public static final void main(String[] args)
{
if (args == null)

View File

@ -0,0 +1,203 @@
//
// ========================================================================
// 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.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.maven.model.Plugin;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
/**
* WarPluginInfo
*
* Information about the maven-war-plugin contained in the pom
*/
public class WarPluginInfo
{
private MavenProject _project;
private Plugin _plugin;
private List<String> _dependentMavenWarIncludes;
private List<String> _dependentMavenWarExcludes;
private List<OverlayConfig> _overlayConfigs;
/**
* @param project
*/
public WarPluginInfo (MavenProject project)
{
_project = project;
}
/**
* Find the maven-war-plugin, if one is configured
* @return
*/
public Plugin getPlugin()
{
if (_plugin == null)
{
List plugins = _project.getBuildPlugins();
if (plugins == null)
return null;
Iterator itor = plugins.iterator();
while (itor.hasNext() && _plugin==null)
{
Plugin plugin = (Plugin)itor.next();
if ("maven-war-plugin".equals(plugin.getArtifactId()))
_plugin = plugin;
}
}
return _plugin;
}
/**
* Get value of dependentWarIncludes for maven-war-plugin
* @return
*/
public List<String> getDependentMavenWarIncludes()
{
if (_dependentMavenWarIncludes == null)
{
getPlugin();
if (_plugin == null)
return null;
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
if (node == null)
return null;
node = node.getChild("dependentWarIncludes");
if (node == null)
return null;
String val = node.getValue();
_dependentMavenWarIncludes = Arrays.asList(val.split(","));
}
return _dependentMavenWarIncludes;
}
/**
* Get value of dependentWarExcludes for maven-war-plugin
* @return
*/
public List<String> getDependentMavenWarExcludes()
{
if (_dependentMavenWarExcludes == null)
{
getPlugin();
if (_plugin == null)
return null;
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
if (node == null)
return null;
node = node.getChild("dependentWarExcludes");
if (node == null)
return null;
String val = node.getValue();
_dependentMavenWarExcludes = Arrays.asList(val.split(","));
}
return _dependentMavenWarExcludes;
}
/**
* Get config for any overlays that have been declared for the maven-war-plugin.
*
* @return
*/
public List<OverlayConfig> getMavenWarOverlayConfigs ()
{
if (_overlayConfigs == null)
{
getPlugin();
if (_plugin == null)
return Collections.emptyList();
getDependentMavenWarIncludes();
getDependentMavenWarExcludes();
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
if (node == null)
return Collections.emptyList();
node = node.getChild("overlays");
if (node == null)
return Collections.emptyList();
Xpp3Dom[] nodes = node.getChildren("overlay");
if (nodes == null)
return Collections.emptyList();
_overlayConfigs = new ArrayList<OverlayConfig>();
for (int i=0;i<nodes.length;i++)
{
OverlayConfig overlayConfig = new OverlayConfig(nodes[i], _dependentMavenWarIncludes, _dependentMavenWarExcludes);
_overlayConfigs.add(overlayConfig);
}
}
return _overlayConfigs;
}
/**
* @return the xml as a string
*/
public String getMavenWarOverlayConfigAsString ()
{
getPlugin();
if (_plugin == null)
return "";
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
if (node == null)
return "";
return node.toString();
}
}