From 67343c5e0ff2415682fa60d36b0cf0f66196c285 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 17 Sep 2019 17:38:27 +1000 Subject: [PATCH] Issue #1743 WIP Signed-off-by: Jan Bartel --- .../maven/plugin/AbstractWebAppMojo.java | 83 ++++++--- .../maven/plugin/NewJettyDeployMojo.java | 137 +++++++++++++++ .../maven/plugin/NewJettyEffectiveWebXml.java | 56 ++++++ .../maven/plugin/NewJettyRunWarMojo.java | 118 ++++++------- .../jetty/maven/plugin/NewJettyStartMojo.java | 19 +- .../jetty/maven/plugin/NewJettyStopMojo.java | 115 ++++++++++++ .../maven/plugin/QuickStartGenerator.java | 164 ++++++++++++++++++ 7 files changed, 593 insertions(+), 99 deletions(-) create mode 100644 jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyDeployMojo.java create mode 100644 jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyEffectiveWebXml.java create mode 100644 jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStopMojo.java create mode 100644 jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/QuickStartGenerator.java diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractWebAppMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractWebAppMojo.java index 87c8ed6475a..16a24b22f50 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractWebAppMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractWebAppMojo.java @@ -30,6 +30,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -409,6 +410,12 @@ public abstract class AbstractWebAppMojo extends AbstractMojo @Parameter (defaultValue="${session}", required=true, readonly=true) private MavenSession session; + /** + * Default supported project type is war packaging. + */ + @Parameter + protected List supportedPackagings = Collections.singletonList("war"); + /** * List of deps that are wars */ @@ -426,34 +433,35 @@ public abstract class AbstractWebAppMojo extends AbstractMojo protected List providedJars; + @Override public void execute() throws MojoExecutionException, MojoFailureException { - //Doesn't apply to non-webapp projects - if ( !"war".equals( project.getPackaging() ) || skip ) - return; - - getLog().info("Configuring Jetty for project: " + this.project.getName()); - if (skip) + if (isPackagingSupported()) { - getLog().info("Skipping Jetty start: jetty.skip==true"); - return; - } + if (skip) + { + getLog().info("Skipping Jetty start: jetty.skip==true"); + return; + } - if (isExcludedGoal(execution.getMojoDescriptor().getGoal())) - { - getLog().info("The goal \""+execution.getMojoDescriptor().getFullGoalName()+ + if (isExcludedGoal(execution.getMojoDescriptor().getGoal())) + { + getLog().info("The goal \""+execution.getMojoDescriptor().getFullGoalName()+ "\" is unavailable for this web app because of an configuration."); - return; + return; + } + + getLog().info("Configuring Jetty for project: " + getProjectName()); + warPluginInfo = new WarPluginInfo(project); + configureSystemProperties(); + augmentPluginClasspath(); + PluginLog.setLog(getLog()); + verifyPomConfiguration(); + startJetty(); } - - warPluginInfo = new WarPluginInfo(project); - configureSystemProperties(); - augmentPluginClasspath(); - PluginLog.setLog(getLog()); - verifyPomConfiguration(); - startJetty(); - + else + getLog().info("Packaging type [" + project.getPackaging() + "] is unsupported"); } @@ -1078,9 +1086,25 @@ public abstract class AbstractWebAppMojo extends AbstractMojo return excluded; } + + protected boolean isPackagingSupported() + { + if (!supportedPackagings.contains(project.getPackaging())) + return false; + return true; + } + + protected String getProjectName() + { + String projectName = project.getName(); + if (StringUtils.isBlank(projectName)) + { + projectName = project.getGroupId() + ":" + project.getArtifactId(); + } + return projectName; + } - - protected void configureWebApp () + protected void configureWebApp() throws Exception { if (webApp == null) @@ -1209,4 +1233,17 @@ public abstract class AbstractWebAppMojo extends AbstractMojo return null; } + + + /** + * Get a file into which to write output from jetty. + */ + protected File getJettyOutputFile (String name) throws Exception + { + File outputFile = new File(target, name); + if (outputFile.exists()) + outputFile.delete(); + outputFile.createNewFile(); + return outputFile; + } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyDeployMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyDeployMojo.java new file mode 100644 index 00000000000..5e37158865c --- /dev/null +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyDeployMojo.java @@ -0,0 +1,137 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 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.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.eclipse.jetty.util.StringUtil; + +/** + *

+ * This goal is used to run Jetty with any pre-assembled war. This goal does not have + * to be used with a project of packaging type "war". + *

+ *

+ * You must configure the "webApp" element with the location of either a war file or + * an unpacked war that you wish to deploy - in either case, the webapp must be + * fully compiled and assembled as this goal does not do anything other than start + * jetty with the given webapp. + *

+ *

+ * This goal is designed to be bound to a build phase, and NOT to be run at the + * command line. It will not block waiting for jetty to execute, but rather continue + * execution. + *

+ *

+ * This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested + * HTTP client components via binding to the test-integration build phase. + *

+ */ +@Mojo(name = "newdeploy", requiresDependencyResolution = ResolutionScope.RUNTIME) +public class NewJettyDeployMojo extends AbstractWebAppMojo +{ + protected JettyEmbedder embedder; + protected JettyForker forker; + protected JettyDistroForker distroForker; + protected Path war; + + @Override + public void configureWebApp() throws Exception + { + if (StringUtil.isBlank(webApp.getWar())) + throw new MojoExecutionException("No war specified"); + + super.configureWebApp(); + war = Paths.get(webApp.getWar()); + getLog().info("War = "+war); + } + + /** + * Start a jetty instance in process to run given war. + */ + @Override + public void startJettyEmbedded() throws MojoExecutionException + { + try + { + embedder = newJettyEmbedder(); + embedder.setExitVm(false); + embedder.setStopAtShutdown(false); + embedder.start(); + } + catch (Exception e) + { + throw new MojoExecutionException("Error starting jetty", e); + } + } + + + /** + * Fork a jetty instance to run the given war. + */ + @Override + public void startJettyForked() throws MojoExecutionException + { + try + { + forker = newJettyForker(); + forker.setWaitForChild(false); //we never wait for child + forker.setJettyOutputFile(getJettyOutputFile("jetty-deploy.out")); + forker.start(); //forks jetty instance + + } + catch (Exception e) + { + throw new MojoExecutionException("Error starting jetty", e); + } + } + + /** + * Fork a jetty distro to run the given war. + */ + @Override + public void startJettyDistro() throws MojoExecutionException + { + try + { + distroForker = newJettyDistroForker(); + distroForker.setWaitForChild(false); //never wait for child + distroForker.setJettyOutputFile(getJettyOutputFile("jetty-deploy.out")); + distroForker.start(); //forks a jetty distro + } + catch (Exception e) + { + throw new MojoExecutionException("Error starting jetty", e); + } + } + + /** + * + */ + @Override + protected void verifyPomConfiguration() throws MojoExecutionException + { + //Do not verify the configuration of the webapp, as we are deploying + //a random war instead. + } +} diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyEffectiveWebXml.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyEffectiveWebXml.java new file mode 100644 index 00000000000..5b58b838c42 --- /dev/null +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyEffectiveWebXml.java @@ -0,0 +1,56 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 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.MojoExecutionException; + +/** + * + * + */ +public class NewJettyEffectiveWebXml extends AbstractWebAppMojo +{ + + + @Override + protected void startJettyEmbedded() throws MojoExecutionException + { + return; //not starting a full jetty + } + + /** + * + */ + @Override + protected void startJettyForked() throws MojoExecutionException + { + return; //not starting jetty this way + } + + /** + * + */ + @Override + protected void startJettyDistro() throws MojoExecutionException + { + return; //not starting jetty + } + +} diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyRunWarMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyRunWarMojo.java index 3826ea2d341..80382e67c60 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyRunWarMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyRunWarMojo.java @@ -19,7 +19,8 @@ package org.eclipse.jetty.maven.plugin; -import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Date; import java.util.List; @@ -31,6 +32,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.eclipse.jetty.util.PathWatcher; import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; +import org.eclipse.jetty.util.StringUtil; /** *

@@ -48,15 +50,7 @@ import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; @Mojo( name = "newrun-war", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) @Execute(phase = LifecyclePhase.PACKAGE) public class NewJettyRunWarMojo extends AbstractWebAppMojo -{ - - /** - * The location of the war file. - * - */ - @Parameter(defaultValue="${project.build.directory}/${project.build.finalName}.war", required = true) - private File war; - +{ //Start of parameters only valid for runType=inprocess /** * The interval in seconds to pause before checking if changes @@ -74,6 +68,7 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo protected JettyEmbedder embedder; protected JettyForker forker; protected JettyDistroForker distroForker; + protected Path war; /** @@ -90,18 +85,25 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo public void configureWebApp() throws Exception { super.configureWebApp(); - webApp.setWar(war.getCanonicalPath()); + if (StringUtil.isBlank(webApp.getWar())) + { + war = target.toPath().resolve(project.getBuild().getFinalName()+".war"); + webApp.setWar(war.toFile().getAbsolutePath()); + } + else + war = Paths.get(webApp.getWar()); + + getLog().info("War = "+war); } /** - * + * Start a jetty instance in process to run the built war. */ @Override public void startJettyEmbedded() throws MojoExecutionException { try { - //start jetty embedder = newJettyEmbedder(); embedder.setExitVm(true); embedder.setStopAtShutdown(true); @@ -115,6 +117,47 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo } } + + /** + * Fork a jetty instance to run the built war. + */ + @Override + public void startJettyForked() throws MojoExecutionException + { + try + { + forker = newJettyForker(); + forker.setWaitForChild(true); //we run at the command line, echo child output and wait for it + startScanner(); + forker.start(); //forks jetty instance + + } + catch (Exception e) + { + throw new MojoExecutionException("Error starting jetty", e); + } + } + + /** + * Deploy the built war to a jetty distro. + */ + @Override + public void startJettyDistro() throws MojoExecutionException + { + try + { + distroForker = newJettyDistroForker(); + distroForker.setWaitForChild(true); //we always run at the command line, echo child output and wait for it + startScanner(); + distroForker.start(); //forks a jetty distro + + } + catch (Exception e) + { + throw new MojoExecutionException("Error starting jetty", e); + } + } + public void startScanner() throws Exception { @@ -149,57 +192,11 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo cthread.start(); } } - - /** - * Fork a jetty instance to run the war - */ - @Override - public void startJettyForked() throws MojoExecutionException - { - try - { - forker = newJettyForker(); - forker.setWaitForChild(true); //we run at the command line, echo child output and wait for it - - startScanner(); - - //TODO is it ok to start the scanner before we start jetty? - - forker.start(); //forks jetty instance - - } - catch (Exception e) - { - throw new MojoExecutionException("Error starting jetty", e); - } - } - - /** - * - */ - @Override - public void startJettyDistro() throws MojoExecutionException - { - - try - { - distroForker = newJettyDistroForker(); - distroForker.setWaitForChild(true); //we always run at the command line, echo child output and wait for it - startScanner(); - distroForker.start(); //forks a jetty distro - - //TODO is it ok to start the scanner before we start jetty? - } - catch (Exception e) - { - throw new MojoExecutionException("Error starting jetty", e); - } - } public void configureScanner() throws MojoExecutionException { scanner.watch(project.getFile().toPath()); - scanner.watch(war.toPath()); + scanner.watch(war); scanner.addListener(new PathWatcher.EventListListener() { @@ -303,5 +300,4 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo } getLog().info("Restart completed."); } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStartMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStartMojo.java index cd6ed51b0e2..e6e9e5151bc 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStartMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStartMojo.java @@ -19,8 +19,6 @@ package org.eclipse.jetty.maven.plugin; -import java.io.File; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -50,7 +48,8 @@ public class NewJettyStartMojo extends AbstractWebAppMojo super.configureUnassembledWebApp(); } - /** Starts the webapp - without first compiling the classes - + /** + * Starts the webapp - without first compiling the classes - * in the same process as maven. */ @Override @@ -58,7 +57,6 @@ public class NewJettyStartMojo extends AbstractWebAppMojo { try { - //start jetty JettyEmbedder jetty = newJettyEmbedder(); jetty.setExitVm(false); jetty.setStopAtShutdown(false); @@ -82,7 +80,7 @@ public class NewJettyStartMojo extends AbstractWebAppMojo { JettyForker jetty = newJettyForker(); jetty.setWaitForChild(false); //we never wait for child - jetty.setJettyOutputFile(getJettyOutputFile()); + jetty.setJettyOutputFile(getJettyOutputFile("jetty-start.out")); jetty.start(); //forks jetty instance } @@ -103,7 +101,7 @@ public class NewJettyStartMojo extends AbstractWebAppMojo { JettyDistroForker jetty = newJettyDistroForker(); jetty.setWaitForChild(false); //never wait for child - jetty.setJettyOutputFile(getJettyOutputFile()); + jetty.setJettyOutputFile(getJettyOutputFile("jetty-start.out")); jetty.start(); //forks a jetty distro } catch (Exception e) @@ -111,13 +109,4 @@ public class NewJettyStartMojo extends AbstractWebAppMojo throw new MojoExecutionException("Error starting jetty", e); } } - - protected File getJettyOutputFile () throws Exception - { - File outputFile = new File(target, "jetty.out"); - if (outputFile.exists()) - outputFile.delete(); - outputFile.createNewFile(); - return outputFile; - } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStopMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStopMojo.java new file mode 100644 index 00000000000..d4f03e8f9c6 --- /dev/null +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/NewJettyStopMojo.java @@ -0,0 +1,115 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 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.InputStreamReader; +import java.io.LineNumberReader; +import java.io.OutputStream; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.Socket; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; + + +/** + * This goal stops a running instance of jetty. + * + * The stopPort and stopKey parameters can be used to + * configure which jetty to stop. + */ +@Mojo(name = "newstop") +public class NewJettyStopMojo extends AbstractWebAppMojo +{ + /** + * Max time in seconds that the plugin will wait for confirmation that jetty has stopped. + */ + @Parameter + protected int stopWait; + + @Override + protected void startJettyEmbedded() throws MojoExecutionException + { + //Does not start jetty + return; + } + + @Override + protected void startJettyForked() throws MojoExecutionException + { + //Does not start jetty + return; + } + + @Override + protected void startJettyDistro() throws MojoExecutionException + { + //Does not start jetty + return; + } + + @Override + 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"); + + String command = "forcestop"; + + try (Socket s = new Socket(InetAddress.getByName("127.0.0.1"), stopPort);) + { + OutputStream out = s.getOutputStream(); + out.write((stopKey + "\r\n" + command + "\r\n").getBytes()); + out.flush(); + + if (stopWait > 0) + { + s.setSoTimeout(stopWait * 1000); + s.getInputStream(); + + getLog().info("Waiting " + stopWait + " seconds for jetty to stop"); + LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream())); + String response; + boolean stopped = false; + while (!stopped && ((response = lin.readLine()) != null)) + { + if ("Stopped".equals(response)) + { + stopped = true; + getLog().info("Server reports itself as stopped"); + } + } + } + } + catch (ConnectException e) + { + getLog().info("Jetty not running!"); + } + catch (Exception e) + { + getLog().error(e); + } + } +} diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/QuickStartGenerator.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/QuickStartGenerator.java new file mode 100644 index 00000000000..84fa52290d9 --- /dev/null +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/QuickStartGenerator.java @@ -0,0 +1,164 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 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 org.eclipse.jetty.annotations.AnnotationConfiguration; +import org.eclipse.jetty.quickstart.QuickStartConfiguration; +import org.eclipse.jetty.quickstart.QuickStartConfiguration.Mode; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.thread.QueuedThreadPool; + +/** + * Run enough of jetty in order to generate a quickstart file for a + * webapp. + * + */ +public class QuickStartGenerator +{ + + private File quickstartXml; + private JettyWebAppContext webApp; + private File webAppPropsFile; + private String contextXml; + private boolean prepared = false; + + /** + * @return the webApp + */ + public JettyWebAppContext getWebApp() + { + return webApp; + } + + /** + * @param webApp the webApp to set + */ + public void setWebApp(JettyWebAppContext webApp) + { + this.webApp = webApp; + } + + /** + * @return the quickstartXml + */ + public File getQuickstartXml() + { + return quickstartXml; + } + + /** + * @param quickstartXml the quickstartXml to set + */ + public void setQuickstartXml(File quickstartXml) + { + this.quickstartXml = quickstartXml; + } + + public File getWebAppPropsFile() + { + return webAppPropsFile; + } + + public void setWebAppPropsFile(File webAppPropsFile) + { + this.webAppPropsFile = webAppPropsFile; + } + + public String getContextXml() + { + return contextXml; + } + + public void setContextXml(String contextXml) + { + this.contextXml = contextXml; + } + + private void prepareWebApp() + throws Exception + { + if (webApp == null) + webApp = new JettyWebAppContext(); + + //set the webapp up to do very little other than generate the quickstart-web.xml + webApp.addConfiguration(new MavenQuickStartConfiguration()); + webApp.setAttribute(QuickStartConfiguration.MODE, Mode.GENERATE); + webApp.setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, Resource.newResource(quickstartXml)); + webApp.setCopyWebDir(false); + webApp.setCopyWebInf(false); + } + + /** + * Run enough of jetty to generate a full quickstart xml file for the + * webapp. The tmp directory is persisted. + */ + public void generate() + throws Exception + { + if (quickstartXml == null) + throw new IllegalStateException ("No quickstart xml output file"); + + if (!prepared) + { + prepareWebApp(); + prepared = true; + } + + Server server = new Server(); + + //ensure handler structure enabled + ServerSupport.configureHandlers(server, null, null); + + ServerSupport.configureDefaultConfigurationClasses(server); + + //if our server has a thread pool associated we can do annotation scanning multithreaded, + //otherwise scanning will be single threaded + QueuedThreadPool tpool = server.getBean(QueuedThreadPool.class); + + //add webapp to our fake server instance + ServerSupport.addWebApplication(server, webApp); + + //leave everything unpacked for the forked process to use + webApp.setPersistTempDirectory(true); + + try + { + if (tpool != null) + tpool.start(); + else + webApp.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE.toString()); + + webApp.start(); //just enough to generate the quickstart + + //save config of the webapp BEFORE we stop + if (webAppPropsFile != null) + WebAppPropertyConverter.toProperties(webApp, webAppPropsFile, contextXml); + } + finally + { + webApp.stop(); + if (tpool != null) + tpool.stop(); + } + } +}