diff --git a/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-deploy/src/main/config/etc/jetty-deploy.xml
index 16e5253a86c..c368a06d8fb 100644
--- a/jetty-deploy/src/main/config/etc/jetty-deploy.xml
+++ b/jetty-deploy/src/main/config/etc/jetty-deploy.xml
@@ -18,7 +18,7 @@
org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern
- .*/servlet-api-[^/]*\.jar$
+ .*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/org.apache.taglibs.taglibs-standard-impl-.*\\.jar$
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
index add8f76ce7e..7e50a964333 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
@@ -280,7 +280,7 @@ public class WebAppProvider extends ScanningAppProvider
}
}
};
-
+
xmlc.getIdMap().put("Server", getDeploymentManager().getServer());
xmlc.getProperties().put("jetty.home",System.getProperty("jetty.home","."));
xmlc.getProperties().put("jetty.base",System.getProperty("jetty.base","."));
diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml
index 347c48062c1..433cc613db5 100644
--- a/jetty-distribution/pom.xml
+++ b/jetty-distribution/pom.xml
@@ -695,6 +695,11 @@
jetty-monitor
${project.version}
+
+ org.eclipse.jetty
+ jetty-quickstart
+ ${project.version}
+
org.eclipse.jetty
jetty-start
diff --git a/jetty-quickstart/README.txt b/jetty-quickstart/README.txt
new file mode 100644
index 00000000000..43ad7f3e9f8
--- /dev/null
+++ b/jetty-quickstart/README.txt
@@ -0,0 +1,6 @@
+mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass="org.eclipse.jetty.quickstart.StartBenchmarkWar"
+
+OR
+
+mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass="org.eclipse.jetty.quickstart.PreconfigureBenchmarkWar"
+mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass="org.eclipse.jetty.quickstart.QuickStartBenchmarkWar"
diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml
new file mode 100644
index 00000000000..5f9f03cf978
--- /dev/null
+++ b/jetty-quickstart/pom.xml
@@ -0,0 +1,170 @@
+
+
+ org.eclipse.jetty
+ jetty-project
+ 9.1.4-SNAPSHOT
+
+ 4.0.0
+ org.eclipse.jetty
+ jetty-quickstart
+ Example :: Jetty Quick Start
+ Jetty Quick Start
+ http://www.eclipse.org/jetty
+
+
+ org.eclipse.jetty
+ jetty-webapp
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-jmx
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-plus
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-annotations
+ ${project.version}
+
+
+ javax.transaction
+ javax.transaction-api
+ 1.2
+ compile
+
+
+ org.eclipse.jetty.tests
+ test-mock-resources
+ ${project.version}
+
+
+ org.eclipse.jetty.orbit
+ javax.mail.glassfish
+ 1.4.1.v201005082020
+
+
+ org.eclipse.jetty
+ jetty-servlets
+ ${project.version}
+ test
+
+
+ org.eclipse.jetty.websocket
+ javax-websocket-server-impl
+ ${project.version}
+ test
+
+
+ org.eclipse.jetty.websocket
+ websocket-server
+ ${project.version}
+ test
+
+
+ org.eclipse.jetty
+ apache-jsp
+ ${project.version}
+ test
+
+
+ org.eclipse.jetty
+ apache-jstl
+ ${project.version}
+ test
+
+
+
+
+
+
+ org.codehaus.mojo
+ appassembler-maven-plugin
+ 1.7
+
+
+ unix
+
+
+
+ preconfigure
+ org.eclipse.jetty.quickstart.PreconfigureQuickStartWar
+
+
+ org.eclipse.jetty.quickstart.QuickStartWar
+ quickstart
+
+
+
+
+
+
+ maven-dependency-plugin
+
+
+ copy
+ generate-resources
+
+ copy
+
+
+
+
+ org.eclipse.jetty.tests
+ test-jndi-webapp
+ ${project.version}
+ war
+ true
+ **
+ ${basedir}/target
+ test-jndi.war
+
+
+ org.eclipse.jetty.tests
+ test-spec-webapp
+ ${project.version}
+ war
+ true
+ **
+ ${basedir}/target
+ test-spec.war
+
+
+ org.eclipse.jetty
+ test-jetty-webapp
+ ${project.version}
+ war
+ true
+ **
+ ${basedir}/target
+ test-standard.war
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+ config
+
+
+
+
+
+
+
+
diff --git a/jetty-quickstart/src/main/config/etc/example-quickstart.xml b/jetty-quickstart/src/main/config/etc/example-quickstart.xml
new file mode 100644
index 00000000000..9a012c701ad
--- /dev/null
+++ b/jetty-quickstart/src/main/config/etc/example-quickstart.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ true
+ /
+ /application.war
+
diff --git a/jetty-quickstart/src/main/config/modules/quickstart.mod b/jetty-quickstart/src/main/config/modules/quickstart.mod
new file mode 100644
index 00000000000..89db9fd4fec
--- /dev/null
+++ b/jetty-quickstart/src/main/config/modules/quickstart.mod
@@ -0,0 +1,12 @@
+#
+# Jetty Quickstart module
+#
+
+[depend]
+server
+plus
+annotations
+
+
+[lib]
+lib/jetty-quickstart-${jetty.version}.jar
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureDescriptorProcessor.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureDescriptorProcessor.java
new file mode 100644
index 00000000000..627277e2ebf
--- /dev/null
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureDescriptorProcessor.java
@@ -0,0 +1,88 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 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.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.webapp.Descriptor;
+import org.eclipse.jetty.webapp.IterativeDescriptorProcessor;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.xml.XmlParser;
+
+/**
+ * Preconfigure DescriptorProcessor
+ *
+ * Saves literal XML snippets
+ *
+ */
+
+public class PreconfigureDescriptorProcessor extends IterativeDescriptorProcessor
+{
+ private static final Logger LOG = Log.getLogger(PreconfigureDescriptorProcessor.class);
+
+ private final StringBuilder _buffer = new StringBuilder();
+ private final boolean _showOrigin;
+ private String _origin;
+
+ public PreconfigureDescriptorProcessor ()
+ {
+ _showOrigin=LOG.isDebugEnabled();
+ try
+ {
+ registerVisitor("env-entry", getClass().getDeclaredMethod("saveSnippet", __signature));
+ registerVisitor("resource-ref", getClass().getDeclaredMethod("saveSnippet", __signature));
+ registerVisitor("resource-env-ref", getClass().getDeclaredMethod("saveSnippet", __signature));
+ registerVisitor("message-destination-ref", getClass().getDeclaredMethod("saveSnippet", __signature));
+ registerVisitor("data-source", getClass().getDeclaredMethod("saveSnippet", __signature));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public void start(WebAppContext context, Descriptor descriptor)
+ {
+ LOG.debug("process {}",descriptor);
+ _origin=(" \n");
+ }
+
+
+ @Override
+ public void end(WebAppContext context,Descriptor descriptor)
+ {
+ }
+
+
+ public void saveSnippet (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
+ throws Exception
+ {
+ LOG.debug("save {}",node.getTag());
+ if (_showOrigin)
+ _buffer.append(_origin);
+ _buffer.append(" ").append(node.toString()).append("\n");
+ }
+
+ public String getXML()
+ {
+ return _buffer.toString();
+ }
+
+}
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.java
new file mode 100644
index 00000000000..204ad2ecd15
--- /dev/null
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.java
@@ -0,0 +1,129 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 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.server.Server;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.JarResource;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.xml.XmlConfiguration;
+
+public class PreconfigureQuickStartWar
+{
+ private static final Logger LOG = Log.getLogger(PreconfigureQuickStartWar.class);
+ static final boolean ORIGIN=LOG.isDebugEnabled();
+
+
+ public static void main(String... args) throws Exception
+ {
+ Resource war = null;
+ Resource dir = null;
+ Resource xml = null;
+
+ switch (args.length)
+ {
+ case 0:
+ error("No WAR file or directory given");
+ break;
+
+ case 1:
+ dir = Resource.newResource(args[0]);
+
+ case 2:
+ war = Resource.newResource(args[0]);
+ if (war.isDirectory())
+ {
+ dir = war;
+ war = null;
+ xml = Resource.newResource(args[1]);
+ }
+ else
+ {
+ dir = Resource.newResource(args[1]);
+ }
+
+ break;
+
+ case 3:
+ war = Resource.newResource(args[0]);
+ dir = Resource.newResource(args[1]);
+ xml = Resource.newResource(args[2]);
+ break;
+
+ default:
+ error("Too many args");
+ break;
+ }
+
+
+ preconfigure(war,dir,xml);
+ }
+
+ /**
+ * @param war The war (or directory) to preconfigure
+ * @param dir The directory to expand the war into (or null if war is a directory)
+ * @param xml A context XML to apply (or null if none)
+ * @throws Exception
+ */
+ public static void preconfigure(Resource war, Resource dir, Resource xml) throws Exception
+ {
+ // Do we need to unpack a war?
+ if (war != null)
+ {
+ if (war.isDirectory())
+ error("war file is directory");
+
+ if (!dir.exists())
+ dir.getFile().mkdirs();
+ JarResource.newJarResource(war).copyTo(dir.getFile());
+ }
+
+ final Server server = new Server();
+
+ QuickStartWebApp webapp = new QuickStartWebApp();
+
+ if (xml != null)
+ {
+ if (xml.isDirectory() || !xml.toString().toLowerCase().endsWith(".xml"))
+ error("Bad context.xml: "+xml);
+ XmlConfiguration xmlConfiguration = new XmlConfiguration(xml.getURL());
+ xmlConfiguration.configure(webapp);
+ }
+ webapp.setResourceBase(dir.getFile().getAbsolutePath());
+ webapp.setPreconfigure(true);
+ server.setHandler(webapp);
+ server.start();
+ server.stop();
+ }
+
+
+
+
+ private static void error(String message)
+ {
+ System.err.println("ERROR: " + message);
+ System.err.println("Usage: java -jar PreconfigureQuickStartWar.jar ");
+ System.err.println(" java -jar PreconfigureQuickStartWar.jar ");
+ System.err.println(" java -jar PreconfigureQuickStartWar.jar ");
+ System.err.println(" java -jar PreconfigureQuickStartWar.jar ");
+ System.exit(1);
+ }
+
+}
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
new file mode 100644
index 00000000000..313c5c03c86
--- /dev/null
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
@@ -0,0 +1,139 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 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.annotations.AnnotationDecorator;
+import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.webapp.StandardDescriptorProcessor;
+import org.eclipse.jetty.webapp.WebAppClassLoader;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.WebInfConfiguration;
+
+/**
+ * QuickStartConfiguration
+ *
+ * Re-inflate a deployable webapp from a saved effective-web.xml
+ * which combines all pre-parsed web xml descriptors and annotations.
+ *
+ */
+public class QuickStartConfiguration extends WebInfConfiguration
+{
+ private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class);
+
+ /**
+ * @see org.eclipse.jetty.webapp.AbstractConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
+ */
+ @Override
+ public void preConfigure(WebAppContext context) throws Exception
+ {
+ //check that webapp is suitable for quick start - it is not a packed war
+ String war = context.getWar();
+ if (war == null || war.length()<=0)
+ throw new IllegalStateException ("No location for webapp");
+
+ //Make a temp directory for the webapp if one is not already set
+ resolveTempDirectory(context);
+
+ Resource webApp = context.newResource(war);
+
+ // Accept aliases for WAR files
+ if (webApp.getAlias() != null)
+ {
+ LOG.debug(webApp + " anti-aliased to " + webApp.getAlias());
+ webApp = context.newResource(webApp.getAlias());
+ }
+
+ // Is the WAR usable directly?
+ if (!webApp.exists() || !webApp.isDirectory() || webApp.toString().startsWith("jar:"))
+ throw new IllegalStateException("Webapp does not exist or is not unpacked");
+
+ context.setBaseResource(webApp);
+
+ LOG.debug("webapp={}",webApp);
+
+
+ //look for effective-web.xml in WEB-INF of webapp
+ Resource webInf = context.getWebInf();
+ if (webInf == null || !webInf.exists())
+ throw new IllegalStateException("No WEB-INF");
+ LOG.debug("webinf={}",webInf);
+
+ Resource quickStartWebXml = webInf.addPath("quickstart-web.xml");
+ if (!quickStartWebXml.exists())
+ throw new IllegalStateException ("No WEB-INF/quickstart-web.xml");
+ LOG.debug("quickStartWebXml={}",quickStartWebXml);
+
+ context.getMetaData().setWebXml(quickStartWebXml);
+ }
+
+
+ /**
+ * @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
+ */
+ @Override
+ public void configure(WebAppContext context) throws Exception
+ {
+ LOG.debug("configure {}",this);
+ if (context.isStarted())
+ {
+ LOG.warn("Cannot configure webapp after it is started");
+ return;
+ }
+
+ //Temporary: set up the classpath here. This should be handled by the QuickStartDescriptorProcessor
+ Resource webInf = context.getWebInf();
+
+ if (webInf != null && webInf.isDirectory() && context.getClassLoader() instanceof WebAppClassLoader)
+ {
+ // Look for classes directory
+ Resource classes= webInf.addPath("classes/");
+ if (classes.exists())
+ ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);
+
+ // Look for jars
+ Resource lib= webInf.addPath("lib/");
+ if (lib.exists() || lib.isDirectory())
+ ((WebAppClassLoader)context.getClassLoader()).addJars(lib);
+ }
+
+ //add the processor to handle normal web.xml content
+ context.getMetaData().addDescriptorProcessor(new StandardDescriptorProcessor());
+
+ //add a processor to handle extended web.xml format
+ context.getMetaData().addDescriptorProcessor(new QuickStartDescriptorProcessor());
+
+ //add a decorator that will find introspectable annotations
+ context.addDecorator(new AnnotationDecorator(context)); //this must be the last Decorator because they are run in reverse order!
+
+ //add a context bean that will run ServletContainerInitializers as the context starts
+ ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER);
+ if (starter != null)
+ throw new IllegalStateException("ServletContainerInitializersStarter already exists");
+ starter = new ServletContainerInitializersStarter(context);
+ context.setAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER, starter);
+ context.addBean(starter, true);
+
+ LOG.debug("configured {}",this);
+ }
+
+}
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
new file mode 100644
index 00000000000..7e5a6c849b9
--- /dev/null
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
@@ -0,0 +1,218 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.jetty.annotations.AnnotationConfiguration;
+import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
+import org.eclipse.jetty.plus.annotation.ContainerInitializer;
+import org.eclipse.jetty.util.QuotedStringTokenizer;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.resource.ResourceCollection;
+import org.eclipse.jetty.webapp.Descriptor;
+import org.eclipse.jetty.webapp.IterativeDescriptorProcessor;
+import org.eclipse.jetty.webapp.MetaInfConfiguration;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.xml.XmlParser;
+
+/**
+ * QuickStartDescriptorProcessor
+ *
+ * Handle extended elements for quickstart-web.xml
+ */
+public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
+{
+ /**
+ *
+ */
+ public QuickStartDescriptorProcessor()
+ {
+ try
+ {
+ registerVisitor("context-param", this.getClass().getDeclaredMethod("visitContextParam", __signature));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.Descriptor)
+ */
+ @Override
+ public void start(WebAppContext context, Descriptor descriptor)
+ {
+ }
+
+ /**
+ * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.Descriptor)
+ */
+ @Override
+ public void end(WebAppContext context, Descriptor descriptor)
+ {
+ }
+
+
+ /**
+ * @param context
+ * @param descriptor
+ * @param node
+ */
+ public void visitContextParam (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
+ throws Exception
+ {
+ String name = node.getString("param-name", false, true);
+ String value = node.getString("param-value", false, true);
+ List values = new ArrayList<>();
+
+ // extract values
+ switch(name)
+ {
+ case ServletContext.ORDERED_LIBS:
+ case AnnotationConfiguration.CONTAINER_INITIALIZERS:
+ case MetaInfConfiguration.METAINF_TLDS:
+ case MetaInfConfiguration.METAINF_RESOURCES:
+
+ context.removeAttribute(name);
+
+ QuotedStringTokenizer tok = new QuotedStringTokenizer(value,",");
+ while(tok.hasMoreElements())
+ values.add(tok.nextToken().trim());
+
+ break;
+
+ default:
+ values.add(value);
+ }
+
+ // handle values
+ switch(name)
+ {
+ case ServletContext.ORDERED_LIBS:
+ {
+ List