Issue #4003 Fix quickstart (#4008)

* Issue #4003 Fix quickstart.

Modes:
AUTO: use quickstart xml if present, start normally otherwise
GENERATE: re/generate quickstart xml
QUICKSTART: use a pregenerated quickstart xml, fail otherwise

Signed-off-by: Jan Bartel <janb@webtide.com>

* Issue #4003 Cleanup quickstart

Removed TerminateException in favour of Server.setDryRun(boolean)
and AbstractLifeCycle.StopException

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Jan Bartel 2019-09-10 16:04:01 +10:00 committed by GitHub
parent b272b36908
commit b851af0a5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 612 additions and 543 deletions

View File

@ -36,9 +36,9 @@
</Arg> </Arg>
</Call> --> </Call> -->
<Call id="webappprovider" name="addAppProvider"> <Call name="addAppProvider">
<Arg> <Arg>
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> <New id="webappprovider" class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="monitoredDirName"> <Set name="monitoredDirName">
<Property> <Property>
<Name>jetty.deploy.monitoredPath</Name> <Name>jetty.deploy.monitoredPath</Name>

View File

@ -172,7 +172,7 @@ public class DeploymentManager extends ContainerLifeCycle
for (AppProvider provider : providers) for (AppProvider provider : providers)
{ {
if (_providers.add(provider)) if (_providers.add(provider))
addBean(provider); addBean(provider, true);
} }
} }
@ -186,7 +186,7 @@ public class DeploymentManager extends ContainerLifeCycle
if (isRunning()) if (isRunning())
throw new IllegalStateException(); throw new IllegalStateException();
_providers.add(provider); _providers.add(provider);
addBean(provider); addBean(provider, true);
} }
public void setLifeCycleBindings(Collection<AppLifeCycle.Binding> bindings) public void setLifeCycleBindings(Collection<AppLifeCycle.Binding> bindings)
@ -523,6 +523,7 @@ public class DeploymentManager extends ContainerLifeCycle
catch (Throwable t) catch (Throwable t)
{ {
LOG.warn("Unable to reach node goal: " + nodeName, t); LOG.warn("Unable to reach node goal: " + nodeName, t);
// migrate to FAILED node // migrate to FAILED node
Node failed = _lifecycle.getNodeByName(AppLifeCycle.FAILED); Node failed = _lifecycle.getNodeByName(AppLifeCycle.FAILED);
appentry.setLifeCycleNode(failed); appentry.setLifeCycleNode(failed);

View File

@ -20,7 +20,6 @@ package org.eclipse.jetty.deploy;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -29,6 +28,7 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
/** /**
@ -37,21 +37,33 @@ import org.eclipse.jetty.util.resource.Resource;
* Supplies properties defined in a file. * Supplies properties defined in a file.
*/ */
@ManagedObject("Configure deployed webapps via properties") @ManagedObject("Configure deployed webapps via properties")
public class PropertiesConfigurationManager implements ConfigurationManager public class PropertiesConfigurationManager implements ConfigurationManager, Dumpable
{ {
private String _properties; private String _properties;
private final Map<String, String> _map = new HashMap<String, String>(); private final Map<String, String> _map = new HashMap<>();
public PropertiesConfigurationManager(String properties) public PropertiesConfigurationManager(String properties)
{ {
if (properties != null)
{
try
{
setFile(properties);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
} }
public PropertiesConfigurationManager() public PropertiesConfigurationManager()
{ {
this(null);
} }
@ManagedAttribute("A file or URL of properties") @ManagedAttribute("A file or URL of properties")
public void setFile(String resource) throws MalformedURLException, IOException public void setFile(String resource) throws IOException
{ {
_properties = resource; _properties = resource;
_map.clear(); _map.clear();
@ -75,7 +87,7 @@ public class PropertiesConfigurationManager implements ConfigurationManager
@Override @Override
public Map<String, String> getProperties() public Map<String, String> getProperties()
{ {
return new HashMap<>(_map); return _map;
} }
private void loadProperties(String resource) throws FileNotFoundException, IOException private void loadProperties(String resource) throws FileNotFoundException, IOException
@ -86,9 +98,25 @@ public class PropertiesConfigurationManager implements ConfigurationManager
Properties properties = new Properties(); Properties properties = new Properties();
properties.load(file.getInputStream()); properties.load(file.getInputStream());
for (Map.Entry<Object, Object> entry : properties.entrySet()) for (Map.Entry<Object, Object> entry : properties.entrySet())
{
_map.put(entry.getKey().toString(), String.valueOf(entry.getValue())); _map.put(entry.getKey().toString(), String.valueOf(entry.getValue()));
}
} }
} }
@Override
public String toString()
{
return String.format("%s@%x{%s}", this.getClass(), hashCode(), _properties);
}
@Override
public String dump()
{
return Dumpable.dump(this);
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
Dumpable.dumpObjects(out, indent, toString(), _map);
}
} }

View File

@ -20,7 +20,9 @@ package org.eclipse.jetty.deploy.bindings;
import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.AppLifeCycle;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.deploy.graph.Node;
import org.eclipse.jetty.deploy.providers.WebAppProvider;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -63,7 +65,7 @@ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding
{ {
return new String[]{"deploying"}; return new String[]{"deploying"};
} }
@Override @Override
public void processBinding(Node node, App app) throws Exception public void processBinding(Node node, App app) throws Exception
{ {
@ -94,6 +96,13 @@ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding
XmlConfiguration jettyXmlConfig = new XmlConfiguration(globalContextSettings); XmlConfiguration jettyXmlConfig = new XmlConfiguration(globalContextSettings);
Resource resource = Resource.newResource(app.getOriginId()); Resource resource = Resource.newResource(app.getOriginId());
app.getDeploymentManager().scope(jettyXmlConfig, resource); app.getDeploymentManager().scope(jettyXmlConfig, resource);
AppProvider appProvider = app.getAppProvider();
if (appProvider instanceof WebAppProvider)
{
WebAppProvider webAppProvider = ((WebAppProvider)appProvider);
if (webAppProvider.getConfigurationManager() != null)
jettyXmlConfig.getProperties().putAll(webAppProvider.getConfigurationManager().getProperties());
}
WebAppClassLoader.runWithServerClassAccess(() -> WebAppClassLoader.runWithServerClassAccess(() ->
{ {
jettyXmlConfig.configure(context); jettyXmlConfig.configure(context);

View File

@ -36,7 +36,7 @@ import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -45,7 +45,7 @@ import org.eclipse.jetty.util.resource.Resource;
* *
*/ */
@ManagedObject("Abstract Provider for loading webapps") @ManagedObject("Abstract Provider for loading webapps")
public abstract class ScanningAppProvider extends AbstractLifeCycle implements AppProvider public abstract class ScanningAppProvider extends ContainerLifeCycle implements AppProvider
{ {
private static final Logger LOG = Log.getLogger(ScanningAppProvider.class); private static final Logger LOG = Log.getLogger(ScanningAppProvider.class);
@ -81,11 +81,13 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
protected ScanningAppProvider() protected ScanningAppProvider()
{ {
this(null);
} }
protected ScanningAppProvider(FilenameFilter filter) protected ScanningAppProvider(FilenameFilter filter)
{ {
_filenameFilter = filter; _filenameFilter = filter;
addBean(_appMap);
} }
protected void setFilenameFilter(FilenameFilter filter) protected void setFilenameFilter(FilenameFilter filter)
@ -142,15 +144,19 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
_scanner.setFilenameFilter(_filenameFilter); _scanner.setFilenameFilter(_filenameFilter);
_scanner.setReportDirs(true); _scanner.setReportDirs(true);
_scanner.addListener(_scannerListener); _scanner.addListener(_scannerListener);
_scanner.start();
addBean(_scanner);
super.doStart();
} }
@Override @Override
protected void doStop() throws Exception protected void doStop() throws Exception
{ {
super.doStop();
if (_scanner != null) if (_scanner != null)
{ {
_scanner.stop(); removeBean(_scanner);
_scanner.removeListener(_scannerListener); _scanner.removeListener(_scannerListener);
_scanner = null; _scanner = null;
} }
@ -307,4 +313,10 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
); );
_scanner.scan(); _scanner.scan();
} }
@Override
public String toString()
{
return String.format("%s@%x%s", this.getClass(), hashCode(), _monitored);
}
} }

View File

@ -206,6 +206,7 @@ public class WebAppProvider extends ScanningAppProvider
*/ */
public void setConfigurationManager(ConfigurationManager configurationManager) public void setConfigurationManager(ConfigurationManager configurationManager)
{ {
updateBean(_configurationManager, configurationManager);
_configurationManager = configurationManager; _configurationManager = configurationManager;
} }

View File

@ -28,8 +28,9 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.plugins.annotations.ResolutionScope;
import org.eclipse.jetty.annotations.AnnotationConfiguration; import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.quickstart.QuickStartConfiguration.Mode;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
@ -92,30 +93,23 @@ public class JettyEffectiveWebXml extends JettyRunMojo
configureWebApplication(); configureWebApplication();
//set the webapp up to do very little other than generate the quickstart-web.xml //set the webapp up to do very little other than generate the quickstart-web.xml
if (effectiveWebXml == null)
{
deleteOnExit = true;
effectiveWebXml = new File(target, "effective-web.xml");
effectiveWebXml.deleteOnExit();
}
Resource descriptor = Resource.newResource(effectiveWebXml);
if (!effectiveWebXml.getParentFile().exists())
effectiveWebXml.getParentFile().mkdirs();
if (!effectiveWebXml.exists())
effectiveWebXml.createNewFile();
webApp.setCopyWebDir(false); webApp.setCopyWebDir(false);
webApp.setCopyWebInf(false); webApp.setCopyWebInf(false);
webApp.setGenerateQuickStart(true); webApp.addConfiguration(new QuickStartConfiguration());
webApp.setAttribute(QuickStartConfiguration.MODE, Mode.GENERATE);
//if the user didn't nominate a file to generate into, pick the name and webApp.setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, descriptor);
//make sure that it is deleted on exit
if (webApp.getQuickStartWebDescriptor() == null)
{
if (effectiveWebXml == null)
{
deleteOnExit = true;
effectiveWebXml = new File(target, "effective-web.xml");
effectiveWebXml.deleteOnExit();
}
Resource descriptor = Resource.newResource(effectiveWebXml);
if (!effectiveWebXml.getParentFile().exists())
effectiveWebXml.getParentFile().mkdirs();
if (!effectiveWebXml.exists())
effectiveWebXml.createNewFile();
webApp.setQuickStartWebDescriptor(descriptor);
}
ServerSupport.addWebApplication(server, webApp); ServerSupport.addWebApplication(server, webApp);
@ -158,7 +152,7 @@ public class JettyEffectiveWebXml extends JettyRunMojo
try try
{ {
//just show the result in the log //just show the result in the log
getLog().info(IO.toString(webApp.getQuickStartWebDescriptor().getInputStream())); getLog().info(IO.toString(((Resource)webApp.getAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML)).getInputStream()));
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -43,6 +43,8 @@ import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.plugins.annotations.ResolutionScope;
import org.eclipse.jetty.annotations.AnnotationConfiguration; 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.server.Server;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -209,22 +211,19 @@ public class JettyRunForkedMojo extends JettyRunMojo
configureWebApplication(); configureWebApplication();
//set the webapp up to do very little other than generate the quickstart-web.xml //set the webapp up to do very little other than generate the quickstart-web.xml
if (forkWebXml == null)
forkWebXml = new File(target, "fork-web.xml");
if (!forkWebXml.getParentFile().exists())
forkWebXml.getParentFile().mkdirs();
if (!forkWebXml.exists())
forkWebXml.createNewFile();
webApp.addConfiguration(new MavenQuickStartConfiguration());
webApp.setAttribute(QuickStartConfiguration.MODE, Mode.GENERATE);
webApp.setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, Resource.newResource(forkWebXml));
webApp.setCopyWebDir(false); webApp.setCopyWebDir(false);
webApp.setCopyWebInf(false); webApp.setCopyWebInf(false);
webApp.setGenerateQuickStart(true);
if (webApp.getQuickStartWebDescriptor() == null)
{
if (forkWebXml == null)
forkWebXml = new File(target, "fork-web.xml");
if (!forkWebXml.getParentFile().exists())
forkWebXml.getParentFile().mkdirs();
if (!forkWebXml.exists())
forkWebXml.createNewFile();
webApp.setQuickStartWebDescriptor(Resource.newResource(forkWebXml));
}
//add webapp to our fake server instance //add webapp to our fake server instance
ServerSupport.addWebApplication(server, webApp); ServerSupport.addWebApplication(server, webApp);
@ -240,11 +239,10 @@ public class JettyRunForkedMojo extends JettyRunMojo
//leave everything unpacked for the forked process to use //leave everything unpacked for the forked process to use
webApp.setPersistTempDirectory(true); webApp.setPersistTempDirectory(true);
File props = null;
webApp.start(); //just enough to generate the quickstart webApp.start(); //just enough to generate the quickstart
//save config of the webapp BEFORE we stop //save config of the webapp BEFORE we stop
final File props = prepareConfiguration(); props = prepareConfiguration();
webApp.stop(); webApp.stop();
if (tpool != null) if (tpool != null)
@ -311,7 +309,7 @@ public class JettyRunForkedMojo extends JettyRunMojo
if (PluginLog.getLog().isDebugEnabled()) if (PluginLog.getLog().isDebugEnabled())
PluginLog.getLog().debug("Forked cli:" + Arrays.toString(cmd.toArray())); PluginLog.getLog().debug("Forked cli:" + Arrays.toString(cmd.toArray()));
PluginLog.getLog().info("Forked process starting"); PluginLog.getLog().info("Forked process starting");
//set up extra environment vars if there are any //set up extra environment vars if there are any

View File

@ -34,7 +34,6 @@ import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration; import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration; import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.quickstart.QuickStartConfiguration; import org.eclipse.jetty.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.quickstart.QuickStartConfiguration.Mode;
import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
@ -105,8 +104,6 @@ public class JettyWebAppContext extends WebAppContext
*/ */
private boolean _baseAppFirst = true; private boolean _baseAppFirst = true;
private boolean _isGenerateQuickStart;
public JettyWebAppContext() throws Exception public JettyWebAppContext() throws Exception
{ {
super(); super();
@ -117,6 +114,8 @@ public class JettyWebAppContext extends WebAppContext
addConfiguration(new EnvConfiguration()); addConfiguration(new EnvConfiguration());
addConfiguration(new PlusConfiguration()); addConfiguration(new PlusConfiguration());
addConfiguration(new AnnotationConfiguration()); addConfiguration(new AnnotationConfiguration());
setAttribute(QuickStartConfiguration.ORIGIN_ATTRIBUTE, "origin");
} }
public void setContainerIncludeJarPattern(String pattern) public void setContainerIncludeJarPattern(String pattern)
@ -210,27 +209,6 @@ public class JettyWebAppContext extends WebAppContext
return attr == null ? null : attr.toString(); return attr == null ? null : attr.toString();
} }
/**
* Toggle whether or not the origin attribute will be generated into the
* xml.
*
* @param generateOrigin if true then the origin of each xml element is
* added, otherwise it is omitted.
*/
public void setGenerateOrigin(boolean generateOrigin)
{
setAttribute(QuickStartConfiguration.GENERATE_ORIGIN, generateOrigin);
}
/**
* @return true if the origin attribute will be generated, false otherwise
*/
public boolean isGenerateOrigin()
{
Object attr = getAttribute(QuickStartConfiguration.GENERATE_ORIGIN);
return attr == null ? false : Boolean.valueOf(attr.toString());
}
public List<Overlay> getOverlays() public List<Overlay> getOverlays()
{ {
return _overlays; return _overlays;
@ -246,35 +224,6 @@ public class JettyWebAppContext extends WebAppContext
return _baseAppFirst; return _baseAppFirst;
} }
/**
* Set the file to use into which to generate the quickstart output.
*
* @param quickStartWebXml the full path to the file to use
*/
public void setQuickStartWebDescriptor(String quickStartWebXml) throws Exception
{
setQuickStartWebDescriptor(Resource.newResource(quickStartWebXml));
}
/**
* Set the Resource to use into which to generate the quickstart output.
*/
protected void setQuickStartWebDescriptor(Resource quickStartWebXml)
{
setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, quickStartWebXml.toString());
}
public Resource getQuickStartWebDescriptor() throws Exception
{
Object o = getAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML);
if (o == null)
return null;
else if (o instanceof Resource)
return (Resource)o;
else
return Resource.newResource((String)o);
}
/** /**
* This method is provided as a convenience for jetty maven plugin * This method is provided as a convenience for jetty maven plugin
* configuration * configuration
@ -307,41 +256,9 @@ public class JettyWebAppContext extends WebAppContext
return _webInfClasses; return _webInfClasses;
} }
/**
* If true, a quickstart for the webapp is generated.
*
* @param quickStart if true the quickstart is generated, false otherwise
*/
public void setGenerateQuickStart(boolean quickStart)
{
_isGenerateQuickStart = quickStart;
}
public boolean isGenerateQuickStart()
{
return _isGenerateQuickStart;
}
@Override @Override
public void doStart() throws Exception public void doStart() throws Exception
{ {
// choose if this will be a quickstart or normal start
if (!isGenerateQuickStart() && getQuickStartWebDescriptor() != null)
{
MavenQuickStartConfiguration quickStart = new MavenQuickStartConfiguration();
quickStart.setMode(Mode.QUICKSTART);
quickStart.setQuickStartWebXml(getQuickStartWebDescriptor());
addConfiguration(quickStart);
}
else if (isGenerateQuickStart())
{
MavenQuickStartConfiguration quickStart = new MavenQuickStartConfiguration();
quickStart.setMode(Mode.GENERATE);
quickStart.setQuickStartWebXml(getQuickStartWebDescriptor());
addConfiguration(quickStart);
}
// Set up the pattern that tells us where the jars are that need // Set up the pattern that tells us where the jars are that need
// scanning // scanning

View File

@ -18,15 +18,12 @@
package org.eclipse.jetty.maven.plugin; package org.eclipse.jetty.maven.plugin;
import java.io.File;
import org.eclipse.jetty.quickstart.QuickStartConfiguration; import org.eclipse.jetty.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection; import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
/** /**
@ -36,56 +33,6 @@ public class MavenQuickStartConfiguration extends QuickStartConfiguration
{ {
private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class); private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class);
private Resource _quickStartWebXml; //the descriptor to use for starting/generating quickstart
public void setQuickStartWebXml(Resource quickStartWebXml)
{
_quickStartWebXml = quickStartWebXml;
}
@Override
public Resource getQuickStartWebXml(WebAppContext context) throws Exception
{
if (_quickStartWebXml == null)
return super.getQuickStartWebXml(context);
return _quickStartWebXml;
}
@Override
public void preConfigure(WebAppContext context) throws Exception
{
//check that webapp is suitable for quick start
if (context.getBaseResource() == null)
throw new IllegalStateException("No location for webapp");
//look for quickstart-web.xml in WEB-INF of webapp
Resource quickStartWebXml = getQuickStartWebXml(context);
if (LOG.isDebugEnabled())
LOG.debug("quickStartWebXml={}", quickStartWebXml);
super.preConfigure(context);
}
@Override
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 ...");
for (File classPathFile : jwac.getClassPathFiles())
{
((WebAppClassLoader)context.getClassLoader()).addClassPath(classPathFile.getCanonicalPath());
}
}
//Set up the quickstart environment for the context
super.configure(context);
}
@Override @Override
public void deconfigure(WebAppContext context) throws Exception public void deconfigure(WebAppContext context) throws Exception
{ {

View File

@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ShutdownMonitor; import org.eclipse.jetty.server.ShutdownMonitor;
@ -71,14 +72,9 @@ public class Starter
//configure webapp from properties file describing unassembled webapp //configure webapp from properties file describing unassembled webapp
configureWebApp(); configureWebApp();
//make it a quickstart if the quickstart-web.xml file exists webApp.addConfiguration(new QuickStartConfiguration());
if (webApp.getTempDirectory() != null) webApp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
{
File qs = new File(webApp.getTempDirectory(), "quickstart-web.xml");
if (qs.exists() && qs.isFile())
webApp.setQuickStartWebDescriptor(Resource.newResource(qs));
}
ServerSupport.addWebApplication(server, webApp); ServerSupport.addWebApplication(server, webApp);
@ -232,7 +228,9 @@ public class Starter
public static final void main(String[] args) public static final void main(String[] args)
{ {
if (args == null) if (args == null)
{
System.exit(1); System.exit(1);
}
Starter starter = null; Starter starter = null;
try try

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.eclipse.jetty.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -71,9 +72,10 @@ public class WebAppPropertyConverter
props.put("web.xml", webApp.getDescriptor()); props.put("web.xml", webApp.getDescriptor());
} }
if (webApp.getQuickStartWebDescriptor() != null) Object tmp = webApp.getAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML);
if (tmp != null)
{ {
props.put("quickstart.web.xml", webApp.getQuickStartWebDescriptor().getFile().getAbsolutePath()); props.put("quickstart.web.xml", tmp.toString());
} }
//sort out the context path //sort out the context path
@ -183,11 +185,10 @@ public class WebAppPropertyConverter
if (!StringUtil.isBlank(str)) if (!StringUtil.isBlank(str))
webApp.setDescriptor(str); webApp.setDescriptor(str);
//TODO the WebAppStarter class doesn't set up the QUICKSTART_CONFIGURATION_CLASSES, but the Starter class does!!!
str = props.getProperty("quickstart.web.xml"); str = props.getProperty("quickstart.web.xml");
if (!StringUtil.isBlank(str)) if (!StringUtil.isBlank(str))
{ {
webApp.setQuickStartWebDescriptor(Resource.newResource(new File(str))); webApp.setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, Resource.newResource(str));
} }
// - the tmp directory // - the tmp directory

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<!-- An example context XML for a quickstart webapp
A quick started webapp has all the jar scanning and fragment resolution done in a
Preconfigure phase, with all the discovered configuration encoded into a
WEB-INF/quickstart-web.xml file.
This allows very rapid and precise starting of a webapp, without the risk of accidental
deployment of other discovered resources. This is above and beyond what is available
with web.xml meta-data-complete, as it also prevents scanning for ServletContainer
initialisers and any annotations/classes they require.
If autoPreconfigure is set to true, then the webapp will be preconfigured the first
time it is run.
-->
<Configure class="org.eclipse.jetty.quickstart.QuickStartWebApp">
<Set name="autoPreconfigure">true</Set>
<Set name="contextPath">/</Set>
<Set name="war"><Property name="jetty.webapps" default="."/>/application.war</Set>
<!--
<Call name="setInitParameter">
<Arg>org.eclipse.jetty.jsp.precompiled</Arg>
<Arg>true</Arg>
</Call>
-->
</Configure>

View File

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call class="org.eclipse.jetty.quickstart.QuickStartConfiguration" name="configureMode">
<Arg><Ref refid="Server"/></Arg>
<Arg><Property name="jetty.quickstart.mode"/></Arg>
</Call>
<Ref refid="webappprovider">
<Get name="configurationManager">
<Get name="properties">
<Put name="jetty.quickstart.mode"><Property name="jetty.quickstart.mode"/></Put>
<Put name="jetty.quickstart.origin"><Property name="jetty.quickstart.origin"/></Put>
<Put name="jetty.quickstart.xml"><Property name="jetty.quickstart.xml"/></Put>
</Get>
</Get>
</Ref>
<Ref refid="DeploymentManager">
<Call name="addLifeCycleBinding">
<Arg>
<New class="org.eclipse.jetty.deploy.bindings.GlobalWebappConfigBinding">
<Set name="jettyXml">
<Property name="jetty.base"/>/etc/quickstart-webapp.xml
</Set>
</New>
</Arg>
</Call>
</Ref>
</Configure>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.quickstart.origin</Arg>
<Arg><Property name="jetty.quickstart.origin" default="origin"/></Arg>
</Call>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.quickstart.xml</Arg>
<Arg><Property name="jetty.quickstart.xml"/></Arg>
</Call>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.quickstart.mode</Arg>
<Arg>
<Call class="org.eclipse.jetty.quickstart.QuickStartConfiguration$Mode" name="valueOf">
<Arg><Property name="jetty.quickstart.mode" default="AUTO"/></Arg>
</Call>
</Arg>
</Call>
<Set name="extractWAR">true</Set>
<Set name="copyWebDir">false</Set>
<Set name="copyWebInf">false</Set>
</Configure>

View File

@ -6,8 +6,21 @@ deployment of preconfigured webapplications.
[depend] [depend]
server server
plus deploy
annotations
[lib] [lib]
lib/jetty-quickstart-${jetty.version}.jar lib/jetty-quickstart-${jetty.version}.jar
[xml]
etc/jetty-quickstart.xml
[files]
basehome:modules/jetty-quickstart.d/quickstart-webapp.xml|etc/quickstart-webapp.xml
[ini-template]
# Modes are AUTO, GENERATE, QUICKSTART
# jetty.quickstart.mode=AUTO
# jetty.quickstart.origin=origin
# jetty.quickstart.xml=

View File

@ -20,11 +20,15 @@ package org.eclipse.jetty.quickstart;
import java.util.Locale; import java.util.Locale;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource; import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration; import org.eclipse.jetty.xml.XmlConfiguration;
public class PreconfigureQuickStartWar public class PreconfigureQuickStartWar
@ -98,7 +102,13 @@ public class PreconfigureQuickStartWar
final Server server = new Server(); final Server server = new Server();
QuickStartWebApp webapp = new QuickStartWebApp(); WebAppContext webapp = new WebAppContext();
webapp.addConfiguration(new QuickStartConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration());
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.GENERATE);
webapp.setAttribute(QuickStartConfiguration.ORIGIN_ATTRIBUTE, "");
if (xml != null) if (xml != null)
{ {
@ -108,10 +118,21 @@ public class PreconfigureQuickStartWar
xmlConfiguration.configure(webapp); xmlConfiguration.configure(webapp);
} }
webapp.setResourceBase(dir.getFile().getAbsolutePath()); webapp.setResourceBase(dir.getFile().getAbsolutePath());
webapp.setMode(QuickStartConfiguration.Mode.GENERATE);
server.setHandler(webapp); server.setHandler(webapp);
server.start(); try
server.stop(); {
server.setDryRun(true);
server.start();
}
catch (Exception e)
{
throw e;
}
finally
{
if (!server.isStopped())
server.stop();
}
} }
private static void error(String message) private static void error(String message)

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.quickstart; package org.eclipse.jetty.quickstart;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -26,6 +27,8 @@ import java.util.stream.Collectors;
import org.eclipse.jetty.annotations.AnnotationConfiguration; import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.annotations.AnnotationDecorator; import org.eclipse.jetty.annotations.AnnotationDecorator;
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter; import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -39,17 +42,16 @@ import org.eclipse.jetty.webapp.WebXmlConfiguration;
/** /**
* QuickStartConfiguration * QuickStartConfiguration
* <p> * <p>
* Re-inflate a deployable webapp from a saved effective-web.xml * Prepare for quickstart generation, or usage.
* which combines all pre-parsed web xml descriptors and annotations.
*/ */
public class QuickStartConfiguration extends AbstractConfiguration public class QuickStartConfiguration extends AbstractConfiguration
{ {
private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class); private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class);
public static final Set<Class<? extends Configuration>> __replacedConfigurations = new HashSet<>(); public static final Set<Class<? extends Configuration>> __replacedConfigurations = new HashSet<>();
public static final String ORIGIN_ATTRIBUTE = "org.eclipse.jetty.quickstart.ORIGIN_ATTRIBUTE"; public static final String ORIGIN_ATTRIBUTE = "org.eclipse.jetty.quickstart.origin";
public static final String GENERATE_ORIGIN = "org.eclipse.jetty.quickstart.GENERATE_ORIGIN"; public static final String QUICKSTART_WEB_XML = "org.eclipse.jetty.quickstart.xml";
public static final String QUICKSTART_WEB_XML = "org.eclipse.jetty.quickstart.QUICKSTART_WEB_XML"; public static final String MODE = "org.eclipse.jetty.quickstart.mode";
static static
{ {
@ -59,41 +61,35 @@ public class QuickStartConfiguration extends AbstractConfiguration
__replacedConfigurations.add(org.eclipse.jetty.annotations.AnnotationConfiguration.class); __replacedConfigurations.add(org.eclipse.jetty.annotations.AnnotationConfiguration.class);
} }
; /** Configure the server for the quickstart mode.
* <p>In practise this means calling <code>server.setDryRun(true)</code> for GENERATE mode</p>
* @see Server#setDryRun(boolean)
* @param server The server to configure
* @param mode The quickstart mode
*/
public static void configureMode(Server server, String mode)
{
if (mode != null && Mode.valueOf(mode) == Mode.GENERATE)
server.setDryRun(true);
}
public enum Mode public enum Mode
{ {
DISABLED, // No Quick start
GENERATE, // Generate quickstart-web.xml and then stop GENERATE, // Generate quickstart-web.xml and then stop
AUTO, // use or generate depending on the existance of quickstart-web.xml AUTO, // use or generate depending on the existance of quickstart-web.xml
QUICKSTART // Use quickstart-web.xml QUICKSTART // Use quickstart-web.xml
} }
;
private Mode _mode = Mode.AUTO; private Mode _mode = Mode.AUTO;
private boolean _quickStart; private boolean _quickStart;
public QuickStartConfiguration() public QuickStartConfiguration()
{ {
super(true); super(false);
addDependencies(WebInfConfiguration.class); addDependencies(WebInfConfiguration.class);
addDependents(WebXmlConfiguration.class); addDependents(WebXmlConfiguration.class);
} }
public void setMode(Mode mode)
{
_mode = mode;
}
public Mode getMode()
{
return _mode;
}
/**
* @see org.eclipse.jetty.webapp.AbstractConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
*/
@Override @Override
public void preConfigure(WebAppContext context) throws Exception public void preConfigure(WebAppContext context) throws Exception
{ {
@ -106,39 +102,46 @@ public class QuickStartConfiguration extends AbstractConfiguration
Resource quickStartWebXml = getQuickStartWebXml(context); Resource quickStartWebXml = getQuickStartWebXml(context);
LOG.debug("quickStartWebXml={} exists={}", quickStartWebXml, quickStartWebXml.exists()); LOG.debug("quickStartWebXml={} exists={}", quickStartWebXml, quickStartWebXml.exists());
//Get the mode
Mode mode = (Mode)context.getAttribute(MODE);
if (mode != null)
_mode = mode;
_quickStart = false; _quickStart = false;
switch (_mode) switch (_mode)
{ {
case DISABLED:
super.preConfigure(context);
break;
case GENERATE: case GENERATE:
{ {
if (quickStartWebXml.exists())
LOG.info("Regenerating {}", quickStartWebXml);
else
LOG.info("Generating {}", quickStartWebXml);
super.preConfigure(context); super.preConfigure(context);
//generate the quickstart file then abort
QuickStartGeneratorConfiguration generator = new QuickStartGeneratorConfiguration(true); QuickStartGeneratorConfiguration generator = new QuickStartGeneratorConfiguration(true);
configure(generator, context); configure(generator, context);
context.addConfiguration(generator); context.addConfiguration(generator);
break; break;
} }
case AUTO: case AUTO:
{ {
if (quickStartWebXml.exists()) if (quickStartWebXml.exists())
quickStart(context, quickStartWebXml); {
quickStart(context);
}
else else
{ {
if (LOG.isDebugEnabled())
LOG.debug("No quickstart xml file, starting webapp {} normally", context);
super.preConfigure(context); super.preConfigure(context);
QuickStartGeneratorConfiguration generator = new QuickStartGeneratorConfiguration(false);
configure(generator, context);
context.addConfiguration(generator);
} }
break; break;
} }
case QUICKSTART: case QUICKSTART:
if (quickStartWebXml.exists()) if (quickStartWebXml.exists())
quickStart(context, quickStartWebXml); quickStart(context);
else else
throw new IllegalStateException("No " + quickStartWebXml); throw new IllegalStateException("No " + quickStartWebXml);
break; break;
@ -151,27 +154,20 @@ public class QuickStartConfiguration extends AbstractConfiguration
protected void configure(QuickStartGeneratorConfiguration generator, WebAppContext context) throws IOException protected void configure(QuickStartGeneratorConfiguration generator, WebAppContext context) throws IOException
{ {
Object attr; Object attr;
attr = context.getAttribute(GENERATE_ORIGIN);
if (attr != null)
generator.setGenerateOrigin(Boolean.valueOf(attr.toString()));
attr = context.getAttribute(ORIGIN_ATTRIBUTE); attr = context.getAttribute(ORIGIN_ATTRIBUTE);
if (attr != null) if (attr != null)
generator.setOriginAttribute(attr.toString()); generator.setOriginAttribute(attr.toString());
attr = context.getAttribute(QUICKSTART_WEB_XML);
if (attr instanceof Resource) generator.setQuickStartWebXml((Resource)context.getAttribute(QUICKSTART_WEB_XML));
generator.setQuickStartWebXml((Resource)attr);
else if (attr != null)
generator.setQuickStartWebXml(Resource.newResource(attr.toString()));
} }
/**
* @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
*/
@Override @Override
public void configure(WebAppContext context) throws Exception public void configure(WebAppContext context) throws Exception
{ {
if (!_quickStart) if (!_quickStart)
{
super.configure(context); super.configure(context);
}
else else
{ {
//add the processor to handle normal web.xml content //add the processor to handle normal web.xml content
@ -195,14 +191,15 @@ public class QuickStartConfiguration extends AbstractConfiguration
} }
} }
protected void quickStart(WebAppContext context, Resource quickStartWebXml) protected void quickStart(WebAppContext context)
throws Exception throws Exception
{ {
LOG.info("Quickstarting {}", context);
_quickStart = true; _quickStart = true;
context.setConfigurations(context.getWebAppConfigurations().stream() context.setConfigurations(context.getWebAppConfigurations().stream()
.filter(c -> !__replacedConfigurations.contains(c.replaces()) && !__replacedConfigurations.contains(c.getClass())) .filter(c -> !__replacedConfigurations.contains(c.replaces()) && !__replacedConfigurations.contains(c.getClass()))
.collect(Collectors.toList()).toArray(new Configuration[]{})); .collect(Collectors.toList()).toArray(new Configuration[]{}));
context.getMetaData().setWebXml(quickStartWebXml); context.getMetaData().setWebXml((Resource)context.getAttribute(QUICKSTART_WEB_XML));
context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebXml().getMajorVersion()); context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebXml().getMajorVersion());
context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebXml().getMinorVersion()); context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebXml().getMinorVersion());
} }
@ -216,12 +213,38 @@ public class QuickStartConfiguration extends AbstractConfiguration
*/ */
public Resource getQuickStartWebXml(WebAppContext context) throws Exception public Resource getQuickStartWebXml(WebAppContext context) throws Exception
{ {
Object attr = context.getAttribute(QUICKSTART_WEB_XML);
if (attr instanceof Resource)
return (Resource)attr;
Resource webInf = context.getWebInf(); Resource webInf = context.getWebInf();
if (webInf == null || !webInf.exists()) if (webInf == null || !webInf.exists())
throw new IllegalStateException("No WEB-INF"); {
LOG.debug("webinf={}", webInf); File tmp = new File(context.getBaseResource().getFile(), "WEB-INF");
tmp.mkdirs();
webInf = context.getWebInf();
}
Resource quickStartWebXml = webInf.addPath("quickstart-web.xml"); Resource qstart;
return quickStartWebXml; if (attr == null || StringUtil.isBlank(attr.toString()))
{
qstart = webInf.addPath("quickstart-web.xml");
}
else
{
try
{
// Try a relative resolution
qstart = Resource.newResource(webInf.getFile().toPath().resolve(attr.toString()));
}
catch (Throwable th)
{
// try as a resource
qstart = (Resource.newResource(attr.toString()));
}
context.setAttribute(QUICKSTART_WEB_XML, qstart);
}
context.setAttribute(QUICKSTART_WEB_XML, qstart);
return qstart;
} }
} }

View File

@ -52,6 +52,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -61,10 +62,11 @@ import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.MetaData.OriginInfo; import org.eclipse.jetty.webapp.MetaData.OriginInfo;
import org.eclipse.jetty.webapp.MetaInfConfiguration; import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.xml.XmlAppendable; import org.eclipse.jetty.xml.XmlAppendable;
/** /**
* QuickStartDescriptorGenerator * QuickStartGeneratorConfiguration
* <p> * <p>
* Generate an effective web.xml from a WebAppContext, including all components * Generate an effective web.xml from a WebAppContext, including all components
* from web.xml, web-fragment.xmls annotations etc. * from web.xml, web-fragment.xmls annotations etc.
@ -81,10 +83,9 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
protected final boolean _abort; protected final boolean _abort;
protected String _originAttribute; protected String _originAttribute;
protected boolean _generateOrigin;
protected int _count; protected int _count;
protected Resource _quickStartWebXml; protected Resource _quickStartWebXml;
public QuickStartGeneratorConfiguration() public QuickStartGeneratorConfiguration()
{ {
this(false); this(false);
@ -116,22 +117,6 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
return _originAttribute; return _originAttribute;
} }
/**
* @return the generateOrigin
*/
public boolean isGenerateOrigin()
{
return _generateOrigin;
}
/**
* @param generateOrigin the generateOrigin to set
*/
public void setGenerateOrigin(boolean generateOrigin)
{
_generateOrigin = generateOrigin;
}
public Resource getQuickStartWebXml() public Resource getQuickStartWebXml()
{ {
return _quickStartWebXml; return _quickStartWebXml;
@ -163,8 +148,6 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
if (context.getBaseResource() == null) if (context.getBaseResource() == null)
throw new IllegalArgumentException("No base resource for " + this); throw new IllegalArgumentException("No base resource for " + this);
LOG.info("Quickstart generating");
MetaData md = context.getMetaData(); MetaData md = context.getMetaData();
Map<String, String> webappAttr = new HashMap<>(); Map<String, String> webappAttr = new HashMap<>();
@ -195,13 +178,13 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
//the META-INF/resources discovered //the META-INF/resources discovered
addContextParamFromAttribute(context, out, MetaInfConfiguration.METAINF_RESOURCES, normalizer); addContextParamFromAttribute(context, out, MetaInfConfiguration.METAINF_RESOURCES, normalizer);
// the default-context-path, if presernt // the default-context-path, if present
String defaultContextPath = (String)context.getAttribute("default-context-path"); String defaultContextPath = (String)context.getAttribute("default-context-path");
if (defaultContextPath != null) if (defaultContextPath != null)
out.tag("default-context-path", defaultContextPath); out.tag("default-context-path", defaultContextPath);
//add the name of the origin attribute, if it is being used //add the name of the origin attribute, if it is being used
if (_generateOrigin) if (StringUtil.isNotBlank(_originAttribute))
{ {
out.openTag("context-param") out.openTag("context-param")
.tag("param-name", ORIGIN) .tag("param-name", ORIGIN)
@ -766,7 +749,7 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
*/ */
public Map<String, String> origin(MetaData md, String name) public Map<String, String> origin(MetaData md, String name)
{ {
if (!(_generateOrigin || LOG.isDebugEnabled())) if (StringUtil.isBlank(_originAttribute))
return Collections.emptyMap(); return Collections.emptyMap();
if (name == null) if (name == null)
return Collections.emptyMap(); return Collections.emptyMap();
@ -792,13 +775,19 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
{ {
MetaData metadata = context.getMetaData(); MetaData metadata = context.getMetaData();
metadata.resolve(context); metadata.resolve(context);
try (FileOutputStream fos = new FileOutputStream(_quickStartWebXml.getFile(), false))
Resource quickStartWebXml = _quickStartWebXml;
if (_quickStartWebXml == null)
quickStartWebXml = context.getWebInf().addPath("/quickstart-web.xml");
try (FileOutputStream fos = new FileOutputStream(quickStartWebXml.getFile(), false))
{ {
generateQuickStartWebXml(context, fos); generateQuickStartWebXml(context, fos);
LOG.info("Generated {}", _quickStartWebXml);
if (context.getAttribute(WebInfConfiguration.TEMPORARY_RESOURCE_BASE) != null && !context.isPersistTempDirectory())
LOG.warn("Generated to non persistent location: " + _quickStartWebXml);
} }
} }
@Override
public void deconfigure(WebAppContext context) throws Exception
{
super.deconfigure(context);
}
} }

View File

@ -1,90 +0,0 @@
//
// ========================================================================
// 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.quickstart;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.quickstart.QuickStartConfiguration.Mode;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* QuickStartWar
*/
public class QuickStartWebApp extends WebAppContext
{
private final QuickStartConfiguration _quickStartConfiguration;
private String _originAttribute;
private boolean _generateOrigin;
public QuickStartWebApp()
{
super();
addConfiguration(
_quickStartConfiguration = new QuickStartConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration());
setExtractWAR(true);
setCopyWebDir(false);
setCopyWebInf(false);
}
public void setOriginAttribute(String name)
{
setAttribute(QuickStartConfiguration.ORIGIN_ATTRIBUTE, name);
}
/**
* @return the originAttribute
*/
public String getOriginAttribute()
{
Object attr = getAttribute(QuickStartConfiguration.ORIGIN_ATTRIBUTE);
return attr == null ? null : attr.toString();
}
/**
* @param generateOrigin the generateOrigin to set
*/
public void setGenerateOrigin(boolean generateOrigin)
{
setAttribute(QuickStartConfiguration.GENERATE_ORIGIN, generateOrigin);
}
/**
* @return the generateOrigin
*/
public boolean isGenerateOrigin()
{
Object attr = getAttribute(QuickStartConfiguration.GENERATE_ORIGIN);
return attr == null ? false : Boolean.valueOf(attr.toString());
}
public Mode getMode()
{
return _quickStartConfiguration.getMode();
}
public void setMode(Mode mode)
{
_quickStartConfiguration.setMode(mode);
}
}

View File

@ -27,6 +27,7 @@ import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -61,10 +62,11 @@ public class TestQuickStart
Server server = new Server(); Server server = new Server();
//generate a quickstart-web.xml //generate a quickstart-web.xml
QuickStartWebApp quickstart = new QuickStartWebApp(); WebAppContext quickstart = new WebAppContext();
quickstart.addConfiguration(new QuickStartConfiguration());
quickstart.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.GENERATE);
quickstart.setAttribute(QuickStartConfiguration.ORIGIN_ATTRIBUTE, "origin");
quickstart.setResourceBase(testDir.getAbsolutePath()); quickstart.setResourceBase(testDir.getAbsolutePath());
quickstart.setMode(QuickStartConfiguration.Mode.GENERATE);
quickstart.setGenerateOrigin(true);
ServletHolder fooHolder = new ServletHolder(); ServletHolder fooHolder = new ServletHolder();
fooHolder.setServlet(new FooServlet()); fooHolder.setServlet(new FooServlet());
fooHolder.setName("foo"); fooHolder.setName("foo");
@ -73,19 +75,22 @@ public class TestQuickStart
lholder.setListener(new FooContextListener()); lholder.setListener(new FooContextListener());
quickstart.getServletHandler().addListener(lholder); quickstart.getServletHandler().addListener(lholder);
server.setHandler(quickstart); server.setHandler(quickstart);
server.setDryRun(true);
server.start(); server.start();
server.stop();
assertTrue(quickstartXml.exists()); assertTrue(quickstartXml.exists());
//now run the webapp again purely from the generated quickstart //now run the webapp again purely from the generated quickstart
QuickStartWebApp webapp = new QuickStartWebApp(); WebAppContext webapp = new WebAppContext();
webapp.setResourceBase(testDir.getAbsolutePath()); webapp.setResourceBase(testDir.getAbsolutePath());
webapp.setMode(QuickStartConfiguration.Mode.QUICKSTART); webapp.addConfiguration(new QuickStartConfiguration());
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
webapp.setClassLoader(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader())); webapp.setClassLoader(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()));
server.setHandler(webapp); server.setHandler(webapp);
server.setDryRun(false);
server.start(); server.start();
server.dumpStdErr();
//verify that FooServlet is now mapped to / and not the DefaultServlet //verify that FooServlet is now mapped to / and not the DefaultServlet
ServletHolder sh = webapp.getServletHandler().getMappedServlet("/").getResource(); ServletHolder sh = webapp.getServletHandler().getMappedServlet("/").getResource();
@ -104,28 +109,30 @@ public class TestQuickStart
Server server = new Server(); Server server = new Server();
// generate a quickstart-web.xml // generate a quickstart-web.xml
QuickStartWebApp quickstart = new QuickStartWebApp(); WebAppContext quickstart = new WebAppContext();
quickstart.setResourceBase(testDir.getAbsolutePath()); quickstart.setResourceBase(testDir.getAbsolutePath());
quickstart.setMode(QuickStartConfiguration.Mode.GENERATE); quickstart.addConfiguration(new QuickStartConfiguration());
quickstart.setGenerateOrigin(true); quickstart.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.GENERATE);
quickstart.setAttribute(QuickStartConfiguration.ORIGIN_ATTRIBUTE, "origin");
quickstart.setDescriptor(MavenTestingUtils.getTestResourceFile("web.xml").getAbsolutePath()); quickstart.setDescriptor(MavenTestingUtils.getTestResourceFile("web.xml").getAbsolutePath());
quickstart.setContextPath("/foo"); quickstart.setContextPath("/foo");
server.setHandler(quickstart); server.setHandler(quickstart);
server.setDryRun(true);
server.start(); server.start();
assertEquals("/foo", quickstart.getContextPath()); assertEquals("/foo", quickstart.getContextPath());
assertFalse(quickstart.isContextPathDefault()); assertFalse(quickstart.isContextPathDefault());
server.stop();
assertTrue(quickstartXml.exists()); assertTrue(quickstartXml.exists());
// quick start // quick start
QuickStartWebApp webapp = new QuickStartWebApp(); WebAppContext webapp = new WebAppContext();
webapp.addConfiguration(new QuickStartConfiguration());
quickstart.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
webapp.setResourceBase(testDir.getAbsolutePath()); webapp.setResourceBase(testDir.getAbsolutePath());
webapp.setMode(QuickStartConfiguration.Mode.QUICKSTART);
webapp.setClassLoader(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader())); webapp.setClassLoader(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()));
server.setHandler(webapp); server.setHandler(webapp);
server.setDryRun(false);
server.start(); server.start();
// verify the context path is the default-context-path // verify the context path is the default-context-path

View File

@ -79,10 +79,11 @@ public class Server extends HandlerWrapper implements Attributes
private final List<Connector> _connectors = new CopyOnWriteArrayList<>(); private final List<Connector> _connectors = new CopyOnWriteArrayList<>();
private SessionIdManager _sessionIdManager; private SessionIdManager _sessionIdManager;
private boolean _stopAtShutdown; private boolean _stopAtShutdown;
private boolean _dumpAfterStart = false; private boolean _dumpAfterStart;
private boolean _dumpBeforeStop = false; private boolean _dumpBeforeStop;
private ErrorHandler _errorHandler; private ErrorHandler _errorHandler;
private RequestLog _requestLog; private RequestLog _requestLog;
private boolean _dryRun;
private final Locker _dateLocker = new Locker(); private final Locker _dateLocker = new Locker();
private volatile DateField _dateField; private volatile DateField _dateField;
@ -131,6 +132,16 @@ public class Server extends HandlerWrapper implements Attributes
setServer(this); setServer(this);
} }
public boolean isDryRun()
{
return _dryRun;
}
public void setDryRun(boolean dryRun)
{
_dryRun = dryRun;
}
public RequestLog getRequestLog() public RequestLog getRequestLog()
{ {
return _requestLog; return _requestLog;
@ -367,25 +378,33 @@ public class Server extends HandlerWrapper implements Attributes
MultiException mex = new MultiException(); MultiException mex = new MultiException();
// Open network connector to ensure ports are available // Open network connector to ensure ports are available
_connectors.stream().filter(NetworkConnector.class::isInstance).map(NetworkConnector.class::cast).forEach(connector -> if (!_dryRun)
{ {
try _connectors.stream().filter(NetworkConnector.class::isInstance).map(NetworkConnector.class::cast).forEach(connector ->
{ {
connector.open(); try
} {
catch (Throwable th) connector.open();
{ }
mex.add(th); catch (Throwable th)
} {
}); mex.add(th);
}
// Throw now if verified start sequence and there was an open exception });
mex.ifExceptionThrow(); // Throw now if verified start sequence and there was an open exception
mex.ifExceptionThrow();
}
// Start the server and components, but not connectors! // Start the server and components, but not connectors!
// #start(LifeCycle) is overridden so that connectors are not started // #start(LifeCycle) is overridden so that connectors are not started
super.doStart(); super.doStart();
if (_dryRun)
{
LOG.info(String.format("Started(dry run) %s @%dms", this, Uptime.getUptime()));
throw new StopException();
}
// start connectors // start connectors
for (Connector connector : _connectors) for (Connector connector : _connectors)
{ {
@ -400,9 +419,8 @@ public class Server extends HandlerWrapper implements Attributes
_connectors.stream().filter(LifeCycle::isRunning).map(Object.class::cast).forEach(LifeCycle::stop); _connectors.stream().filter(LifeCycle::isRunning).map(Object.class::cast).forEach(LifeCycle::stop);
} }
} }
mex.ifExceptionThrow(); mex.ifExceptionThrow();
LOG.info(String.format("Started @%dms", Uptime.getUptime())); LOG.info(String.format("Started %s @%dms", this, Uptime.getUptime()));
} }
catch (Throwable th) catch (Throwable th)
{ {
@ -423,7 +441,7 @@ public class Server extends HandlerWrapper implements Attributes
} }
finally finally
{ {
if (isDumpAfterStart()) if (isDumpAfterStart() && !(_dryRun && isDumpBeforeStop()))
dumpStdErr(); dumpStdErr();
} }
} }
@ -442,6 +460,7 @@ public class Server extends HandlerWrapper implements Attributes
if (isDumpBeforeStop()) if (isDumpBeforeStop())
dumpStdErr(); dumpStdErr();
LOG.info(String.format("Stopped %s", this));
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("doStop {}", this); LOG.debug("doStop {}", this);

View File

@ -123,7 +123,7 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
if (_server == server) if (_server == server)
return; return;
if (isStarted()) if (isStarted())
throw new IllegalStateException(STARTED); throw new IllegalStateException(getState());
_server = server; _server = server;
} }

View File

@ -128,7 +128,7 @@ public abstract class AbstractHandlerContainer extends AbstractHandler implement
return; return;
if (isStarted()) if (isStarted())
throw new IllegalStateException(STARTED); throw new IllegalStateException(getState());
super.setServer(server); super.setServer(server);
Handler[] handlers = getHandlers(); Handler[] handlers = getHandlers();

View File

@ -2231,7 +2231,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
@Override @Override
public void log(String message, Throwable throwable) public void log(String message, Throwable throwable)
{ {
_logger.warn(message, throwable); if (throwable == null)
_logger.warn(message);
else
_logger.warn(message, throwable);
} }
/* /*

View File

@ -82,7 +82,7 @@ public class HandlerCollection extends AbstractHandlerContainer
public void setHandlers(Handler[] handlers) public void setHandlers(Handler[] handlers)
{ {
if (!_mutableWhenRunning && isStarted()) if (!_mutableWhenRunning && isStarted())
throw new IllegalStateException(STARTED); throw new IllegalStateException(getState());
while (true) while (true)
{ {

View File

@ -74,7 +74,7 @@ public class HandlerWrapper extends AbstractHandlerContainer
public void setHandler(Handler handler) public void setHandler(Handler handler)
{ {
if (isStarted()) if (isStarted())
throw new IllegalStateException(STARTED); throw new IllegalStateException(getState());
// check for loops // check for loops
if (handler == this || (handler instanceof HandlerContainer && if (handler == this || (handler instanceof HandlerContainer &&

View File

@ -34,27 +34,39 @@ public abstract class AbstractLifeCycle implements LifeCycle
{ {
private static final Logger LOG = Log.getLogger(AbstractLifeCycle.class); private static final Logger LOG = Log.getLogger(AbstractLifeCycle.class);
public static final String STOPPED = "STOPPED"; enum State
public static final String FAILED = "FAILED"; {
public static final String STARTING = "STARTING"; STOPPED,
public static final String STARTED = "STARTED"; STARTING,
public static final String STOPPING = "STOPPING"; STARTED,
public static final String RUNNING = "RUNNING"; STOPPING,
FAILED
}
public static final String STOPPED = State.STOPPED.toString();
public static final String FAILED = State.FAILED.toString();
public static final String STARTING = State.STARTING.toString();
public static final String STARTED = State.STARTED.toString();
public static final String STOPPING = State.STOPPING.toString();
private final CopyOnWriteArrayList<LifeCycle.Listener> _listeners = new CopyOnWriteArrayList<LifeCycle.Listener>(); private final CopyOnWriteArrayList<LifeCycle.Listener> _listeners = new CopyOnWriteArrayList<LifeCycle.Listener>();
private final Object _lock = new Object(); private final Object _lock = new Object();
private static final int STATE_FAILED = -1; private volatile State _state = State.STOPPED;
private static final int STATE_STOPPED = 0;
private static final int STATE_STARTING = 1;
private static final int STATE_STARTED = 2;
private static final int STATE_STOPPING = 3;
private volatile int _state = STATE_STOPPED;
private long _stopTimeout = 30000; private long _stopTimeout = 30000;
/**
* Method to override to start the lifecycle
* @throws StopException If thrown, the lifecycle will immediately be stopped.
* @throws Exception If there was a problem starting. Will cause a transition to FAILED state
*/
protected void doStart() throws Exception protected void doStart() throws Exception
{ {
} }
/**
* Method to override to stop the lifecycle
* @throws Exception If there was a problem stopping. Will cause a transition to FAILED state
*/
protected void doStop() throws Exception protected void doStop() throws Exception
{ {
} }
@ -66,11 +78,31 @@ public abstract class AbstractLifeCycle implements LifeCycle
{ {
try try
{ {
if (_state == STATE_STARTED || _state == STATE_STARTING) switch (_state)
return; {
setStarting(); case STARTED:
doStart(); return;
setStarted();
case STARTING:
case STOPPING:
throw new IllegalStateException(getState());
default:
try
{
setStarting();
doStart();
setStarted();
}
catch (StopException e)
{
if (LOG.isDebugEnabled())
LOG.debug(e);
setStopping();
doStop();
setStopped();
}
}
} }
catch (Throwable e) catch (Throwable e)
{ {
@ -87,11 +119,20 @@ public abstract class AbstractLifeCycle implements LifeCycle
{ {
try try
{ {
if (_state == STATE_STOPPING || _state == STATE_STOPPED) switch (_state)
return; {
setStopping(); case STOPPED:
doStop(); return;
setStopped();
case STARTING:
case STOPPING:
throw new IllegalStateException(getState());
default:
setStopping();
doStop();
setStopped();
}
} }
catch (Throwable e) catch (Throwable e)
{ {
@ -104,39 +145,45 @@ public abstract class AbstractLifeCycle implements LifeCycle
@Override @Override
public boolean isRunning() public boolean isRunning()
{ {
final int state = _state; final State state = _state;
switch (state)
return state == STATE_STARTED || state == STATE_STARTING; {
case STARTED:
case STARTING:
return true;
default:
return false;
}
} }
@Override @Override
public boolean isStarted() public boolean isStarted()
{ {
return _state == STATE_STARTED; return _state == State.STARTED;
} }
@Override @Override
public boolean isStarting() public boolean isStarting()
{ {
return _state == STATE_STARTING; return _state == State.STARTING;
} }
@Override @Override
public boolean isStopping() public boolean isStopping()
{ {
return _state == STATE_STOPPING; return _state == State.STOPPING;
} }
@Override @Override
public boolean isStopped() public boolean isStopped()
{ {
return _state == STATE_STOPPED; return _state == State.STOPPED;
} }
@Override @Override
public boolean isFailed() public boolean isFailed()
{ {
return _state == STATE_FAILED; return _state == State.FAILED;
} }
@Override @Override
@ -154,85 +201,73 @@ public abstract class AbstractLifeCycle implements LifeCycle
@ManagedAttribute(value = "Lifecycle State for this instance", readonly = true) @ManagedAttribute(value = "Lifecycle State for this instance", readonly = true)
public String getState() public String getState()
{ {
switch (_state) return _state.toString();
{
case STATE_FAILED:
return FAILED;
case STATE_STARTING:
return STARTING;
case STATE_STARTED:
return STARTED;
case STATE_STOPPING:
return STOPPING;
case STATE_STOPPED:
return STOPPED;
default:
return null;
}
} }
public static String getState(LifeCycle lc) public static String getState(LifeCycle lc)
{ {
if (lc instanceof AbstractLifeCycle)
return ((AbstractLifeCycle)lc)._state.toString();
if (lc.isStarting()) if (lc.isStarting())
return STARTING; return State.STARTING.toString();
if (lc.isStarted()) if (lc.isStarted())
return STARTED; return State.STARTED.toString();
if (lc.isStopping()) if (lc.isStopping())
return STOPPING; return State.STOPPING.toString();
if (lc.isStopped()) if (lc.isStopped())
return STOPPED; return State.STOPPED.toString();
return FAILED; return State.FAILED.toString();
} }
private void setStarted() private void setStarted()
{ {
_state = STATE_STARTED; if (_state == State.STARTING)
if (LOG.isDebugEnabled())
LOG.debug(STARTED + " @{}ms {}", Uptime.getUptime(), this);
for (Listener listener : _listeners)
{ {
listener.lifeCycleStarted(this); _state = State.STARTED;
if (LOG.isDebugEnabled())
LOG.debug("STARTED @{}ms {}", Uptime.getUptime(), this);
for (Listener listener : _listeners)
listener.lifeCycleStarted(this);
} }
} }
private void setStarting() private void setStarting()
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("starting {}", this); LOG.debug("STARTING {}", this);
_state = STATE_STARTING; _state = State.STARTING;
for (Listener listener : _listeners) for (Listener listener : _listeners)
{
listener.lifeCycleStarting(this); listener.lifeCycleStarting(this);
}
} }
private void setStopping() private void setStopping()
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("stopping {}", this); LOG.debug("STOPPING {}", this);
_state = STATE_STOPPING; _state = State.STOPPING;
for (Listener listener : _listeners) for (Listener listener : _listeners)
{
listener.lifeCycleStopping(this); listener.lifeCycleStopping(this);
}
} }
private void setStopped() private void setStopped()
{ {
_state = STATE_STOPPED; if (_state == State.STOPPING)
if (LOG.isDebugEnabled())
LOG.debug("{} {}", STOPPED, this);
for (Listener listener : _listeners)
{ {
listener.lifeCycleStopped(this); _state = State.STOPPED;
if (LOG.isDebugEnabled())
LOG.debug("STOPPED {}", this);
for (Listener listener : _listeners)
{
listener.lifeCycleStopped(this);
}
} }
} }
private void setFailed(Throwable th) private void setFailed(Throwable th)
{ {
_state = STATE_FAILED; _state = State.FAILED;
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.warn(FAILED + " " + this + ": " + th, th); LOG.warn("FAILED " + this + ": " + th, th);
for (Listener listener : _listeners) for (Listener listener : _listeners)
{ {
listener.lifeCycleFailure(this, th); listener.lifeCycleFailure(this, th);
@ -290,4 +325,10 @@ public abstract class AbstractLifeCycle implements LifeCycle
} }
return String.format("%s@%x{%s}", name, hashCode(), getState()); return String.format("%s@%x{%s}", name, hashCode(), getState());
} }
/**
* An exception, which if thrown by doStart will immediately stop the component
*/
public class StopException extends RuntimeException
{}
} }

View File

@ -100,6 +100,8 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
{ {
for (Bean b : _beans) for (Bean b : _beans)
{ {
if (!isStarting())
break;
if (b._bean instanceof LifeCycle) if (b._bean instanceof LifeCycle)
{ {
LifeCycle l = (LifeCycle)b._bean; LifeCycle l = (LifeCycle)b._bean;
@ -127,8 +129,6 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
} }
} }
} }
super.doStart();
} }
catch (Throwable th) catch (Throwable th)
{ {
@ -193,6 +193,8 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
MultiException mex = new MultiException(); MultiException mex = new MultiException();
for (Bean b : reverse) for (Bean b : reverse)
{ {
if (!isStopping())
break;
if (b._managed == Managed.MANAGED && b._bean instanceof LifeCycle) if (b._managed == Managed.MANAGED && b._bean instanceof LifeCycle)
{ {
LifeCycle l = (LifeCycle)b._bean; LifeCycle l = (LifeCycle)b._bean;

View File

@ -403,7 +403,7 @@ public class MetaData
p.process(context, getWebXml()); p.process(context, getWebXml());
for (WebDescriptor wd : getOverrideWebs()) for (WebDescriptor wd : getOverrideWebs())
{ {
LOG.debug("process {} {}", context, wd); LOG.debug("process {} {} {}", context, p, wd);
p.process(context, wd); p.process(context, wd);
} }
} }

View File

@ -38,6 +38,7 @@ public class WebInfConfiguration extends AbstractConfiguration
private static final Logger LOG = Log.getLogger(WebInfConfiguration.class); private static final Logger LOG = Log.getLogger(WebInfConfiguration.class);
public static final String TEMPDIR_CONFIGURED = "org.eclipse.jetty.tmpdirConfigured"; public static final String TEMPDIR_CONFIGURED = "org.eclipse.jetty.tmpdirConfigured";
public static final String TEMPORARY_RESOURCE_BASE = "org.eclipse.jetty.webapp.tmpResourceBase";
protected Resource _preUnpackBaseResource; protected Resource _preUnpackBaseResource;
@ -338,8 +339,11 @@ public class WebInfConfiguration extends AbstractConfiguration
} }
if (extractedWebAppDir == null) if (extractedWebAppDir == null)
{
// Then extract it if necessary to the temporary location // Then extract it if necessary to the temporary location
extractedWebAppDir = new File(context.getTempDirectory(), "webapp"); extractedWebAppDir = new File(context.getTempDirectory(), "webapp");
context.setAttribute(TEMPORARY_RESOURCE_BASE, extractedWebAppDir);
}
if (webApp.getFile() != null && webApp.getFile().isDirectory()) if (webApp.getFile() != null && webApp.getFile().isDirectory())
{ {

View File

@ -36,6 +36,7 @@ import java.nio.file.Paths;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -1747,6 +1748,8 @@ public class XmlConfiguration
properties.putAll(System.getProperties()); properties.putAll(System.getProperties());
// For all arguments, load properties // For all arguments, load properties
if (LOG.isDebugEnabled())
LOG.debug("args={}", Arrays.asList(args));
for (String arg : args) for (String arg : args)
{ {
if (arg.indexOf('=') >= 0) if (arg.indexOf('=') >= 0)
@ -1785,17 +1788,34 @@ public class XmlConfiguration
} }
} }
if (LOG.isDebugEnabled())
LOG.debug("objects={}", Arrays.asList(objects));
// For all objects created by XmlConfigurations, start them if they are lifecycles. // For all objects created by XmlConfigurations, start them if they are lifecycles.
List<LifeCycle> started = new ArrayList<>(objects.size());
for (Object obj : objects) for (Object obj : objects)
{ {
if (obj instanceof LifeCycle) if (obj instanceof LifeCycle)
{ {
LifeCycle lc = (LifeCycle)obj; LifeCycle lc = (LifeCycle)obj;
if (!lc.isRunning()) if (!lc.isRunning())
{
lc.start(); lc.start();
if (lc.isStarted())
started.add(lc);
else
{
// Failed to start a component, so stop all started components
Collections.reverse(started);
for (LifeCycle slc : started)
{
slc.stop();
}
break;
}
}
} }
} }
return null; return null;
}); });
} }

View File

@ -103,7 +103,7 @@ public class BadAppTests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/badapp/"); ContentResponse response = client.GET("http://localhost:" + port + "/badapp/");
@ -143,7 +143,7 @@ public class BadAppTests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/badapp/"); ContentResponse response = client.GET("http://localhost:" + port + "/badapp/");

View File

@ -101,7 +101,7 @@ public class CDITests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/demo/greetings"); ContentResponse response = client.GET("http://localhost:" + port + "/demo/greetings");

View File

@ -56,7 +56,7 @@ public class DemoBaseTests extends AbstractDistributionTest
try (DistributionTester.Run run1 = distribution.start(args)) try (DistributionTester.Run run1 = distribution.start(args))
{ {
assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS)); assertTrue(run1.awaitConsoleLogsFor("Started Server@", 20, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + httpPort + "/test/jsp/dump.jsp"); ContentResponse response = client.GET("http://localhost:" + httpPort + "/test/jsp/dump.jsp");
@ -88,7 +88,7 @@ public class DemoBaseTests extends AbstractDistributionTest
try (DistributionTester.Run run1 = distribution.start(args)) try (DistributionTester.Run run1 = distribution.start(args))
{ {
assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS)); assertTrue(run1.awaitConsoleLogsFor("Started Server@", 20, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response; ContentResponse response;
@ -133,7 +133,7 @@ public class DemoBaseTests extends AbstractDistributionTest
try (DistributionTester.Run run1 = distribution.start(args)) try (DistributionTester.Run run1 = distribution.start(args))
{ {
assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS)); assertTrue(run1.awaitConsoleLogsFor("Started Server@", 20, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.POST("http://localhost:" + httpPort + "/test-spec/asy/xx").send(); ContentResponse response = client.POST("http://localhost:" + httpPort + "/test-spec/asy/xx").send();

View File

@ -41,6 +41,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue;
@ -63,7 +64,7 @@ public class DistributionTests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port); ContentResponse response = client.GET("http://localhost:" + port);
@ -75,6 +76,57 @@ public class DistributionTests extends AbstractDistributionTest
} }
} }
@Test
public void testQuickStartGenerationAndRun() throws Exception
{
String jettyVersion = System.getProperty("jettyVersion");
DistributionTester distribution = DistributionTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.mavenLocalRepository(System.getProperty("mavenRepoPath"))
.build();
String[] args1 = {
"--create-startd",
"--approve-all-licenses",
"--add-to-start=resources,server,http,webapp,deploy,jsp,servlet,servlets,quickstart"
};
try (DistributionTester.Run run1 = distribution.start(args1))
{
assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
try (DistributionTester.Run run2 = distribution.start("jetty.quickstart.mode=GENERATE"))
{
assertTrue(run2.awaitConsoleLogsFor("QuickStartGeneratorConfiguration:main: Generated", 10, TimeUnit.SECONDS));
Path unpackedWebapp = distribution.getJettyBase().resolve("webapps").resolve("test");
assertTrue(Files.exists(unpackedWebapp));
Path webInf = unpackedWebapp.resolve("WEB-INF");
assertTrue(Files.exists(webInf));
Path quickstartWebXml = webInf.resolve("quickstart-web.xml");
assertTrue(Files.exists(quickstartWebXml));
assertNotEquals(0, Files.size(quickstartWebXml));
int port = distribution.freePort();
try (DistributionTester.Run run3 = distribution.start("jetty.http.port=" + port, "jetty.quickstart.mode=QUICKSTART"))
{
assertTrue(run3.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp");
assertEquals(HttpStatus.OK_200, response.getStatus());
assertThat(response.getContentAsString(), containsString("Hello"));
assertThat(response.getContentAsString(), not(containsString("<%")));
}
}
}
}
@Test @Test
public void testSimpleWebAppWithJSP() throws Exception public void testSimpleWebAppWithJSP() throws Exception
{ {
@ -100,7 +152,7 @@ public class DistributionTests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp"); ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp");
@ -141,7 +193,7 @@ public class DistributionTests extends AbstractDistributionTest
}; };
try (DistributionTester.Run run2 = distribution.start(args2)) try (DistributionTester.Run run2 = distribution.start(args2))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp"); ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp");
@ -177,7 +229,7 @@ public class DistributionTests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
HTTP2Client h2Client = new HTTP2Client(); HTTP2Client h2Client = new HTTP2Client();
startHttpClient(() -> new HttpClient(new HttpClientTransportOverHTTP2(h2Client))); startHttpClient(() -> new HttpClient(new HttpClientTransportOverHTTP2(h2Client)));
@ -229,7 +281,7 @@ public class DistributionTests extends AbstractDistributionTest
try (DistributionTester.Run run2 = distribution.start("jetty.unixsocket.path=" + sockFile.toString())) try (DistributionTester.Run run2 = distribution.start("jetty.unixsocket.path=" + sockFile.toString()))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(() -> new HttpClient(new HttpClientTransportOverUnixSockets(sockFile.toString()))); startHttpClient(() -> new HttpClient(new HttpClientTransportOverUnixSockets(sockFile.toString())));
ContentResponse response = client.GET("http://localhost/test/index.jsp"); ContentResponse response = client.GET("http://localhost/test/index.jsp");
@ -272,7 +324,7 @@ public class DistributionTests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp"); ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp");

View File

@ -78,7 +78,7 @@ public class DynamicListenerTests
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/test/testservlet/foo"); ContentResponse response = client.GET("http://localhost:" + port + "/test/testservlet/foo");

View File

@ -57,7 +57,7 @@ public class OsgiAppTests extends AbstractDistributionTest
int port = distribution.freePort(); int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{ {
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
startHttpClient(); startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/test/info"); ContentResponse response = client.GET("http://localhost:" + port + "/test/info");

View File

@ -24,6 +24,9 @@ import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@ -31,6 +34,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebDescriptor; import org.eclipse.jetty.webapp.WebDescriptor;
import org.eclipse.jetty.xml.XmlConfiguration; import org.eclipse.jetty.xml.XmlConfiguration;
import org.eclipse.jetty.xml.XmlParser.Node; import org.eclipse.jetty.xml.XmlParser.Node;
@ -47,6 +51,7 @@ public class QuickStartTest
@Test @Test
public void testStandardTestWar() throws Exception public void testStandardTestWar() throws Exception
{ {
//Generate the quickstart
PreconfigureStandardTestWar.main(new String[]{}); PreconfigureStandardTestWar.main(new String[]{});
WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-standard-preconfigured/WEB-INF/quickstart-web.xml")); WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-standard-preconfigured/WEB-INF/quickstart-web.xml"));
@ -65,8 +70,12 @@ public class QuickStartTest
Server server = new Server(0); Server server = new Server(0);
QuickStartWebApp webapp = new QuickStartWebApp(); WebAppContext webapp = new WebAppContext();
webapp.setMode(QuickStartConfiguration.Mode.AUTO); webapp.addConfiguration(new QuickStartConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration());
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
webapp.setWar(war); webapp.setWar(war);
webapp.setContextPath("/"); webapp.setContextPath("/");
@ -93,6 +102,7 @@ public class QuickStartTest
@Test @Test
public void testSpecWar() throws Exception public void testSpecWar() throws Exception
{ {
//Generate the quickstart xml
PreconfigureSpecWar.main(new String[]{}); PreconfigureSpecWar.main(new String[]{});
Path webXmlPath = MavenTestingUtils.getTargetPath().resolve("test-spec-preconfigured/WEB-INF/quickstart-web.xml"); Path webXmlPath = MavenTestingUtils.getTargetPath().resolve("test-spec-preconfigured/WEB-INF/quickstart-web.xml");
@ -114,8 +124,12 @@ public class QuickStartTest
Server server = new Server(0); Server server = new Server(0);
QuickStartWebApp webapp = new QuickStartWebApp(); WebAppContext webapp = new WebAppContext();
webapp.setMode(QuickStartConfiguration.Mode.AUTO); webapp.addConfiguration(new QuickStartConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration());
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
webapp.setWar(war); webapp.setWar(war);
webapp.setContextPath("/"); webapp.setContextPath("/");
@ -142,6 +156,7 @@ public class QuickStartTest
@Test @Test
public void testJNDIWar() throws Exception public void testJNDIWar() throws Exception
{ {
//Generate the quickstart
PreconfigureJNDIWar.main(new String[]{}); PreconfigureJNDIWar.main(new String[]{});
WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml")); WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml"));
@ -160,8 +175,12 @@ public class QuickStartTest
Server server = new Server(0); Server server = new Server(0);
QuickStartWebApp webapp = new QuickStartWebApp(); WebAppContext webapp = new WebAppContext();
webapp.setMode(QuickStartConfiguration.Mode.AUTO); webapp.addConfiguration(new QuickStartConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration());
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
webapp.setWar(war); webapp.setWar(war);
webapp.setContextPath("/"); webapp.setContextPath("/");

View File

@ -18,8 +18,12 @@
package org.eclipse.jetty.quickstart; package org.eclipse.jetty.quickstart;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration; import org.eclipse.jetty.xml.XmlConfiguration;
public class Quickstart public class Quickstart
@ -40,8 +44,12 @@ public class Quickstart
Server server = new Server(8080); Server server = new Server(8080);
QuickStartWebApp webapp = new QuickStartWebApp(); WebAppContext webapp = new WebAppContext();
webapp.setMode(QuickStartConfiguration.Mode.AUTO); webapp.addConfiguration(new QuickStartConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration());
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
webapp.setWar(war); webapp.setWar(war);
webapp.setContextPath("/"); webapp.setContextPath("/");