diff options
author | Greg Wilkins | 2014-03-17 07:22:36 +0000 |
---|---|---|
committer | Greg Wilkins | 2014-03-18 22:56:19 +0000 |
commit | 119718d86fb773ae9c5839639107de4be126999e (patch) | |
tree | 1788a20ec32bd5e4e5f59143c7ac5b8af42496d2 /jetty-quickstart | |
parent | 1ffd308bbef7c9cad816631131c1029fe7ac88db (diff) | |
download | org.eclipse.jetty.project-119718d86fb773ae9c5839639107de4be126999e.tar.gz org.eclipse.jetty.project-119718d86fb773ae9c5839639107de4be126999e.tar.xz org.eclipse.jetty.project-119718d86fb773ae9c5839639107de4be126999e.zip |
added jetty-quickstart module
Diffstat (limited to 'jetty-quickstart')
20 files changed, 2001 insertions, 0 deletions
diff --git a/jetty-quickstart/README.txt b/jetty-quickstart/README.txt new file mode 100644 index 0000000000..43ad7f3e9f --- /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 0000000000..5f9f03cf97 --- /dev/null +++ b/jetty-quickstart/pom.xml @@ -0,0 +1,170 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-project</artifactId> + <version>9.1.4-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-quickstart</artifactId> + <name>Example :: Jetty Quick Start</name> + <description>Jetty Quick Start</description> + <url>http://www.eclipse.org/jetty</url> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-jmx</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-plus</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-annotations</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>javax.transaction</groupId> + <artifactId>javax.transaction-api</artifactId> + <version>1.2</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>test-mock-resources</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.mail.glassfish</artifactId> + <version>1.4.1.v201005082020</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlets</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>javax-websocket-server-impl</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>websocket-server</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>apache-jsp</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>apache-jstl</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <plugins> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>appassembler-maven-plugin</artifactId> + <version>1.7</version> + <configuration> + <platforms> + <platform>unix</platform> + </platforms> + <programs> + <program> + <id>preconfigure</id> + <mainClass>org.eclipse.jetty.quickstart.PreconfigureQuickStartWar</mainClass> + </program> + <program> + <mainClass>org.eclipse.jetty.quickstart.QuickStartWar</mainClass> + <id>quickstart</id> + </program> + </programs> + </configuration> + </plugin> + + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy</id> + <phase>generate-resources</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>test-jndi-webapp</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${basedir}/target</outputDirectory> + <destFileName>test-jndi.war</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>test-spec-webapp</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${basedir}/target</outputDirectory> + <destFileName>test-spec.war</destFileName> + </artifactItem> + <artifactItem> + <groupId>org.eclipse.jetty</groupId> + <artifactId>test-jetty-webapp</artifactId> + <version>${project.version}</version> + <type>war</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${basedir}/target</outputDirectory> + <destFileName>test-standard.war</destFileName> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + <configuration> + <descriptorRefs> + <descriptorRef>config</descriptorRef> + </descriptorRefs> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> 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 0000000000..9a012c701a --- /dev/null +++ b/jetty-quickstart/src/main/config/etc/example-quickstart.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_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> +</Configure> 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 0000000000..89db9fd4fe --- /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 0000000000..627277e2eb --- /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=(" <!-- "+descriptor+" -->\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 0000000000..204ad2ecd1 --- /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 <war-directory>"); + System.err.println(" java -jar PreconfigureQuickStartWar.jar <war-directory> <context-xml-file>"); + System.err.println(" java -jar PreconfigureQuickStartWar.jar <war-file> <target-war-directory>"); + System.err.println(" java -jar PreconfigureQuickStartWar.jar <war-file> <target-war-directory> <context-xml-file>"); + 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 0000000000..313c5c03c8 --- /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 0000000000..7e5a6c849b --- /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<String> 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<Object> libs = new ArrayList<>(); + Object o=context.getAttribute(ServletContext.ORDERED_LIBS); + if (o instanceof Collection<?>) + libs.addAll((Collection<?>)o); + libs.addAll(values); + if (libs.size()>0) + context.setAttribute(ServletContext.ORDERED_LIBS,libs); + + break; + } + + case AnnotationConfiguration.CONTAINER_INITIALIZERS: + { + for (String i : values) + visitContainerInitializer(context, new ContainerInitializer(Thread.currentThread().getContextClassLoader(), i)); + break; + } + + case MetaInfConfiguration.METAINF_TLDS: + { + List<Object> tlds = new ArrayList<>(); + String war=context.getBaseResource().getURI().toString(); + Object o=context.getAttribute(MetaInfConfiguration.METAINF_TLDS); + if (o instanceof Collection<?>) + tlds.addAll((Collection<?>)o); + for (String i : values) + { + Resource r = Resource.newResource(i.replace("${WAR}/",war)); + if (r.exists()) + tlds.add(r.getURL()); + else + throw new IllegalArgumentException("TLD not found: "+r); + } + + if (tlds.size()>0) + context.setAttribute(MetaInfConfiguration.METAINF_TLDS,tlds); + break; + } + + case MetaInfConfiguration.METAINF_RESOURCES: + { + String war=context.getBaseResource().getURI().toString(); + for (String i : values) + { + Resource r = Resource.newResource(i.replace("${WAR}/",war)); + if (r.exists()) + visitMetaInfResource(context,r); + else + throw new IllegalArgumentException("Resource not found: "+r); + } + break; + } + + default: + + } + } + + + public void visitContainerInitializer (WebAppContext context, ContainerInitializer containerInitializer) + { + if (containerInitializer == null) + return; + + //add the ContainerInitializer to the list of container initializers + List<ContainerInitializer> containerInitializers = (List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); + if (containerInitializers == null) + { + containerInitializers = new ArrayList<ContainerInitializer>(); + context.setAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS, containerInitializers); + } + + containerInitializers.add(containerInitializer); + + //Ensure a bean is set up on the context that will invoke the ContainerInitializers as the context starts + ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER); + if (starter == null) + { + starter = new ServletContainerInitializersStarter(context); + context.setAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER, starter); + context.addBean(starter, true); + } + } + + + public void visitMetaInfResource (WebAppContext context, Resource dir) + { + Collection<Resource> metaInfResources = (Collection<Resource>)context.getAttribute(MetaInfConfiguration.METAINF_RESOURCES); + if (metaInfResources == null) + { + metaInfResources = new HashSet<Resource>(); + context.setAttribute(MetaInfConfiguration.METAINF_RESOURCES, metaInfResources); + } + metaInfResources.add(dir); + //also add to base resource of webapp + Resource[] collection=new Resource[metaInfResources.size()+1]; + int i=0; + collection[i++]=context.getBaseResource(); + for (Resource resource : metaInfResources) + collection[i++]=resource; + context.setBaseResource(new ResourceCollection(collection)); + } +} diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java new file mode 100644 index 0000000000..bcbcab8080 --- /dev/null +++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java @@ -0,0 +1,720 @@ +// +// ======================================================================== +// 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.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.servlet.DispatcherType; +import javax.servlet.MultipartConfigElement; +import javax.servlet.ServletContext; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspPropertyGroupDescriptor; +import javax.servlet.descriptor.TaglibDescriptor; + +import org.eclipse.jetty.annotations.AnnotationConfiguration; +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.plus.annotation.LifeCycleCallback; +import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; +import org.eclipse.jetty.security.ConstraintAware; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.SecurityHandler; +import org.eclipse.jetty.security.authentication.FormAuthenticator; +import org.eclipse.jetty.servlet.ErrorPageErrorHandler; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; +import org.eclipse.jetty.servlet.Holder; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.util.QuotedStringTokenizer; +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.util.security.Constraint; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.MetaData.OriginInfo; +import org.eclipse.jetty.webapp.MetaInfConfiguration; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.xml.XmlAppendable; + +/** + * QuickStartWar + * + */ +public class QuickStartWebApp extends WebAppContext +{ + private static final Logger LOG = Log.getLogger(QuickStartWebApp.class); + + public static final String[] __configurationClasses = new String[] + { + org.eclipse.jetty.quickstart.QuickStartConfiguration.class.getCanonicalName(), + org.eclipse.jetty.plus.webapp.EnvConfiguration.class.getCanonicalName(), + org.eclipse.jetty.plus.webapp.PlusConfiguration.class.getCanonicalName(), + org.eclipse.jetty.webapp.JettyWebXmlConfiguration.class.getCanonicalName() + }; + + + private boolean _preconfigure=false; + private boolean _autoPreconfigure=false; + private boolean _startWebapp=false; + private PreconfigureDescriptorProcessor _preconfigProcessor; + + + public static final String[] __preconfigurationClasses = new String[] + { + org.eclipse.jetty.webapp.WebInfConfiguration.class.getCanonicalName(), + org.eclipse.jetty.webapp.WebXmlConfiguration.class.getCanonicalName(), + org.eclipse.jetty.webapp.MetaInfConfiguration.class.getCanonicalName(), + org.eclipse.jetty.webapp.FragmentConfiguration.class.getCanonicalName(), + org.eclipse.jetty.plus.webapp.EnvConfiguration.class.getCanonicalName(), + org.eclipse.jetty.plus.webapp.PlusConfiguration.class.getCanonicalName(), + org.eclipse.jetty.annotations.AnnotationConfiguration.class.getCanonicalName(), + }; + + public QuickStartWebApp() + { + super(); + setConfigurationClasses(__preconfigurationClasses); + setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*\\.jar"); + } + + public boolean isPreconfigure() + { + return _preconfigure; + } + + /* ------------------------------------------------------------ */ + /** Preconfigure webapp + * @param preconfigure If true, then starting the webapp will generate + * the WEB-INF/quickstart-web.xml rather than start the webapp. + */ + public void setPreconfigure(boolean preconfigure) + { + _preconfigure = preconfigure; + } + + public boolean isAutoPreconfigure() + { + return _autoPreconfigure; + } + + public void setAutoPreconfigure(boolean autoPrecompile) + { + _autoPreconfigure = autoPrecompile; + } + + @Override + protected void startWebapp() throws Exception + { + if (isPreconfigure()) + generateQuickstartWebXml(_preconfigProcessor.getXML()); + + if (_startWebapp) + super.startWebapp(); + } + + @Override + protected void doStart() throws Exception + { + // unpack and Adjust paths. + Resource war = null; + Resource dir = null; + + Resource base = getBaseResource(); + if (base==null) + base=Resource.newResource(getWar()); + + if (base.isDirectory()) + dir=base; + else if (base.toString().toLowerCase().endsWith(".war")) + { + war=base; + String w=war.toString(); + dir=Resource.newResource(w.substring(0,w.length()-4)); + + if (!dir.exists()) + { + LOG.info("Quickstart Extract " + war + " to " + dir); + dir.getFile().mkdirs(); + JarResource.newJarResource(war).copyTo(dir.getFile()); + } + + setWar(null); + setBaseResource(dir); + } + else + throw new IllegalArgumentException(); + + + Resource qswebxml=dir.addPath("/WEB-INF/quickstart-web.xml"); + + if (isPreconfigure()) + { + _preconfigProcessor = new PreconfigureDescriptorProcessor(); + getMetaData().addDescriptorProcessor(_preconfigProcessor); + _startWebapp=false; + } + else if (qswebxml.exists()) + { + setConfigurationClasses(__configurationClasses); + _startWebapp=true; + } + else if (_autoPreconfigure) + { + LOG.info("Quickstart preconfigure: {}(war={},dir={})",this,war,dir); + + _preconfigProcessor = new PreconfigureDescriptorProcessor(); + + getMetaData().addDescriptorProcessor(_preconfigProcessor); + setPreconfigure(true); + _startWebapp=true; + } + else + _startWebapp=true; + + super.doStart(); + } + + + public void generateQuickstartWebXml(String extraXML) throws IOException + { + getMetaData().getOrigins(); + // dumpStdErr(); + + if (getBaseResource()==null) + throw new IllegalArgumentException("No base resource for "+this); + + File webxml = new File(getWebInf().getFile(),"quickstart-web.xml"); + + LOG.info("Quickstart generate {}",webxml); + + XmlAppendable out = new XmlAppendable(new FileOutputStream(webxml),"UTF-8"); + MetaData md = getMetaData(); + + Map<String, String> webappAttr = new HashMap<>(); + webappAttr.put("xmlns","http://xmlns.jcp.org/xml/ns/javaee"); + webappAttr.put("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); + webappAttr.put("xsi:schemaLocation","http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"); + webappAttr.put("metadata-complete","true"); + webappAttr.put("version","3.1"); + + out.open("web-app",webappAttr); + + if (getDisplayName() != null) + out.tag("display-name",getDisplayName()); + + // Set some special context parameters + + // The location of the war file on disk + String resourceBase=getBaseResource().getFile().getCanonicalFile().getAbsoluteFile().toURI().toString(); + + // The library order + addContextParamFromAttribute(out,ServletContext.ORDERED_LIBS); + //the servlet container initializers + addContextParamFromAttribute(out,AnnotationConfiguration.CONTAINER_INITIALIZERS); + //the tlds discovered + addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,resourceBase); + //the META-INF/resources discovered + addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,resourceBase); + + + // init params + for (String p : getInitParams().keySet()) + out.open("context-param",origin(md,"context-param." + p)) + .tag("param-name",p) + .tag("param-value",getInitParameter(p)) + .close(); + + if (getEventListeners() != null) + for (EventListener e : getEventListeners()) + out.open("listener",origin(md,e.getClass().getCanonicalName() + ".listener")) + .tag("listener-class",e.getClass().getCanonicalName()) + .close(); + + ServletHandler servlets = getServletHandler(); + + if (servlets.getFilters() != null) + { + for (FilterHolder holder : servlets.getFilters()) + outholder(out,md,"filter",holder); + } + + if (servlets.getFilterMappings() != null) + { + for (FilterMapping mapping : servlets.getFilterMappings()) + { + out.open("filter-mapping"); + out.tag("filter-name",mapping.getFilterName()); + if (mapping.getPathSpecs() != null) + for (String s : mapping.getPathSpecs()) + out.tag("url-pattern",s); + if (mapping.getServletNames() != null) + for (String n : mapping.getServletNames()) + out.tag("servlet-name",n); + + if (!mapping.isDefaultDispatches()) + { + if (mapping.appliesTo(DispatcherType.REQUEST)) + out.tag("dispatcher","REQUEST"); + if (mapping.appliesTo(DispatcherType.ASYNC)) + out.tag("dispatcher","ASYNC"); + if (mapping.appliesTo(DispatcherType.ERROR)) + out.tag("dispatcher","ERROR"); + if (mapping.appliesTo(DispatcherType.FORWARD)) + out.tag("dispatcher","FORWARD"); + if (mapping.appliesTo(DispatcherType.INCLUDE)) + out.tag("dispatcher","INCLUDE"); + } + out.close(); + } + } + + if (servlets.getServlets() != null) + { + for (ServletHolder holder : servlets.getServlets()) + outholder(out,md,"servlet",holder); + } + + if (servlets.getServletMappings() != null) + { + for (ServletMapping mapping : servlets.getServletMappings()) + { + out.open("servlet-mapping",origin(md,mapping.getServletName() + ".servlet.mappings")); + out.tag("servlet-name",mapping.getServletName()); + if (mapping.getPathSpecs() != null) + for (String s : mapping.getPathSpecs()) + out.tag("url-pattern",s); + out.close(); + } + } + + // Security elements + SecurityHandler security = getSecurityHandler(); + + if (security!=null && (security.getRealmName()!=null || security.getAuthMethod()!=null)) + { + out.open("login-config"); + if (security.getAuthMethod()!=null) + out.tag("auth-method",origin(md,"auth-method"),security.getAuthMethod()); + if (security.getRealmName()!=null) + out.tag("realm-name",origin(md,"realm-name"),security.getRealmName()); + + + if (Constraint.__FORM_AUTH.equalsIgnoreCase(security.getAuthMethod())) + { + out.open("form-login-config"); + out.tag("form-login-page",origin(md,"form-login-page"),security.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE)); + out.tag("form-error-page",origin(md,"form-error-page"),security.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE)); + out.close(); + } + + out.close(); + } + + if (security instanceof ConstraintAware) + { + ConstraintAware ca = (ConstraintAware)security; + for (String r:ca.getRoles()) + out.open("security-role") + .tag("role-name",r) + .close(); + + for (ConstraintMapping m : ca.getConstraintMappings()) + { + out.open("security-constraint"); + + if (m.getConstraint().getAuthenticate()) + { + out.open("auth-constraint"); + if (m.getConstraint().getRoles()!=null) + for (String r : m.getConstraint().getRoles()) + out.tag("role-name",r); + + out.close(); + } + + switch (m.getConstraint().getDataConstraint()) + { + case Constraint.DC_NONE: + out.open("user-data-constraint").tag("transport-guarantee","NONE").close(); + break; + + case Constraint.DC_INTEGRAL: + out.open("user-data-constraint").tag("transport-guarantee","INTEGRAL").close(); + break; + + case Constraint.DC_CONFIDENTIAL: + out.open("user-data-constraint").tag("transport-guarantee","CONFIDENTIAL").close(); + break; + + default: + break; + + } + + out.open("web-resource-collection"); + { + if (m.getConstraint().getName()!=null) + out.tag("web-resource-name",m.getConstraint().getName()); + if (m.getPathSpec()!=null) + out.tag("url-pattern",origin(md,"constraint.url."+m.getPathSpec()),m.getPathSpec()); + if (m.getMethod()!=null) + out.tag("http-method",m.getMethod()); + + if (m.getMethodOmissions()!=null) + for (String o:m.getMethodOmissions()) + out.tag("http-method-omission",o); + + out.close(); + } + + out.close(); + + } + } + + if (getWelcomeFiles() != null) + { + out.open("welcome-file-list"); + for (String welcomeFile:getWelcomeFiles()) + { + out.tag("welcome-file", welcomeFile); + } + out.close(); + } + + Map<String,String> localeEncodings = getLocaleEncodings(); + if (localeEncodings != null && !localeEncodings.isEmpty()) + { + out.open("locale-encoding-mapping-list"); + for (Map.Entry<String, String> entry:localeEncodings.entrySet()) + { + out.open("locale-encoding-mapping", origin(md,"locale-encoding."+entry.getKey())); + out.tag("locale", entry.getKey()); + out.tag("encoding", entry.getValue()); + out.close(); + } + out.close(); + } + + //session-config + if (getSessionHandler().getSessionManager() != null) + { + out.open("session-config"); + int maxInactiveSec = getSessionHandler().getSessionManager().getMaxInactiveInterval(); + out.tag("session-timeout", (maxInactiveSec==0?"0":Integer.toString(maxInactiveSec/60))); + + Set<SessionTrackingMode> modes = getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes(); + if (modes != null) + { + for (SessionTrackingMode mode:modes) + out.tag("tracking-mode", mode.toString()); + } + + //cookie-config + SessionCookieConfig cookieConfig = getSessionHandler().getSessionManager().getSessionCookieConfig(); + if (cookieConfig != null) + { + out.open("cookie-config"); + if (cookieConfig.getName() != null) + out.tag("name", origin(md,"cookie-config.name"), cookieConfig.getName()); + + if (cookieConfig.getDomain() != null) + out.tag("domain", origin(md, "cookie-config.domain"), cookieConfig.getDomain()); + + if (cookieConfig.getPath() != null) + out.tag("path", origin(md, "cookie-config.path"), cookieConfig.getPath()); + + if (cookieConfig.getComment() != null) + out.tag("comment", origin(md, "cookie-config.comment"), cookieConfig.getComment()); + + out.tag("http-only", origin(md, "cookie-config.http-only"), Boolean.toString(cookieConfig.isHttpOnly())); + out.tag("secure", origin(md, "cookie-config.secure"), Boolean.toString(cookieConfig.isSecure())); + out.tag("max-age", origin(md, "cookie-config.max-age"), Integer.toString(cookieConfig.getMaxAge())); + out.close(); + } + out.close(); + } + + //error-pages + Map<String,String> errorPages = ((ErrorPageErrorHandler)getErrorHandler()).getErrorPages(); + if (errorPages != null) + { + for (Map.Entry<String, String> entry:errorPages.entrySet()) + { + out.open("error-page", origin(md, "error."+entry.getKey())); + //a global or default error page has no code or exception + if (!ErrorPageErrorHandler.GLOBAL_ERROR_PAGE.equals(entry.getKey())) + { + if (entry.getKey().matches("\\d{3}")) + out.tag("error-code", entry.getKey()); + else + out.tag("exception-type", entry.getKey()); + } + out.tag("location", entry.getValue()); + out.close(); + } + } + + //mime-types + MimeTypes mimeTypes = getMimeTypes(); + if (mimeTypes != null) + { + for (Map.Entry<String, String> entry:mimeTypes.getMimeMap().entrySet()) + { + out.open("mime-mapping"); + out.tag("extension", origin(md, "extension."+entry.getKey()), entry.getKey()); + out.tag("mime-type", entry.getValue()); + out.close(); + } + } + + //jsp-config + JspConfig jspConfig = (JspConfig)getServletContext().getJspConfigDescriptor(); + if (jspConfig != null) + { + out.open("jsp-config"); + Collection<TaglibDescriptor> tlds = jspConfig.getTaglibs(); + if (tlds != null && !tlds.isEmpty()) + { + for (TaglibDescriptor tld:tlds) + { + out.open("taglib"); + out.tag("taglib-uri", tld.getTaglibURI()); + out.tag("taglib-location", tld.getTaglibLocation()); + out.close(); + } + } + + Collection<JspPropertyGroupDescriptor> jspPropertyGroups = jspConfig.getJspPropertyGroups(); + if (jspPropertyGroups != null && !jspPropertyGroups.isEmpty()) + { + for (JspPropertyGroupDescriptor jspPropertyGroup:jspPropertyGroups) + { + out.open("jsp-property-group"); + Collection<String> strings = jspPropertyGroup.getUrlPatterns(); + if (strings != null && !strings.isEmpty()) + { + for (String urlPattern:strings) + out.tag("url-pattern", urlPattern); + } + + if (jspPropertyGroup.getElIgnored() != null) + out.tag("el-ignored", jspPropertyGroup.getElIgnored()); + + if (jspPropertyGroup.getPageEncoding() != null) + out.tag("page-encoding", jspPropertyGroup.getPageEncoding()); + + if (jspPropertyGroup.getScriptingInvalid() != null) + out.tag("scripting-invalid", jspPropertyGroup.getScriptingInvalid()); + + if (jspPropertyGroup.getIsXml() != null) + out.tag("is-xml", jspPropertyGroup.getIsXml()); + + if (jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral() != null) + out.tag("deferred-syntax-allowed-as-literal", jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral()); + + if (jspPropertyGroup.getTrimDirectiveWhitespaces() != null) + out.tag("trim-directive-whitespaces", jspPropertyGroup.getTrimDirectiveWhitespaces()); + + if (jspPropertyGroup.getDefaultContentType() != null) + out.tag("default-content-type", jspPropertyGroup.getDefaultContentType()); + + if (jspPropertyGroup.getBuffer() != null) + out.tag("buffer", jspPropertyGroup.getBuffer()); + + if (jspPropertyGroup.getErrorOnUndeclaredNamespace() != null) + out.tag("error-on-undeclared-namespace", jspPropertyGroup.getErrorOnUndeclaredNamespace()); + + strings = jspPropertyGroup.getIncludePreludes(); + if (strings != null && !strings.isEmpty()) + { + for (String prelude:strings) + out.tag("include-prelude", prelude); + } + + strings = jspPropertyGroup.getIncludeCodas(); + if (strings != null && !strings.isEmpty()) + { + for (String coda:strings) + out.tag("include-coda", coda); + } + + out.close(); + } + } + + out.close(); + } + + //lifecycle: post-construct, pre-destroy + LifeCycleCallbackCollection lifecycles = ((LifeCycleCallbackCollection)getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)); + if (lifecycles != null) + { + Collection<LifeCycleCallback> tmp = lifecycles.getPostConstructCallbacks(); + + for (LifeCycleCallback c:tmp) + { + out.open("post-construct"); + out.tag("lifecycle-callback-class", c.getTargetClassName()); + out.tag("lifecycle-callback-method", c.getMethodName()); + out.close(); + } + + tmp = lifecycles.getPreDestroyCallbacks(); + for (LifeCycleCallback c:tmp) + { + out.open("pre-destroy"); + out.tag("lifecycle-callback-class", c.getTargetClassName()); + out.tag("lifecycle-callback-method", c.getMethodName()); + out.close(); + } + } + + out.literal(extraXML); + + out.close(); + } + + private void addContextParamFromAttribute(XmlAppendable out, String attribute) throws IOException + { + addContextParamFromAttribute(out,attribute,null); + } + + private void addContextParamFromAttribute(XmlAppendable out, String attribute, String resourceBase) throws IOException + { + Object o=getAttribute(attribute); + if (o==null) + return; + + Collection<?> c = (o instanceof Collection)? (Collection<?>)o:Collections.singletonList(o); + StringBuilder v=new StringBuilder(); + for (Object i:c) + { + if (i!=null) + { + if (v.length()>0) + v.append(",\n "); + else + v.append("\n "); + if (resourceBase==null) + QuotedStringTokenizer.quote(v,i.toString()); + else + QuotedStringTokenizer.quote(v,i.toString().replace(resourceBase,"${WAR}/")); + } + } + out.open("context-param") + .tag("param-name",attribute) + .tagCDATA("param-value",v.toString()) + .close(); + } + + private static void outholder(XmlAppendable out, MetaData md, String tag, Holder<?> holder) throws IOException + { + out.open(tag,Collections.singletonMap("source",holder.getSource().toString())); + String n = holder.getName(); + out.tag(tag + "-name",n); + + String ot = n + "." + tag + "."; + + out.tag(tag + "-class",origin(md,ot + tag + "-class"),holder.getClassName()); + + for (String p : holder.getInitParameters().keySet()) + { + if ("scratchdir".equalsIgnoreCase(p)) //don't preconfigure the temp dir for jsp output + continue; + out.open("init-param",origin(md,ot + "init-param." + p)) + .tag("param-name",p) + .tag("param-value",holder.getInitParameter(p)) + .close(); + } + + if (holder instanceof ServletHolder) + { + ServletHolder s = (ServletHolder)holder; + if (s.getForcedPath() != null) + out.tag("jsp-file",s.getForcedPath()); + + if (s.getInitOrder() != 0) + out.tag("load-on-startup",Integer.toString(s.getInitOrder())); + + if (s.getRunAsRole() != null) + out.open("run-as",origin(md,ot + "run-as")) + .tag("role-name",s.getRunAsRole()) + .close(); + + Map<String,String> roles = s.getRoleRefMap(); + if (roles!=null) + { + for (Map.Entry<String, String> e : roles.entrySet()) + { + out.open("security-role-ref",origin(md,ot+"role-name."+e.getKey())) + .tag("role-name",e.getKey()) + .tag("role-link",e.getValue()) + .close(); + } + } + + if (!s.isEnabled()) + out.tag("enabled",origin(md,ot + "enabled"),"false"); + + //multipart-config + MultipartConfigElement multipartConfig = ((ServletHolder.Registration)s.getRegistration()).getMultipartConfig(); + if (multipartConfig != null) + { + out.open("multipart-config", origin(md, s.getName()+".servlet.multipart-config")); + if (multipartConfig.getLocation() != null) + out.tag("location", multipartConfig.getLocation()); + out.tag("max-file-size", Long.toString(multipartConfig.getMaxFileSize())); + out.tag("max-request-size", Long.toString(multipartConfig.getMaxRequestSize())); + out.tag("file-size-threshold", Long.toString(multipartConfig.getFileSizeThreshold())); + out.close(); + } + } + + out.tag("async-supported",origin(md,ot + "async-supported"),holder.isAsyncSupported()?"true":"false"); + out.close(); + } + + public static Map<String, String> origin(MetaData md, String name) + { + if (!LOG.isDebugEnabled()) + return Collections.emptyMap(); + if (name == null) + return Collections.emptyMap(); + OriginInfo origin = md.getOriginInfo(name); + // System.err.println("origin of "+name+" is "+origin); + if (origin == null) + return Collections.emptyMap(); + return Collections.singletonMap("origin",origin.toString()); + + } + +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java new file mode 100644 index 0000000000..570b724cae --- /dev/null +++ b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java @@ -0,0 +1,49 @@ +// +// ======================================================================== +// 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.io.File; +import java.io.FileInputStream; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class PreconfigureJNDIWar +{ + private static final long __start=System.nanoTime(); + private static final Logger LOG = Log.getLogger(Server.class); + + public static void main(String[] args) throws Exception + { + String target="target/test-jndi-preconfigured"; + File file = new File(target); + if (file.exists()) + IO.delete(file); + + PreconfigureQuickStartWar.main("target/test-jndi.war",target, "src/test/resources/test-jndi.xml"); + + LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start)); + + IO.copy(new FileInputStream("target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml"),System.out); + } + +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java new file mode 100644 index 0000000000..f8b49c77c2 --- /dev/null +++ b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java @@ -0,0 +1,58 @@ +// +// ======================================================================== +// 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.io.File; +import java.io.FileInputStream; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; + +public class PreconfigureSpecWar +{ + private static final long __start=System.nanoTime(); + private static final Logger LOG = Log.getLogger(Server.class); + + public static void main(String[] args) throws Exception + { + String target="target/test-spec-preconfigured"; + File file = new File(target); + if (file.exists()) + IO.delete(file); + + File realmPropertiesDest = new File ("target/test-spec-realm.properties"); + if (realmPropertiesDest.exists()) + IO.delete(realmPropertiesDest); + + Resource realmPropertiesSrc = Resource.newResource("src/test/resources/realm.properties"); + realmPropertiesSrc.copyTo(realmPropertiesDest); + System.setProperty("jetty.home", "target"); + + PreconfigureQuickStartWar.main("target/test-spec.war",target, "src/test/resources/test-spec.xml"); + + LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start)); + + IO.copy(new FileInputStream("target/test-spec-preconfigured/WEB-INF/quickstart-web.xml"),System.out); + } + +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java new file mode 100644 index 0000000000..91e424165e --- /dev/null +++ b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java @@ -0,0 +1,62 @@ +// +// ======================================================================== +// 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.io.File; +import java.io.FileInputStream; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; + +/** + * PreconfigureStandardTestWar + * + */ +public class PreconfigureStandardTestWar +{ + + private static final long __start=System.nanoTime(); + private static final Logger LOG = Log.getLogger(Server.class); + + public static void main(String[] args) throws Exception + { + String target="target/test-standard-preconfigured"; + File file = new File(target); + if (file.exists()) + IO.delete(file); + + File realmPropertiesDest = new File ("target/test-standard-realm.properties"); + if (realmPropertiesDest.exists()) + IO.delete(realmPropertiesDest); + + Resource realmPropertiesSrc = Resource.newResource("src/test/resources/realm.properties"); + realmPropertiesSrc.copyTo(realmPropertiesDest); + System.setProperty("jetty.home", "target"); + + PreconfigureQuickStartWar.main("target/test-standard.war",target, "src/test/resources/test.xml"); + + LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start)); + + IO.copy(new FileInputStream("target/test-standard-preconfigured/WEB-INF/quickstart-web.xml"),System.out); + } +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java new file mode 100644 index 0000000000..07bc1b6648 --- /dev/null +++ b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java @@ -0,0 +1,31 @@ +// +// ======================================================================== +// 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; + +public class QuickStartJNDIWar +{ + + public static void main(String... args) throws Exception + { + // Log.getRootLogger().setDebugEnabled(true); + Quickstart.main("target/test-jndi-preconfigured", "src/test/resources/test-jndi.xml"); + } + + +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java new file mode 100644 index 0000000000..b84a12f298 --- /dev/null +++ b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java @@ -0,0 +1,30 @@ +// +// ======================================================================== +// 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; + + +public class QuickStartSpecWar +{ + public static void main(String... args) throws Exception + { + // Log.getRootLogger().setDebugEnabled(true); + System.setProperty("jetty.home", "target"); + Quickstart.main("target/test-spec-preconfigured", "src/test/resources/test-spec.xml"); + } +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java new file mode 100644 index 0000000000..7da8b23465 --- /dev/null +++ b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java @@ -0,0 +1,30 @@ +// +// ======================================================================== +// 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; + +public class QuickStartStandardTestWar +{ + + public static void main(String... args) throws Exception + { + // Log.getRootLogger().setDebugEnabled(true); + System.setProperty("jetty.home", "target"); + Quickstart.main("target/test-standard-preconfigured", "src/test/resources/test.xml"); + } +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java new file mode 100644 index 0000000000..75dc114e10 --- /dev/null +++ b/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java @@ -0,0 +1,73 @@ +// +// ======================================================================== +// 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.resource.Resource; +import org.eclipse.jetty.xml.XmlConfiguration; + +public class Quickstart +{ + + public static void main(String... args) throws Exception + { + if (args.length<1) + error("No WAR file or directory given"); + + //war file or dir to start + String war = args[0]; + + //optional jetty context xml file to configure the webapp + Resource contextXml = null; + if (args.length > 1) + contextXml = Resource.newResource(args[1]); + + Server server = new Server(8080); + + QuickStartWebApp webapp = new QuickStartWebApp(); + webapp.setAutoPreconfigure(true); + webapp.setWar(war); + webapp.setContextPath("/"); + + //apply context xml file + if (contextXml != null) + { + // System.err.println("Applying "+contextXml); + XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml.getURL()); + xmlConfiguration.configure(webapp); + } + + server.setHandler(webapp); + + server.start(); + + + + server.join(); + } + + + private static void error(String message) + { + System.err.println("ERROR: "+message); + System.err.println("Usage: java -jar QuickStartWar.jar <war-directory> <context-xml>"); + System.err.println(" java -jar QuickStartWar.jar <war-file> <context-xml>"); + System.exit(1); + } +} diff --git a/jetty-quickstart/src/test/resources/realm.properties b/jetty-quickstart/src/test/resources/realm.properties new file mode 100644 index 0000000000..9d88b852b7 --- /dev/null +++ b/jetty-quickstart/src/test/resources/realm.properties @@ -0,0 +1,21 @@ +# +# This file defines users passwords and roles for a HashUserRealm +# +# The format is +# <username>: <password>[,<rolename> ...] +# +# Passwords may be clear text, obfuscated or checksummed. The class +# org.eclipse.util.Password should be used to generate obfuscated +# passwords or password checksums +# +# If DIGEST Authentication is used, the password must be in a recoverable +# format, either plain text or OBF:. +# +jetty: MD5:164c88b302622e17050af52c89945d44,user +admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin,user +other: OBF:1xmk1w261u9r1w1c1xmq,user +plain: plain,user +user: password,user + +# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password +digest: MD5:6e120743ad67abfbc385bc2bb754e297,user diff --git a/jetty-quickstart/src/test/resources/test-jndi.xml b/jetty-quickstart/src/test/resources/test-jndi.xml new file mode 100644 index 0000000000..14c0934845 --- /dev/null +++ b/jetty-quickstart/src/test/resources/test-jndi.xml @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> + +<!-- =============================================================== --> +<!-- Configure the test-jndi webapp --> +<!-- =============================================================== --> +<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> + + <New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction"> + <Arg> + <New class="com.acme.MockUserTransaction"/> + </Arg> + </New> + + <!-- Define an env entry with Server scope for java:comp/env --> + <New id="woggle" class="org.eclipse.jetty.plus.jndi.EnvEntry"> + <Arg><Property name='server'/></Arg> + <Arg>woggle</Arg> + <Arg type="java.lang.Integer">4000</Arg> + <Arg type="boolean">false</Arg> + </New> + + <!-- Define an env entry with webapp scope for java:comp/env --> + <New id="wiggle" class="org.eclipse.jetty.plus.jndi.EnvEntry"> + <Arg><Ref refid='wac'/></Arg> + <Arg>wiggle</Arg> + <Arg type="java.lang.Double">100</Arg> + <Arg type="boolean">true</Arg> + </New> + + <!-- Mail Session setup --> + <New id="xxxmail" class="org.eclipse.jetty.plus.jndi.Resource"> + <Arg><Ref refid='wac'/></Arg> + <Arg>mail/Session</Arg> + <Arg> + <New class="org.eclipse.jetty.jndi.factories.MailSessionReference"> + <Set name="user">CHANGE-ME</Set> + <Set name="password">CHANGE-ME</Set> + <Set name="properties"> + <New class="java.util.Properties"> + <Put name="mail.smtp.auth">false</Put> <!-- change to true if you want to authenticate --> + <Put name="mail.smtp.host">CHANGE-ME</Put> + <Put name="mail.from">CHANGE-ME</Put> + <Put name="mail.debug">false</Put> + </New> + </Set> + </New> + </Arg> + </New> + + <!-- A mock DataSource --> + <New id="mydatasource" class="org.eclipse.jetty.plus.jndi.Resource"> + <Arg><Ref refid='wac'/></Arg> + <Arg>jdbc/mydatasource</Arg> + <Arg> + <New class="com.acme.MockDataSource"/> + </Arg> + </New> + +</Configure> diff --git a/jetty-quickstart/src/test/resources/test-spec.xml b/jetty-quickstart/src/test/resources/test-spec.xml new file mode 100644 index 0000000000..99fc577205 --- /dev/null +++ b/jetty-quickstart/src/test/resources/test-spec.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> + +<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> + + <New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction"> + <Arg> + <New class="com.acme.MockUserTransaction"/> + </Arg> + </New> + + <Get name="securityHandler"> + <Set name="loginService"> + <New class="org.eclipse.jetty.security.HashLoginService"> + <Set name="name">Test Realm</Set> + <Set name="config"><SystemProperty name="jetty.home" default="."/>/test-spec-realm.properties</Set> + </New> + </Set> + </Get> + + + <New id="maxAmount" class="org.eclipse.jetty.plus.jndi.EnvEntry"> + <Arg><Ref refid='wac'/></Arg> + <Arg>maxAmount</Arg> + <Arg type="java.lang.Double">100</Arg> + <Arg type="boolean">true</Arg> + </New> + + + <New id="mydatasource" class="org.eclipse.jetty.plus.jndi.Resource"> + <Arg><Ref refid='wac'/></Arg> + <Arg>jdbc/mydatasource</Arg> + <Arg> + <New class="com.acme.MockDataSource"> + </New> + </Arg> + </New> + +</Configure> diff --git a/jetty-quickstart/src/test/resources/test.xml b/jetty-quickstart/src/test/resources/test.xml new file mode 100644 index 0000000000..bbdf08a23a --- /dev/null +++ b/jetty-quickstart/src/test/resources/test.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> + +<!-- ================================================================== +Configure and deploy the test web application in $(jetty.home)/webapps/test + +Note. If this file did not exist or used a context path other that /test +then the default configuration of jetty.xml would discover the test +webapplication with a WebAppDeployer. By specifying a context in this +directory, additional configuration may be specified and hot deployments +detected. +===================================================================== --> + +<Configure class="org.eclipse.jetty.webapp.WebAppContext"> + + <Set name="contextPath">/test</Set> + + <Get name="securityHandler"> + <Set name="loginService"> + <New class="org.eclipse.jetty.security.HashLoginService"> + <Set name="name">Test Realm</Set> + <Set name="config"><SystemProperty name="jetty.home" default="."/>/test-standard-realm.properties</Set> + </New> + </Set> + <Set name="authenticator"> + <New class="org.eclipse.jetty.security.authentication.FormAuthenticator"> + <Set name="alwaysSaveUri">true</Set> + </New> + </Set> + <Set name="checkWelcomeFiles">true</Set> + </Get> + + <!-- Non standard error page mapping --> + <!-- + <Get name="errorHandler"> + <Call name="addErrorPage"> + <Arg type="int">500</Arg> + <Arg type="int">599</Arg> + <Arg type="String">/dump/errorCodeRangeMapping</Arg> + </Call> + </Get> + --> + + +</Configure> |