Merge branch 'jetty-9.4.x' into issue-207

This commit is contained in:
Joakim Erdfelt 2016-10-12 11:36:28 -07:00
commit 82942cb3a4
480 changed files with 18932 additions and 9478 deletions

6
Jenkinsfile vendored
View File

@ -20,8 +20,10 @@ node {
{ {
stage 'Compile' stage 'Compile'
withEnv(mvnEnv) { withEnv(mvnEnv) {
timeout(15) {
sh "mvn -B clean install -Dtest=None" sh "mvn -B clean install -Dtest=None"
} }
}
} catch(Exception e) { } catch(Exception e) {
notifyBuild("Compile Failure") notifyBuild("Compile Failure")
throw e throw e
@ -31,8 +33,10 @@ node {
{ {
stage 'Javadoc' stage 'Javadoc'
withEnv(mvnEnv) { withEnv(mvnEnv) {
timeout(15) {
sh "mvn -B javadoc:javadoc" sh "mvn -B javadoc:javadoc"
} }
}
} catch(Exception e) { } catch(Exception e) {
notifyBuild("Javadoc Failure") notifyBuild("Javadoc Failure")
throw e throw e
@ -41,8 +45,8 @@ node {
try try
{ {
stage 'Test' stage 'Test'
timeout(60) {
withEnv(mvnEnv) { withEnv(mvnEnv) {
timeout(60) {
// Run test phase / ignore test failures // Run test phase / ignore test failures
sh "mvn -B install -Dmaven.test.failure.ignore=true" sh "mvn -B install -Dmaven.test.failure.ignore=true"
// Report failures in the jenkins UI // Report failures in the jenkins UI

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@
org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package> </Export-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability> <Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer</Provide-Capability> <Provide-Capability>osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=org.apache.juli.logging.Log</Provide-Capability>
<_nouses>true</_nouses> <_nouses>true</_nouses>
</instructions> </instructions>
</configuration> </configuration>

View File

@ -23,7 +23,6 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
/** /**
* Simple Jetty FileServer. * Simple Jetty FileServer.
@ -41,6 +40,7 @@ public class FileServer
// Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is // Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is
// a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples. // a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples.
ResourceHandler resource_handler = new ResourceHandler(); ResourceHandler resource_handler = new ResourceHandler();
// Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of. // Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of.
// In this example it is the current directory but it can be configured to anything that the jvm has access to. // In this example it is the current directory but it can be configured to anything that the jvm has access to.
resource_handler.setDirectoriesListed(true); resource_handler.setDirectoriesListed(true);
@ -48,11 +48,9 @@ public class FileServer
resource_handler.setResourceBase("."); resource_handler.setResourceBase(".");
// Add the ResourceHandler to the server. // Add the ResourceHandler to the server.
GzipHandler gzip = new GzipHandler();
server.setHandler(gzip);
HandlerList handlers = new HandlerList(); HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() }); handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
gzip.setHandler(handlers); server.setHandler(handlers);
// Start things up! By using the server.join() the server thread will join with the current thread. // Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details. // See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.

View File

@ -30,7 +30,6 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.rewrite.handler.RewriteHandler; import org.eclipse.jetty.rewrite.handler.RewriteHandler;
import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.ConnectorStatistics;
import org.eclipse.jetty.server.DebugListener; import org.eclipse.jetty.server.DebugListener;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
@ -39,6 +38,7 @@ import org.eclipse.jetty.server.LowResourceMonitor;
import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnectionStatistics;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
@ -193,7 +193,7 @@ public class LikeJettyXml
StatisticsHandler stats = new StatisticsHandler(); StatisticsHandler stats = new StatisticsHandler();
stats.setHandler(server.getHandler()); stats.setHandler(server.getHandler());
server.setHandler(stats); server.setHandler(stats);
ConnectorStatistics.addToAllConnectors(server); ServerConnectionStatistics.addToAllConnectors(server);
// === Rewrite Handler // === Rewrite Handler
RewriteHandler rewrite = new RewriteHandler(); RewriteHandler rewrite = new RewriteHandler();

View File

@ -21,8 +21,8 @@ package org.eclipse.jetty.embedded;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.ConnectorStatistics;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnectionStatistics;
import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
@ -44,7 +44,7 @@ public class OneServletContextJmxStats
context.addServlet(DefaultServlet.class, "/"); context.addServlet(DefaultServlet.class, "/");
// Add Connector Statistics tracking to all connectors // Add Connector Statistics tracking to all connectors
ConnectorStatistics.addToAllConnectors(server); ServerConnectionStatistics.addToAllConnectors(server);
server.start(); server.start();
server.join(); server.join();

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.annotations;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -48,6 +47,7 @@ import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
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;
@ -81,8 +81,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>(); protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
protected List<ParserTask> _parserTasks; protected List<ParserTask> _parserTasks;
protected WebAppClassNameResolver _webAppClassNameResolver;
protected ContainerClassNameResolver _containerClassNameResolver;
protected CounterStatistic _containerPathStats; protected CounterStatistic _containerPathStats;
protected CounterStatistic _webInfLibStats; protected CounterStatistic _webInfLibStats;
@ -138,15 +136,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected Exception _exception; protected Exception _exception;
protected final AnnotationParser _parser; protected final AnnotationParser _parser;
protected final Set<? extends Handler> _handlers; protected final Set<? extends Handler> _handlers;
protected final ClassNameResolver _resolver;
protected final Resource _resource; protected final Resource _resource;
protected TimeStatistic _stat; protected TimeStatistic _stat;
public ParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver) public ParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource)
{ {
_parser = parser; _parser = parser;
_handlers = handlers; _handlers = handlers;
_resolver = resolver;
_resource = resource; _resource = resource;
} }
@ -160,7 +156,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_stat != null) if (_stat != null)
_stat.start(); _stat.start();
if (_parser != null) if (_parser != null)
_parser.parse(_handlers, _resource, _resolver); _parser.parse(_handlers, _resource);
if (_stat != null) if (_stat != null)
_stat.end(); _stat.end();
return null; return null;
@ -175,82 +171,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
{ {
return _resource; return _resource;
} }
}
/**
* WebAppClassNameResolver
*
* Checks to see if a classname belongs to hidden or visible packages when scanning,
* and whether a classname that is a duplicate should override a previously
* scanned classname.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class WebAppClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public WebAppClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return true;
if (_context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class
//of same name - did it come from system or duplicate in webapp?
if (_context.isParentLoaderPriority())
return false;
return true;
}
}
/**
* ContainerClassNameResolver
*
* Checks to see if a classname belongs to a hidden or visible package
* when scanning for annotations and thus whether it should be excluded from
* consideration or not.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class ContainerClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public ContainerClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return false;
if (_context.isServerClass(name)) return true;
return false;
}
public boolean shouldOverride (String name)
{
//visiting the container classpath,
if (_context.isParentLoaderPriority())
return true;
return false;
}
} }
@ -390,8 +310,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override @Override
public void preConfigure(final WebAppContext context) throws Exception public void preConfigure(final WebAppContext context) throws Exception
{ {
_webAppClassNameResolver = new WebAppClassNameResolver(context);
_containerClassNameResolver = new ContainerClassNameResolver(context);
String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN); String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN);
_sciExcludePattern = (tmp==null?null:Pattern.compile(tmp)); _sciExcludePattern = (tmp==null?null:Pattern.compile(tmp));
} }
@ -723,23 +641,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getJarFor (ServletContainerInitializer service) public Resource getJarFor (ServletContainerInitializer service)
throws MalformedURLException, IOException throws MalformedURLException, IOException
{ {
//try the thread context classloader to get the jar that loaded the class return TypeUtil.getLoadedFrom(service.getClass());
URL jarURL = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class");
//if for some reason that failed (eg we're in osgi and the TCCL does not know about the service) try the classloader that
//loaded the class
if (jarURL == null)
jarURL = service.getClass().getClassLoader().getResource(service.getClass().getName().replace('.','/')+".class");
String loadingJarName = jarURL.toString();
int i = loadingJarName.indexOf(".jar");
if (i < 0)
return null; //not from a jar
loadingJarName = loadingJarName.substring(0,i+4);
loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName);
return Resource.newResource(loadingJarName);
} }
/** /**
@ -760,26 +662,41 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (context == null) if (context == null)
throw new IllegalArgumentException("WebAppContext null"); throw new IllegalArgumentException("WebAppContext null");
if (LOG.isDebugEnabled()) LOG.debug("Checking {} for jar exclusion", sci);
//A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering //A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering
//of WEB-INF/lib jars //of WEB-INF/lib jars
if (isFromContainerClassPath(context, sci)) if (isFromContainerClassPath(context, sci))
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} from container classpath", sci);
return false; return false;
}
//If no ordering, nothing is excluded //If no ordering, nothing is excluded
if (context.getMetaData().getOrdering() == null) if (context.getMetaData().getOrdering() == null)
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} no ordering", sci);
return false; return false;
}
List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars(); List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
//there is an ordering, but there are no jars resulting from the ordering, everything excluded //there is an ordering, but there are no jars resulting from the ordering, everything excluded
if (orderedJars.isEmpty()) if (orderedJars.isEmpty())
{
if (LOG.isDebugEnabled())
LOG.debug("Excluded {} empty ordering", sci);
return true; return true;
}
if (sciResource == null) if (sciResource == null)
return false; //not from a jar therefore not from WEB-INF so not excludable {
//not from a jar therefore not from WEB-INF so not excludable
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} not from jar", sci);
return false;
}
URI loadingJarURI = sciResource.getURI(); URI loadingJarURI = sciResource.getURI();
boolean found = false; boolean found = false;
@ -790,10 +707,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
found = r.getURI().equals(loadingJarURI); found = r.getURI().equals(loadingJarURI);
} }
if (LOG.isDebugEnabled())
LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found);
return !found; return !found;
} }
/** /**
* Test if the ServletContainerIntializer is excluded by the * Test if the ServletContainerIntializer is excluded by the
* o.e.j.containerInitializerExclusionPattern * o.e.j.containerInitializerExclusionPattern
@ -808,7 +726,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
return false; return false;
//test if name of class matches the regex //test if name of class matches the regex
if (LOG.isDebugEnabled()) LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName()); if (LOG.isDebugEnabled())
LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName());
return _sciExcludePattern.matcher(sci.getClass().getName()).matches(); return _sciExcludePattern.matcher(sci.getClass().getName()).matches();
} }
@ -866,17 +785,18 @@ public class AnnotationConfiguration extends AbstractConfiguration
//because containerInitializerOrdering omits it //because containerInitializerOrdering omits it
for (ServletContainerInitializer sci:_loadedInitializers) for (ServletContainerInitializer sci:_loadedInitializers)
{ {
if (matchesExclusionPattern(sci)) if (matchesExclusionPattern(sci))
{ {
if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci); if (LOG.isDebugEnabled())
LOG.debug("{} excluded by pattern", sci);
continue; continue;
} }
Resource sciResource = getJarFor(sci); Resource sciResource = getJarFor(sci);
if (isFromExcludedJar(context, sci, sciResource)) if (isFromExcludedJar(context, sci, sciResource))
{ {
if (LOG.isDebugEnabled()) LOG.debug("{} is from excluded jar", sci); if (LOG.isDebugEnabled())
LOG.debug("{} is from excluded jar", sci);
continue; continue;
} }
@ -885,7 +805,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (initializerOrdering != null if (initializerOrdering != null
&& (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0)) && (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0))
{ {
if (LOG.isDebugEnabled()) LOG.debug("{} is excluded by ordering", sci); if (LOG.isDebugEnabled())
LOG.debug("{} is excluded by ordering", sci);
continue; continue;
} }
@ -912,12 +833,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
//no web.xml ordering defined, add SCIs in any order //no web.xml ordering defined, add SCIs in any order
if (context.getMetaData().getOrdering() == null) if (context.getMetaData().getOrdering() == null)
{ {
if (LOG.isDebugEnabled()) LOG.debug("No web.xml ordering, ServletContainerInitializers in random order"); if (LOG.isDebugEnabled())
LOG.debug("No web.xml ordering, ServletContainerInitializers in random order");
nonExcludedInitializers.addAll(sciResourceMap.keySet()); nonExcludedInitializers.addAll(sciResourceMap.keySet());
} }
else else
{ {
if (LOG.isDebugEnabled()) LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering()); if (LOG.isDebugEnabled())
LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering());
for (Map.Entry<ServletContainerInitializer, Resource> entry:sciResourceMap.entrySet()) for (Map.Entry<ServletContainerInitializer, Resource> entry:sciResourceMap.entrySet())
{ {
//add in SCIs from the container classpath //add in SCIs from the container classpath
@ -992,7 +915,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
//queue it up for scanning if using multithreaded mode //queue it up for scanning if using multithreaded mode
if (_parserTasks != null) if (_parserTasks != null)
{ {
ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver); ParserTask task = new ParserTask(parser, handlers, r);
_parserTasks.add(task); _parserTasks.add(task);
_containerPathStats.increment(); _containerPathStats.increment();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -1054,7 +977,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_parserTasks != null) if (_parserTasks != null)
{ {
ParserTask task = new ParserTask(parser, handlers,r, _webAppClassNameResolver); ParserTask task = new ParserTask(parser, handlers,r);
_parserTasks.add (task); _parserTasks.add (task);
_webInfLibStats.increment(); _webInfLibStats.increment();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -1087,7 +1010,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
{ {
if (_parserTasks != null) if (_parserTasks != null)
{ {
ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver); ParserTask task = new ParserTask(parser, handlers, dir);
_parserTasks.add(task); _parserTasks.add(task);
_webInfClassesStats.increment(); _webInfClassesStats.increment();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())

View File

@ -544,18 +544,15 @@ public class AnnotationParser
* *
* @param handlers the set of handlers to find class * @param handlers the set of handlers to find class
* @param className the class name to parse * @param className the class name to parse
* @param resolver the class name resolver to use
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
public void parse (Set<? extends Handler> handlers, String className, ClassNameResolver resolver) public void parse (Set<? extends Handler> handlers, String className)
throws Exception throws Exception
{ {
if (className == null) if (className == null)
return; return;
if (!resolver.isExcluded(className)) if (!isParsed(className))
{
if (!isParsed(className) || resolver.shouldOverride(className))
{ {
className = className.replace('.', '/')+".class"; className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className); URL resource = Loader.getResource(className);
@ -569,7 +566,6 @@ public class AnnotationParser
} }
} }
} }
}
@ -578,19 +574,16 @@ public class AnnotationParser
* *
* @param handlers the handlers to look for class in * @param handlers the handlers to look for class in
* @param clazz the class to look for * @param clazz the class to look for
* @param resolver the resolver to look up class with
* @param visitSuperClasses if true, also visit super classes for parse * @param visitSuperClasses if true, also visit super classes for parse
* @throws Exception if unable to parse class * @throws Exception if unable to parse class
*/ */
public void parse (Set<? extends Handler> handlers, Class<?> clazz, ClassNameResolver resolver, boolean visitSuperClasses) public void parse (Set<? extends Handler> handlers, Class<?> clazz, boolean visitSuperClasses)
throws Exception throws Exception
{ {
Class<?> cz = clazz; Class<?> cz = clazz;
while (cz != null) while (cz != null)
{ {
if (!resolver.isExcluded(cz.getName())) if (!isParsed(cz.getName()))
{
if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
{ {
String nameAsResource = cz.getName().replace('.', '/')+".class"; String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource); URL resource = Loader.getResource(nameAsResource);
@ -603,7 +596,7 @@ public class AnnotationParser
} }
} }
} }
}
if (visitSuperClasses) if (visitSuperClasses)
cz = cz.getSuperclass(); cz = cz.getSuperclass();
@ -619,16 +612,15 @@ public class AnnotationParser
* *
* @param handlers the set of handlers to look for class in * @param handlers the set of handlers to look for class in
* @param classNames the class name * @param classNames the class name
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
public void parse (Set<? extends Handler> handlers, String[] classNames, ClassNameResolver resolver) public void parse (Set<? extends Handler> handlers, String[] classNames)
throws Exception throws Exception
{ {
if (classNames == null) if (classNames == null)
return; return;
parse(handlers, Arrays.asList(classNames), resolver); parse(handlers, Arrays.asList(classNames));
} }
@ -637,10 +629,9 @@ public class AnnotationParser
* *
* @param handlers the set of handlers to look for class in * @param handlers the set of handlers to look for class in
* @param classNames the class names * @param classNames the class names
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
public void parse (Set<? extends Handler> handlers, List<String> classNames, ClassNameResolver resolver) public void parse (Set<? extends Handler> handlers, List<String> classNames)
throws Exception throws Exception
{ {
MultiException me = new MultiException(); MultiException me = new MultiException();
@ -649,7 +640,7 @@ public class AnnotationParser
{ {
try try
{ {
if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s)))) if (!isParsed(s))
{ {
s = s.replace('.', '/')+".class"; s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(s); URL resource = Loader.getResource(s);
@ -677,10 +668,9 @@ public class AnnotationParser
* *
* @param handlers the set of handlers to look for classes in * @param handlers the set of handlers to look for classes in
* @param dir the resource directory to look for classes * @param dir the resource directory to look for classes
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
protected void parseDir (Set<? extends Handler> handlers, Resource dir, ClassNameResolver resolver) protected void parseDir (Set<? extends Handler> handlers, Resource dir)
throws Exception throws Exception
{ {
// skip dirs whose name start with . (ie hidden) // skip dirs whose name start with . (ie hidden)
@ -696,7 +686,7 @@ public class AnnotationParser
{ {
Resource res = dir.addPath(files[f]); Resource res = dir.addPath(files[f]);
if (res.isDirectory()) if (res.isDirectory())
parseDir(handlers, res, resolver); parseDir(handlers, res);
else else
{ {
//we've already verified the directories, so just verify the class file name //we've already verified the directories, so just verify the class file name
@ -706,7 +696,7 @@ public class AnnotationParser
try try
{ {
String name = res.getName(); String name = res.getName();
if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name)))) if (!isParsed(name))
{ {
Resource r = Resource.newResource(res.getURL()); Resource r = Resource.newResource(res.getURL());
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);}; if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);};
@ -741,10 +731,9 @@ public class AnnotationParser
* @param loader the classloader for the classes * @param loader the classloader for the classes
* @param visitParents if true, visit parent classloaders too * @param visitParents if true, visit parent classloaders too
* @param nullInclusive if true, an empty pattern means all names match, if false, none match * @param nullInclusive if true, an empty pattern means all names match, if false, none match
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver) public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive)
throws Exception throws Exception
{ {
if (loader==null) if (loader==null)
@ -762,7 +751,7 @@ public class AnnotationParser
{ {
try try
{ {
parseJarEntry(handlers, Resource.newResource(jarUri), entry, resolver); parseJarEntry(handlers, Resource.newResource(jarUri), entry);
} }
catch (Exception e) catch (Exception e)
{ {
@ -782,10 +771,9 @@ public class AnnotationParser
* *
* @param handlers the handlers to look for classes in * @param handlers the handlers to look for classes in
* @param uris the uris for the jars * @param uris the uris for the jars
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
public void parse (final Set<? extends Handler> handlers, final URI[] uris, final ClassNameResolver resolver) public void parse (final Set<? extends Handler> handlers, final URI[] uris)
throws Exception throws Exception
{ {
if (uris==null) if (uris==null)
@ -797,7 +785,7 @@ public class AnnotationParser
{ {
try try
{ {
parse(handlers, uri, resolver); parse(handlers, uri);
} }
catch (Exception e) catch (Exception e)
{ {
@ -812,16 +800,15 @@ public class AnnotationParser
* *
* @param handlers the handlers to look for classes in * @param handlers the handlers to look for classes in
* @param uri the uri for the jar * @param uri the uri for the jar
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
public void parse (final Set<? extends Handler> handlers, URI uri, final ClassNameResolver resolver) public void parse (final Set<? extends Handler> handlers, URI uri)
throws Exception throws Exception
{ {
if (uri == null) if (uri == null)
return; return;
parse (handlers, Resource.newResource(uri), resolver); parse (handlers, Resource.newResource(uri));
} }
@ -830,10 +817,9 @@ public class AnnotationParser
* *
* @param handlers the handlers to look for classes in * @param handlers the handlers to look for classes in
* @param r the resource to parse * @param r the resource to parse
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
public void parse (final Set<? extends Handler> handlers, Resource r, final ClassNameResolver resolver) public void parse (final Set<? extends Handler> handlers, Resource r)
throws Exception throws Exception
{ {
if (r == null) if (r == null)
@ -841,14 +827,14 @@ public class AnnotationParser
if (r.exists() && r.isDirectory()) if (r.exists() && r.isDirectory())
{ {
parseDir(handlers, r, resolver); parseDir(handlers, r);
return; return;
} }
String fullname = r.toString(); String fullname = r.toString();
if (fullname.endsWith(".jar")) if (fullname.endsWith(".jar"))
{ {
parseJar(handlers, r, resolver); parseJar(handlers, r);
return; return;
} }
@ -872,10 +858,9 @@ public class AnnotationParser
* *
* @param handlers the handlers to look for classes in * @param handlers the handlers to look for classes in
* @param jarResource the jar resource to parse * @param jarResource the jar resource to parse
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
protected void parseJar (Set<? extends Handler> handlers, Resource jarResource, final ClassNameResolver resolver) protected void parseJar (Set<? extends Handler> handlers, Resource jarResource)
throws Exception throws Exception
{ {
if (jarResource == null) if (jarResource == null)
@ -899,7 +884,7 @@ public class AnnotationParser
{ {
try try
{ {
parseJarEntry(handlers, jarResource, entry, resolver); parseJarEntry(handlers, jarResource, entry);
} }
catch (Exception e) catch (Exception e)
{ {
@ -927,10 +912,9 @@ public class AnnotationParser
* @param handlers the handlers to look for classes in * @param handlers the handlers to look for classes in
* @param jar the jar resource to parse * @param jar the jar resource to parse
* @param entry the entry in the jar resource to parse * @param entry the entry in the jar resource to parse
* @param resolver the class name resolver
* @throws Exception if unable to parse * @throws Exception if unable to parse
*/ */
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry, final ClassNameResolver resolver) protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry)
throws Exception throws Exception
{ {
if (jar == null || entry == null) if (jar == null || entry == null)
@ -947,9 +931,7 @@ public class AnnotationParser
{ {
String shortName = name.replace('/', '.').substring(0,name.length()-6); String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null) if (!isParsed(shortName))
||
(!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
{ {
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name); Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);}; if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);};

View File

@ -74,6 +74,12 @@ public class TestAnnotationInheritance
return; return;
annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName()); annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName());
} }
@Override
public String toString()
{
return annotatedClassNames.toString()+annotatedMethods+annotatedFields;
}
} }
@After @After
@ -93,18 +99,7 @@ public class TestAnnotationInheritance
SampleHandler handler = new SampleHandler(); SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser(); AnnotationParser parser = new AnnotationParser();
parser.parse(Collections.singleton(handler), classNames, new ClassNameResolver () parser.parse(Collections.singleton(handler), classNames);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
//check we got 2 class annotations //check we got 2 class annotations
assertEquals(2, handler.annotatedClassNames.size()); assertEquals(2, handler.annotatedClassNames.size());
@ -129,18 +124,7 @@ public class TestAnnotationInheritance
{ {
SampleHandler handler = new SampleHandler(); SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser(); AnnotationParser parser = new AnnotationParser();
parser.parse(Collections.singleton(handler), ClassB.class, new ClassNameResolver () parser.parse(Collections.singleton(handler), ClassB.class, true);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
}, true);
//check we got 2 class annotations //check we got 2 class annotations
assertEquals(2, handler.annotatedClassNames.size()); assertEquals(2, handler.annotatedClassNames.size());
@ -160,46 +144,6 @@ public class TestAnnotationInheritance
assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0));
} }
@Test
public void testExclusions() throws Exception
{
AnnotationParser parser = new AnnotationParser();
SampleHandler handler = new SampleHandler();
parser.parse(Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return true;
}
public boolean shouldOverride(String name)
{
return false;
}
});
assertEquals (0, handler.annotatedClassNames.size());
assertEquals (0, handler.annotatedFields.size());
assertEquals (0, handler.annotatedMethods.size());
handler.annotatedClassNames.clear();
handler.annotatedFields.clear();
handler.annotatedMethods.clear();
parser.parse (Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
assertEquals (1, handler.annotatedClassNames.size());
}
@Test @Test
public void testTypeInheritanceHandling() throws Exception public void testTypeInheritanceHandling() throws Exception
{ {
@ -218,7 +162,7 @@ public class TestAnnotationInheritance
classNames.add(InterfaceD.class.getName()); classNames.add(InterfaceD.class.getName());
classNames.add(Foo.class.getName()); classNames.add(Foo.class.getName());
parser.parse(Collections.singleton(handler), classNames, null); parser.parse(Collections.singleton(handler), classNames);
assertNotNull(map); assertNotNull(map);
assertFalse(map.isEmpty()); assertFalse(map.isEmpty());

View File

@ -111,19 +111,7 @@ public class TestAnnotationParser
} }
//long start = System.currentTimeMillis(); //long start = System.currentTimeMillis();
parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver() parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
//long end = System.currentTimeMillis(); //long end = System.currentTimeMillis();
//System.err.println("Time to parse class: " + ((end - start))); //System.err.println("Time to parse class: " + ((end - start)));
@ -162,7 +150,7 @@ public class TestAnnotationParser
} }
} }
parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames,null); parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames);
} }
@Test @Test
@ -171,7 +159,7 @@ public class TestAnnotationParser
File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar"); File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar");
AnnotationParser parser = new AnnotationParser(); AnnotationParser parser = new AnnotationParser();
Set<Handler> emptySet = Collections.emptySet(); Set<Handler> emptySet = Collections.emptySet();
parser.parse(emptySet, badClassesJar.toURI(),null); parser.parse(emptySet, badClassesJar.toURI());
// only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here // only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here
} }
@ -196,7 +184,7 @@ public class TestAnnotationParser
AnnotationParser parser = new AnnotationParser(); AnnotationParser parser = new AnnotationParser();
// Parse // Parse
parser.parse(Collections.singleton(tracker), basedir.toURI(),null); parser.parse(Collections.singleton(tracker), basedir.toURI());
// Validate // Validate
Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName())); Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName()));

View File

@ -73,18 +73,7 @@ public class TestServletAnnotations
TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results); TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results);
parser.parse(Collections.singleton(handler), classes, new ClassNameResolver () parser.parse(Collections.singleton(handler), classes);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
assertEquals(1, results.size()); assertEquals(1, results.size());

View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
// ========================================================================
// Copyright (c) Webtide LLC
//
// 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.apache.org/licenses/LICENSE-2.0.txt
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
-->
<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"> <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> <parent>
<groupId>org.eclipse.jetty.cdi</groupId> <groupId>org.eclipse.jetty.cdi</groupId>

View File

@ -64,6 +64,10 @@ public class ContinueProtocolHandler implements ProtocolHandler
return new ContinueListener(); return new ContinueListener();
} }
protected void onContinue(Request request)
{
}
protected class ContinueListener extends BufferingResponseListener protected class ContinueListener extends BufferingResponseListener
{ {
@Override @Override
@ -72,7 +76,8 @@ public class ContinueProtocolHandler implements ProtocolHandler
// Handling of success must be done here and not from onComplete(), // Handling of success must be done here and not from onComplete(),
// since the onComplete() is not invoked because the request is not completed yet. // since the onComplete() is not invoked because the request is not completed yet.
HttpConversation conversation = ((HttpRequest)response.getRequest()).getConversation(); Request request = response.getRequest();
HttpConversation conversation = ((HttpRequest)request).getConversation();
// Mark the 100 Continue response as handled // Mark the 100 Continue response as handled
conversation.setAttribute(ATTRIBUTE, Boolean.TRUE); conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
@ -88,6 +93,7 @@ public class ContinueProtocolHandler implements ProtocolHandler
// All good, continue // All good, continue
exchange.resetResponse(); exchange.resetResponse();
exchange.proceed(null); exchange.proceed(null);
onContinue(request);
break; break;
} }
default: default:
@ -98,7 +104,7 @@ public class ContinueProtocolHandler implements ProtocolHandler
List<Response.ResponseListener> listeners = exchange.getResponseListeners(); List<Response.ResponseListener> listeners = exchange.getResponseListeners();
HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding()); HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
notifier.forwardSuccess(listeners, contentResponse); notifier.forwardSuccess(listeners, contentResponse);
exchange.proceed(new HttpRequestException("Expectation failed", exchange.getRequest())); exchange.proceed(new HttpRequestException("Expectation failed", request));
break; break;
} }
} }

View File

@ -18,26 +18,13 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
import org.eclipse.jetty.util.BufferUtil;
/** /**
* {@link ContentDecoder} for the "gzip" encoding. * {@link ContentDecoder} for the "gzip" encoding.
*
*/ */
public class GZIPContentDecoder implements ContentDecoder public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecoder implements ContentDecoder
{ {
private final Inflater inflater = new Inflater(true);
private final byte[] bytes;
private byte[] output;
private State state;
private int size;
private int value;
private byte flags;
public GZIPContentDecoder() public GZIPContentDecoder()
{ {
@ -46,285 +33,7 @@ public class GZIPContentDecoder implements ContentDecoder
public GZIPContentDecoder(int bufferSize) public GZIPContentDecoder(int bufferSize)
{ {
this.bytes = new byte[bufferSize]; super(null,bufferSize);
reset();
}
/**
* {@inheritDoc}
* <p>If the decoding did not produce any output, for example because it consumed gzip header
* or trailer bytes, it returns a buffer with zero capacity.</p>
* <p>This method never returns null.</p>
* <p>The given {@code buffer}'s position will be modified to reflect the bytes consumed during
* the decoding.</p>
* <p>The decoding may be finished without consuming the buffer completely if the buffer contains
* gzip bytes plus other bytes (either plain or gzipped).</p>
*/
@Override
public ByteBuffer decode(ByteBuffer buffer)
{
try
{
while (buffer.hasRemaining())
{
byte currByte = buffer.get();
switch (state)
{
case INITIAL:
{
buffer.position(buffer.position() - 1);
state = State.ID;
break;
}
case ID:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 2)
{
if (value != 0x8B1F)
throw new ZipException("Invalid gzip bytes");
state = State.CM;
}
break;
}
case CM:
{
if ((currByte & 0xFF) != 0x08)
throw new ZipException("Invalid gzip compression method");
state = State.FLG;
break;
}
case FLG:
{
flags = currByte;
state = State.MTIME;
size = 0;
value = 0;
break;
}
case MTIME:
{
// Skip the 4 MTIME bytes
++size;
if (size == 4)
state = State.XFL;
break;
}
case XFL:
{
// Skip XFL
state = State.OS;
break;
}
case OS:
{
// Skip OS
state = State.FLAGS;
break;
}
case FLAGS:
{
buffer.position(buffer.position() - 1);
if ((flags & 0x04) == 0x04)
{
state = State.EXTRA_LENGTH;
size = 0;
value = 0;
}
else if ((flags & 0x08) == 0x08)
state = State.NAME;
else if ((flags & 0x10) == 0x10)
state = State.COMMENT;
else if ((flags & 0x2) == 0x2)
{
state = State.HCRC;
size = 0;
value = 0;
}
else
state = State.DATA;
break;
}
case EXTRA_LENGTH:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 2)
state = State.EXTRA;
break;
}
case EXTRA:
{
// Skip EXTRA bytes
--value;
if (value == 0)
{
// Clear the EXTRA flag and loop on the flags
flags &= ~0x04;
state = State.FLAGS;
}
break;
}
case NAME:
{
// Skip NAME bytes
if (currByte == 0)
{
// Clear the NAME flag and loop on the flags
flags &= ~0x08;
state = State.FLAGS;
}
break;
}
case COMMENT:
{
// Skip COMMENT bytes
if (currByte == 0)
{
// Clear the COMMENT flag and loop on the flags
flags &= ~0x10;
state = State.FLAGS;
}
break;
}
case HCRC:
{
// Skip HCRC
++size;
if (size == 2)
{
// Clear the HCRC flag and loop on the flags
flags &= ~0x02;
state = State.FLAGS;
}
break;
}
case DATA:
{
buffer.position(buffer.position() - 1);
while (true)
{
int decoded = inflate(bytes);
if (decoded == 0)
{
if (inflater.needsInput())
{
if (buffer.hasRemaining())
{
byte[] input = new byte[buffer.remaining()];
buffer.get(input);
inflater.setInput(input);
}
else
{
if (output != null)
{
ByteBuffer result = ByteBuffer.wrap(output);
output = null;
return result;
}
break;
}
}
else if (inflater.finished())
{
int remaining = inflater.getRemaining();
buffer.position(buffer.limit() - remaining);
state = State.CRC;
size = 0;
value = 0;
break;
}
else
{
throw new ZipException("Invalid inflater state");
}
}
else
{
if (output == null)
{
// Save the inflated bytes and loop to see if we have finished
output = Arrays.copyOf(bytes, decoded);
}
else
{
// Accumulate inflated bytes and loop to see if we have finished
byte[] newOutput = Arrays.copyOf(output, output.length + decoded);
System.arraycopy(bytes, 0, newOutput, output.length, decoded);
output = newOutput;
}
}
}
break;
}
case CRC:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 4)
{
// From RFC 1952, compliant decoders need not to verify the CRC
state = State.ISIZE;
size = 0;
value = 0;
}
break;
}
case ISIZE:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 4)
{
if (value != inflater.getBytesWritten())
throw new ZipException("Invalid input size");
ByteBuffer result = output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output);
reset();
return result;
}
break;
}
default:
throw new ZipException();
}
}
return BufferUtil.EMPTY_BUFFER;
}
catch (ZipException x)
{
throw new RuntimeException(x);
}
}
private int inflate(byte[] bytes) throws ZipException
{
try
{
return inflater.inflate(bytes);
}
catch (DataFormatException x)
{
throw new ZipException(x.getMessage());
}
}
private void reset()
{
inflater.reset();
Arrays.fill(bytes, (byte)0);
output = null;
state = State.INITIAL;
size = 0;
value = 0;
flags = 0;
}
protected boolean isFinished()
{
return state == State.INITIAL;
} }
/** /**
@ -351,9 +60,4 @@ public class GZIPContentDecoder implements ContentDecoder
return new GZIPContentDecoder(bufferSize); return new GZIPContentDecoder(bufferSize);
} }
} }
private enum State
{
INITIAL, ID, CM, FLG, MTIME, XFL, OS, FLAGS, EXTRA_LENGTH, EXTRA, NAME, COMMENT, HCRC, DATA, CRC, ISIZE
}
} }

View File

@ -459,9 +459,10 @@ public class HttpClient extends ContainerLifeCycle
HttpHeader.PROXY_AUTHORIZATION == header) HttpHeader.PROXY_AUTHORIZATION == header)
continue; continue;
String name = field.getName();
String value = field.getValue(); String value = field.getValue();
if (!newRequest.getHeaders().contains(header, value)) if (!newRequest.getHeaders().contains(name, value))
newRequest.header(field.getName(), value); newRequest.header(name, value);
} }
return newRequest; return newRequest;
} }
@ -564,18 +565,12 @@ public class HttpClient extends ContainerLifeCycle
{ {
context.put(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY, new Promise.Wrapper<Connection>(promise) context.put(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY, new Promise.Wrapper<Connection>(promise)
{ {
@Override
public void succeeded(Connection result)
{
getPromise().succeeded(result);
}
@Override @Override
public void failed(Throwable x) public void failed(Throwable x)
{ {
int nextIndex = index + 1; int nextIndex = index + 1;
if (nextIndex == socketAddresses.size()) if (nextIndex == socketAddresses.size())
getPromise().failed(x); super.failed(x);
else else
connect(socketAddresses, nextIndex, context); connect(socketAddresses, nextIndex, context);
} }

View File

@ -35,7 +35,6 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
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;
@ -68,21 +67,23 @@ public abstract class HttpConnection implements Connection
@Override @Override
public void send(Request request, Response.CompleteListener listener) public void send(Request request, Response.CompleteListener listener)
{ {
ArrayList<Response.ResponseListener> listeners = new ArrayList<>(2); HttpRequest httpRequest = (HttpRequest)request;
if (request.getTimeout() > 0)
ArrayList<Response.ResponseListener> listeners = new ArrayList<>(httpRequest.getResponseListeners());
if (httpRequest.getTimeout() > 0)
{ {
TimeoutCompleteListener timeoutListener = new TimeoutCompleteListener(request); TimeoutCompleteListener timeoutListener = new TimeoutCompleteListener(httpRequest);
timeoutListener.schedule(getHttpClient().getScheduler()); timeoutListener.schedule(getHttpClient().getScheduler());
listeners.add(timeoutListener); listeners.add(timeoutListener);
} }
if (listener != null) if (listener != null)
listeners.add(listener); listeners.add(listener);
HttpExchange exchange = new HttpExchange(getHttpDestination(), (HttpRequest)request, listeners); HttpExchange exchange = new HttpExchange(getHttpDestination(), httpRequest, listeners);
SendFailure result = send(exchange); SendFailure result = send(exchange);
if (result != null) if (result != null)
request.abort(result.failure); httpRequest.abort(result.failure);
} }
protected abstract SendFailure send(HttpExchange exchange); protected abstract SendFailure send(HttpExchange exchange);

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
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;
@ -87,7 +88,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
} }
this.connectionFactory = connectionFactory; this.connectionFactory = connectionFactory;
String host = getHost(); String host = HostPort.normalizeHost(getHost());
if (!client.isDefaultPort(getScheme(), getPort())) if (!client.isDefaultPort(getScheme(), getPort()))
host += ":" + getPort(); host += ":" + getPort();
hostField = new HttpField(HttpHeader.HOST, host); hostField = new HttpField(HttpHeader.HOST, host);

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.CountingCallback; import org.eclipse.jetty.util.CountingCallback;
import org.eclipse.jetty.util.component.Destroyable;
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;
@ -470,6 +471,7 @@ public abstract class HttpReceiver
*/ */
protected void reset() protected void reset()
{ {
destroyDecoder(decoder);
decoder = null; decoder = null;
} }
@ -482,9 +484,18 @@ public abstract class HttpReceiver
*/ */
protected void dispose() protected void dispose()
{ {
destroyDecoder(decoder);
decoder = null; decoder = null;
} }
private static void destroyDecoder(ContentDecoder decoder)
{
if (decoder instanceof Destroyable)
{
((Destroyable)decoder).destroy();
}
}
public boolean abort(HttpExchange exchange, Throwable failure) public boolean abort(HttpExchange exchange, Throwable failure)
{ {
// Update the state to avoid more response processing. // Update the state to avoid more response processing.

View File

@ -693,6 +693,11 @@ public class HttpRequest implements Request
client.send(request, responseListeners); client.send(request, responseListeners);
} }
protected List<Response.ResponseListener> getResponseListeners()
{
return responseListeners;
}
@Override @Override
public boolean abort(Throwable cause) public boolean abort(Throwable cause)
{ {

View File

@ -25,6 +25,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.util.HostPort;
/** /**
* The configuration of the forward proxy to use with {@link org.eclipse.jetty.client.HttpClient}. * The configuration of the forward proxy to use with {@link org.eclipse.jetty.client.HttpClient}.
@ -58,6 +59,7 @@ public class ProxyConfiguration
public static abstract class Proxy public static abstract class Proxy
{ {
// TO use IPAddress Map
private final Set<String> included = new HashSet<>(); private final Set<String> included = new HashSet<>();
private final Set<String> excluded = new HashSet<>(); private final Set<String> excluded = new HashSet<>();
private final Origin.Address address; private final Origin.Address address;
@ -149,12 +151,10 @@ public class ProxyConfiguration
private boolean matches(Origin.Address address, String pattern) private boolean matches(Origin.Address address, String pattern)
{ {
// TODO: add support for CIDR notation like 192.168.0.0/24, see DoSFilter // TODO: add support for CIDR notation like 192.168.0.0/24, see DoSFilter
int colon = pattern.indexOf(':'); HostPort hostPort = new HostPort(pattern);
if (colon < 0) String host = hostPort.getHost();
return pattern.equals(address.getHost()); int port = hostPort.getPort();
String host = pattern.substring(0, colon); return host.equals(address.getHost()) && ( port<=0 || port==address.getPort() );
String port = pattern.substring(colon + 1);
return host.equals(address.getHost()) && port.equals(String.valueOf(address.getPort()));
} }
/** /**

View File

@ -33,6 +33,7 @@ import org.eclipse.jetty.toolchain.test.TestTracker;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
@Deprecated
public class GZIPContentDecoderTest public class GZIPContentDecoderTest
{ {
@Rule @Rule

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Connection;
@ -27,7 +28,7 @@ import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP; import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP; import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Assert; import org.junit.Assert;
@ -65,7 +66,6 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe
} }
} }
@Slow
@Test @Test
public void testExplicitConnectionIsClosedOnRemoteClose() throws Exception public void testExplicitConnectionIsClosedOnRemoteClose() throws Exception
{ {
@ -98,4 +98,26 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe
Assert.assertTrue(connectionPool.getActiveConnections().isEmpty()); Assert.assertTrue(connectionPool.getActiveConnections().isEmpty());
Assert.assertTrue(connectionPool.getIdleConnections().isEmpty()); Assert.assertTrue(connectionPool.getIdleConnections().isEmpty());
} }
@Test
public void testExplicitConnectionResponseListeners() throws Exception
{
start(new EmptyServerHandler());
Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort());
FuturePromise<Connection> futureConnection = new FuturePromise<>();
destination.newConnection(futureConnection);
Connection connection = futureConnection.get(5, TimeUnit.SECONDS);
CountDownLatch responseLatch = new CountDownLatch(1);
Request request = client.newRequest(destination.getHost(), destination.getPort())
.scheme(scheme)
.onResponseSuccess(response -> responseLatch.countDown());
FutureResponseListener listener = new FutureResponseListener(request);
connection.send(request, listener);
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
}
} }

View File

@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpCookie; import java.net.HttpCookie;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
@ -89,6 +88,7 @@ import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.SocketAddressResolver;
import org.eclipse.jetty.util.log.StacklessLogging; import org.eclipse.jetty.util.log.StacklessLogging;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume; import org.junit.Assume;
import org.junit.Rule; import org.junit.Rule;
@ -811,10 +811,23 @@ public class HttpClientTest extends AbstractHttpClientServerTest
@Test @Test
public void testConnectThrowsUnknownHostException() throws Exception public void testConnectThrowsUnknownHostException() throws Exception
{ {
String host = "idontexist";
int port = 80;
try
{
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host, port), 1000);
Assume.assumeTrue("Host must not be resolvable", false);
}
catch (IOException ignored)
{
}
start(new EmptyServerHandler()); start(new EmptyServerHandler());
final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1);
client.newRequest("idontexist", 80) client.newRequest(host, port)
.send(result -> .send(result ->
{ {
Assert.assertTrue(result.isFailed()); Assert.assertTrue(result.isFailed());
@ -828,19 +841,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest
@Test @Test
public void testConnectHostWithMultipleAddresses() throws Exception public void testConnectHostWithMultipleAddresses() throws Exception
{ {
String host = "google.com"; start(new EmptyServerHandler());
try
{
// Likely that the DNS for google.com returns multiple addresses.
Assume.assumeTrue(InetAddress.getAllByName(host).length > 1);
}
catch (Throwable x)
{
Assume.assumeNoException(x);
}
startClient();
client.setFollowRedirects(false); // Avoid redirects from 80 to 443.
client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), client.getConnectTimeout()) client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), client.getConnectTimeout())
{ {
@Override @Override
@ -853,7 +855,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
{ {
// Add as first address an invalid address so that we test // Add as first address an invalid address so that we test
// that the connect operation iterates over the addresses. // that the connect operation iterates over the addresses.
result.add(0, new InetSocketAddress("idontexist", 80)); result.add(0, new InetSocketAddress("idontexist", port));
promise.succeeded(result); promise.succeeded(result);
} }
@ -866,9 +868,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest
} }
}); });
// Response code may be 200 or 302; // If no exceptions the test passes.
// if no exceptions the test passes. client.newRequest("localhost", connector.getLocalPort())
client.newRequest(host, 80) .scheme(scheme)
.header(HttpHeader.CONNECTION, "close") .header(HttpHeader.CONNECTION, "close")
.send(); .send();
} }
@ -1232,7 +1234,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
// before closing the connection, so we need to wait before checking // before closing the connection, so we need to wait before checking
// that the connection is closed to avoid races. // that the connection is closed to avoid races.
Thread.sleep(1000); Thread.sleep(1000);
Assert.assertTrue(((HttpConnectionOverHTTP)connection).isClosed()); Assert.assertTrue(connection.isClosed());
} }
} }
@ -1535,6 +1537,93 @@ public class HttpClientTest extends AbstractHttpClientServerTest
} }
} }
@Test
public void test_IPv6_Host() throws Exception
{
start(new AbstractHandler()
{
@Override
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
response.setContentType("text/plain");
response.getOutputStream().print(request.getHeader("Host"));
}
});
URI uri = URI.create(scheme + "://[::1]:" + connector.getLocalPort() + "/path");
ContentResponse response = client.newRequest(uri)
.method(HttpMethod.PUT)
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertNotNull(response);
Assert.assertEquals(200, response.getStatus());
Assert.assertThat(new String(response.getContent(), StandardCharsets.ISO_8859_1),Matchers.startsWith("[::1]:"));
}
@Test
public void testCopyRequest()
throws Exception
{
startClient();
assertCopyRequest(client.newRequest("http://example.com/some/url")
.method(HttpMethod.HEAD)
.version(HttpVersion.HTTP_2)
.content(new StringContentProvider("some string"))
.timeout(321, TimeUnit.SECONDS)
.idleTimeout(2221, TimeUnit.SECONDS)
.followRedirects(true)
.header(HttpHeader.CONTENT_TYPE, "application/json")
.header("X-Some-Custom-Header", "some-value"));
assertCopyRequest(client.newRequest("https://example.com")
.method(HttpMethod.POST)
.version(HttpVersion.HTTP_1_0)
.content(new StringContentProvider("some other string"))
.timeout(123231, TimeUnit.SECONDS)
.idleTimeout(232342, TimeUnit.SECONDS)
.followRedirects(false)
.header(HttpHeader.ACCEPT, "application/json")
.header("X-Some-Other-Custom-Header", "some-other-value"));
assertCopyRequest(client.newRequest("https://example.com")
.header(HttpHeader.ACCEPT, "application/json")
.header(HttpHeader.ACCEPT, "application/xml")
.header("x-same-name", "value1")
.header("x-same-name", "value2"));
assertCopyRequest(client.newRequest("https://example.com")
.header(HttpHeader.ACCEPT, "application/json")
.header(HttpHeader.CONTENT_TYPE, "application/json"));
assertCopyRequest(client.newRequest("https://example.com")
.header("Accept", "application/json")
.header("Content-Type", "application/json"));
assertCopyRequest(client.newRequest("https://example.com")
.header("X-Custom-Header-1", "value1")
.header("X-Custom-Header-2", "value2"));
assertCopyRequest(client.newRequest("https://example.com")
.header("X-Custom-Header-1", "value")
.header("X-Custom-Header-2", "value"));
}
private void assertCopyRequest(Request original)
{
Request copy = client.copyRequest((HttpRequest) original, original.getURI());
Assert.assertEquals(original.getURI(), copy.getURI());
Assert.assertEquals(original.getMethod(), copy.getMethod());
Assert.assertEquals(original.getVersion(), copy.getVersion());
Assert.assertEquals(original.getContent(), copy.getContent());
Assert.assertEquals(original.getIdleTimeout(), copy.getIdleTimeout());
Assert.assertEquals(original.getTimeout(), copy.getTimeout());
Assert.assertEquals(original.isFollowRedirects(), copy.isFollowRedirects());
Assert.assertEquals(original.getHeaders(), copy.getHeaders());
}
private void consume(InputStream input, boolean eof) throws IOException private void consume(InputStream input, boolean eof) throws IOException
{ {
int crlfs = 0; int crlfs = 0;

View File

@ -63,4 +63,16 @@ public class ProxyConfigurationTest
Assert.assertTrue(proxy.matches(new Origin("http", "1.2.3.4", 0))); Assert.assertTrue(proxy.matches(new Origin("http", "1.2.3.4", 0)));
Assert.assertFalse(proxy.matches(new Origin("http", "1.2.3.4", 5))); Assert.assertFalse(proxy.matches(new Origin("http", "1.2.3.4", 5)));
} }
@Test
public void testProxyMatchesWithIncludesAndExcludesIPv6() throws Exception
{
HttpProxy proxy = new HttpProxy("host", 0);
proxy.getIncludedAddresses().add("[1::2:3:4]");
proxy.getExcludedAddresses().add("[1::2:3:4]:5");
Assert.assertFalse(proxy.matches(new Origin("http", "any", 0)));
Assert.assertTrue(proxy.matches(new Origin("http", "[1::2:3:4]", 0)));
Assert.assertFalse(proxy.matches(new Origin("http", "[1::2:3:4]", 5)));
}
} }

View File

@ -43,4 +43,9 @@ package org.eclipse.jetty.continuation;
* </p> * </p>
*/ */
public class ContinuationThrowable extends Error public class ContinuationThrowable extends Error
{} {
public ContinuationThrowable()
{
super(null, null, false, false);
}
}

View File

@ -273,7 +273,7 @@ public class WebAppProvider extends ScanningAppProvider
Resource resource = Resource.newResource(app.getOriginId()); Resource resource = Resource.newResource(app.getOriginId());
File file = resource.getFile(); File file = resource.getFile();
if (!resource.exists()) if (!resource.exists())
throw new IllegalStateException("App resouce does not exist "+resource); throw new IllegalStateException("App resource does not exist "+resource);
String context = file.getName(); String context = file.getName();

View File

@ -329,7 +329,7 @@
<arguments> <arguments>
<argument>jetty.home=${assembly-directory}</argument> <argument>jetty.home=${assembly-directory}</argument>
<argument>jetty.base=${assembly-directory}</argument> <argument>jetty.base=${assembly-directory}</argument>
<argument>--add-to-start=deploy,websocket,ext,resources,jsp,jstl,http</argument> <argument>--add-to-start=server,deploy,websocket,ext,resources,jsp,jstl,http</argument>
</arguments> </arguments>
</configuration> </configuration>
<goals> <goals>

View File

@ -72,6 +72,7 @@
<plugin> <plugin>
<groupId>com.agilejava.docbkx</groupId> <groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId> <artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.17</version>
<executions> <executions>
<execution> <execution>
<id>html</id> <id>html</id>
@ -81,10 +82,10 @@
</goals> </goals>
<configuration> <configuration>
<htmlStylesheet>css/docbook.css</htmlStylesheet> <htmlStylesheet>css/docbook.css</htmlStylesheet>
<htmlCustomization>${basedir}/src/main/docbkx-stylesheet/html/docbook.xsl</htmlCustomization> <htmlCustomization>${project.basedir}/src/main/docbkx-stylesheet/html/docbook.xsl</htmlCustomization>
<preProcess> <preProcess>
<!-- pull over the images from the source material --> <!-- pull over the images from the source material -->
<copy todir="target/docbkx/html/index/images" flatten="true"> <copy todir="target/docbkx/html/images" flatten="true">
<fileset dir="src/main/asciidoc"> <fileset dir="src/main/asciidoc">
<include name="**/*.png" /> <include name="**/*.png" />
<include name="**/*.jpg" /> <include name="**/*.jpg" />
@ -92,16 +93,16 @@
<include name="**/*.dot" /> <include name="**/*.dot" />
</fileset> </fileset>
</copy> </copy>
<copy todir="target/docbkx/html/index/images"> <copy todir="target/docbkx/html/images">
<fileset dir="src/main/docbkx-resources/images" /> <fileset dir="src/main/docbkx-resources/images" />
</copy> </copy>
<copy todir="target/docbkx/html/index/css"> <copy todir="target/docbkx/html/css">
<fileset dir="src/main/docbkx-resources/css" /> <fileset dir="src/main/docbkx-resources/css" />
</copy> </copy>
<copy todir="target/docbkx/html/index/fonts"> <copy todir="target/docbkx/html/fonts">
<fileset dir="src/main/docbkx-resources/fonts" /> <fileset dir="src/main/docbkx-resources/fonts" />
</copy> </copy>
<copy todir="target/docbkx/html/index/js"> <copy todir="target/docbkx/html/js">
<fileset dir="src/main/docbkx-resources/js" /> <fileset dir="src/main/docbkx-resources/js" />
</copy> </copy>
</preProcess> </preProcess>

View File

@ -72,10 +72,10 @@ This example comes from within `jetty-http.xml`.
<Set name="host"><Property name="jetty.host" /></Set> <Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.http.port" default="8080" /></Set> <Set name="port"><Property name="jetty.http.port" default="8080" /></Set>
<Set name="idleTimeout">30000</Set> <Set name="idleTimeout">30000</Set>
<!-- Enable Connector Statistics --> <!-- Enable Connection Statistics -->
<Call name="addBean"> <Call name="addBean">
<Arg> <Arg>
<New id="ConnectorStatistics" class="org.eclipse.jetty.server.ConnectorStatistics"/> <New id="ConnectionStatistics" class="org.eclipse.jetty.io.ConnectionStatistics"/>
</Arg> </Arg>
</Call> </Call>
</New> </New>

View File

@ -33,7 +33,7 @@ The fourth step is to create a Jetty base directory (see xref:startup-base-and-h
.... ....
$ mkdir -p /usr/jetty/wordpress $ mkdir -p /usr/jetty/wordpress
$ cd /usr/jetty/wordpress $ cd /usr/jetty/wordpress
$ java -jar $JETTY_HOME/start.jar --add-to-startd=fcgi,http,deploy $ java -jar $JETTY_HOME/start.jar --add-to-start=fcgi,http,deploy
.... ....
Therefore `$JETTY_BASE=/usr/jetty/wordpress`. Therefore `$JETTY_BASE=/usr/jetty/wordpress`.
@ -152,7 +152,7 @@ Enabling the `http2` is easy; in additions to the modules you have enabled above
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
.... ....
$ cd $JETTY_BASE $ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2 $ java -jar $JETTY_HOME/start.jar --add-to-start=http2
.... ....
The command above adds the `http2` module (and its dependencies) to the existing modules and uses the default Jetty keystore to provide the key material required by TLS. The command above adds the `http2` module (and its dependencies) to the existing modules and uses the default Jetty keystore to provide the key material required by TLS.

View File

@ -65,5 +65,5 @@ Currently there are very few HTTP/2 configuration properties and the default val
|======================================================================= |=======================================================================
|Property |Description |Property |Description
|jetty.http2.maxConcurrentStreams |The maximum number of concurrently open streams allowed on a single HTTP/2 connection (default 1024). Larger values increase parallelism but cost a memory commitment. |jetty.http2.maxConcurrentStreams |The maximum number of concurrently open streams allowed on a single HTTP/2 connection (default 1024). Larger values increase parallelism but cost a memory commitment.
|jetty.http2.initialStreamSendWindow |The initial flow control window size for a new stream (default 65535). Larger values may allow greater throughput but also risk head of line blocking if TCP/IP flow control is triggered. |jetty.http2.initialStreamRecvWindow |The initial receive flow control window size for a new stream (default 65535). Larger values may allow greater throughput but also risk head of line blocking if TCP/IP flow control is triggered.
|======================================================================= |=======================================================================

View File

@ -25,7 +25,7 @@ A demo Jetty base that supports HTTP/1, HTTPS/1 and deployment from a webapps di
$ JETTY_BASE=http2-demo $ JETTY_BASE=http2-demo
$ mkdir $JETTY_BASE $ mkdir $JETTY_BASE
$ cd $JETTY_BASE $ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar --add-to-startd=http,https,deploy $ java -jar $JETTY_HOME/start.jar --add-to-start=http,https,deploy
.... ....
The commands above create a `$JETTY_BASE` directory called `http2-demo`, and initializes the `http,` `https` and `deploy` modules (and their dependencies) to run a typical Jetty Server on port 8080 (for HTTP/1) and 8443 (for HTTPS/1). The commands above create a `$JETTY_BASE` directory called `http2-demo`, and initializes the `http,` `https` and `deploy` modules (and their dependencies) to run a typical Jetty Server on port 8080 (for HTTP/1) and 8443 (for HTTPS/1).
@ -35,7 +35,7 @@ To add HTTP/2 to this demo base, it is just a matter of enabling the `http2` mod
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
.... ....
$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2 $ java -jar $JETTY_HOME/start.jar --add-to-start=http2
.... ....
This command does not create a new connector, but instead simply adds the HTTP/2 protocol to the existing HTTPS/1 connector, so that it now supports both protocols on port 8443. This command does not create a new connector, but instead simply adds the HTTP/2 protocol to the existing HTTPS/1 connector, so that it now supports both protocols on port 8443.
@ -61,7 +61,7 @@ HTTP/2 can be enabled on the plain text connector and the server restarted with
[source,screen] [source,screen]
.... ....
$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2c $ java -jar $JETTY_HOME/start.jar --add-to-start=http2c
$ java -jar $JETTY_HOME/start.jar $ java -jar $JETTY_HOME/start.jar
.. ..
2015-06-17 14:16:12.549:INFO:oejs.ServerConnector:main: Started ServerConnector@6f32cd1e{HTTP/1.1,[http/1.1, h2c, h2c-17]}{0.0.0.0:8080} 2015-06-17 14:16:12.549:INFO:oejs.ServerConnector:main: Started ServerConnector@6f32cd1e{HTTP/1.1,[http/1.1, h2c, h2c-17]}{0.0.0.0:8080}

View File

@ -21,13 +21,12 @@ If you are using the standard distribution of Jetty, you must enable the _JNDI_
As the _plus_ module depends on the _JNDI_ module, you only need to enable the _plus_ module to enable both. As the _plus_ module depends on the _JNDI_ module, you only need to enable the _plus_ module to enable both.
Assuming you have Jetty installed in `/opt/jetty`, and you have made a link:#startup-base-and-home[jetty base] in `/opt/jetty/my-base`, do: Assuming you have Jetty installed in `/opt/jetty`, and you have made a link:#startup-base-and-home[jetty base] in `/opt/jetty/my-base`, do:
[source,bash] [source, screen, subs="{sub-order}"]
---- ....
cd /opt/jetty cd /opt/jetty
cd my-base cd my-base
java -jar $JETTY_HOME/start.jar --add-to-startd=plus java -jar $JETTY_HOME/start.jar --add-to-start=plus
....
----
You can now start Jetty and use JNDI within your webapps. You can now start Jetty and use JNDI within your webapps.
See link:#using-jndi[Using JNDI] for information on how to add entries to the JNDI environment that Jetty can look up within webapps. See link:#using-jndi[Using JNDI] for information on how to add entries to the JNDI environment that Jetty can look up within webapps.
@ -36,10 +35,9 @@ If you have extra jars associated with your JNDI resources, for example a databa
You will then need to enable the _ext_ module to ensure the jars in the `ext/` directory are on the classpath. You will then need to enable the _ext_ module to ensure the jars in the `ext/` directory are on the classpath.
Assuming you have Jetty installed in `/opt/jetty`, and you have made a link:#startup-base-and-home[jetty base] in `/opt/jetty/my-base`, do: Assuming you have Jetty installed in `/opt/jetty`, and you have made a link:#startup-base-and-home[jetty base] in `/opt/jetty/my-base`, do:
[source,bash] [source, screen, subs="{sub-order}"]
---- ....
cd /opt/jetty cd /opt/jetty
cd my-base cd my-base
java -jar $JETTY_HOME/start.jar --add-to-startd=ext java -jar $JETTY_HOME/start.jar --add-to-start=ext
....
----

View File

@ -22,10 +22,12 @@ This chapter discusses various options for configuring logging.
include::configuring-jetty-logging.adoc[] include::configuring-jetty-logging.adoc[]
include::default-logging-with-stderrlog.adoc[] include::default-logging-with-stderrlog.adoc[]
include::configuring-jetty-request-logs.adoc[] include::configuring-jetty-request-logs.adoc[]
include::example-apache-log4j.adoc[] include::configuring-logging-modules.adoc[]
include::example-java-util-logging.adoc[] // TODO - Remove following
include::example-java-util-logging-native.adoc[] // include::example-apache-log4j.adoc[]
include::example-logback.adoc[] // include::example-java-util-logging.adoc[]
include::example-slf4j-multiple-loggers.adoc[] // include::example-java-util-logging-native.adoc[]
// include::example-logback.adoc[]
// include::example-slf4j-multiple-loggers.adoc[]
include::example-logback-centralized-logging.adoc[] include::example-logback-centralized-logging.adoc[]
include::dump-tool.adoc[] include::dump-tool.adoc[]

View File

@ -49,15 +49,14 @@ To enable the Request Log module for the entire server via the Jetty distributio
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
$ java -jar ../start.jar --add-to-startd=requestlog $ java -jar ../start.jar --add-to-start=requestlog
INFO: requestlog initialised in ${jetty.base}/start.d/requestlog.ini INFO: requestlog initialised in ${jetty.base}/start.d/requestlog.ini
MKDIR: ${jetty.base}/logs MKDIR: ${jetty.base}/logs
INFO: Base directory was modified INFO: Base directory was modified
---- ----
The above command will add a new `requestlog.ini` file to your `{$jetty.base}/start.d` directory. The above command will add a new `requestlog.ini` file to your link:#start-vs-startd[`{$jetty.base}/start.d` directory].
If you used `--add-to-start` it will append the configuration options for the module to the `start.ini` file located in your `{$jetty.base}` directory.
The equivalent code for embedded usages of Jetty is: The equivalent code for embedded usages of Jetty is:

View File

@ -0,0 +1,425 @@
// ========================================================================
// Copyright (c) 1995-2016 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.
// ========================================================================
[[configuring-logging-modules]]
=== Jetty Logging Integrations (Slf4j, Log4j, Logback, JCL, JUL)
Jetty provides support for several logging frameworks including SLF4J, Java Commons Logging (jcl), Java Util Logging (jul), Log4j (including version 2), and Logback.
This page includes examples of how to enable the associated modules for these different frameworks.
Enabling these frameworks in the Jetty distribution is as easy as activating any other module, by adding `--add-to-start=<module name>` to the start command for your server, such as:
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --add-to-start=logging-jetty
INFO : logging-jetty initialized in ${jetty.base}/start.d/logging-jetty.ini
INFO : resources transitive
INFO : Base directory was modified
....
As noted above, Jetty supports a wide array of logging technologies.
The release of Jetty 9.4 made the implementation of these frameworks easier by providing logging modules that contain all the dependencies needed to implement a specific technology.
If a particular logging framework requires additional jar files, Jetty will automatically download these as part of enabling the associated module.
You can view a list of all the Jetty modules by running `java -jar <path-to-jetty.home>/start.jar --list-modules`.
[[example-logging-slf4j]]
==== Logging with SLF4J
===== jetty-slf4j
Jetty uses the Slf4j api as a bridge to provide logging information to additional frameworks such as Log4j or Logback.
It can also be used itself to provide logging in conjunction with standard Jetty logging.
To enable the Slf4j framework, you need to activate the `logging-slf4j` module.
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --add-to-start=logging-slf4j
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api
INFO : logging-slf4j initialized in ${jetty.base}/start.d/logging-slf4j.ini
INFO : slf4j-impl transitive
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar
INFO : Base directory was modified
$ tree
.
├── lib
│   └── slf4j
│   ├── slf4j-api-1.7.21.jar
│   └── slf4j-simple-1.7.21.jar
└── start.d
├── logging-slf4j.ini
....
[[example-logging-log4j]]
==== Logging with Log4j and log4j2
It is possible to have the Jetty Server logging configured so that Log4j or Log4j2 controls the output of logging events produced by Jetty.
This is accomplished by configuring Jetty for logging to http://logging.apache.org/log4j/[Apache Log4j] via http://slf4j.org/manual.html[Slf4j] and the http://slf4j.org/manual.html#swapping[Slf4j binding layer for Log4j].
Implementation of Log4j can be done by enabling the `logging-log4j` module.
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --add-to-start=logging-log4j
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: log4j-impl
+ Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api
INFO : log4j-impl transitive, ini template available with --add-to-start=log4j-impl
INFO : resources transitive
INFO : slf4j-log4j transitive
INFO : logging-log4j initialized in ${jetty.base}/start.d/logging-log4j.ini
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
DOWNLOAD: http://central.maven.org/maven2/log4j/log4j/1.2.17/log4j-1.2.17.jar to ${jetty.base}/lib/log4j/log4j-1.2.17.jar
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-log4j12-1.7.21.jar
INFO : Base directory was modified
$ tree
.
├── lib
│   ├── log4j
│   │   └── log4j-1.2.17.jar
│   └── slf4j
│   ├── slf4j-api-1.7.21.jar
│   └── slf4j-log4j12-1.7.21.jar
├── resources
│   └── log4j.properties
└── start.d
├── logging-log4j.ini
....
Or, to enable Log4j2, simply enable the `logging-log4j2` module.
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --add-to-start=logging-log4j2
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: log4j2-api
+ Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api
INFO : logging-log4j2 initialized in ${jetty.base}/start.d/logging-log4j2.ini
INFO : log4j2-api transitive, ini template available with --add-to-start=log4j2-api
INFO : resources transitive
INFO : slf4j-log4j2 transitive
INFO : log4j2-impl transitive
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
DOWNLOAD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.6.1/log4j-api-2.6.1.jar to ${jetty.base}/lib/log4j/log4j-api-2.6.1.jar
MKDIR: ${jetty.base}/resources
DOWNLOAD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.6.1/log4j-slf4j-impl-2.6.1.jar to ${jetty.base}/lib/log4j/log4j-slf4j-impl-2.6.1.jar
DOWNLOAD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.6.1/log4j-core-2.6.1.jar to ${jetty.base}/lib/log4j/log4j-core-2.6.1.jar
INFO : Base directory was modified
$ tree
.
├── lib
│   ├── log4j
│   │   ├── log4j-api-2.6.1.jar
│   │   ├── log4j-core-2.6.1.jar
│   │   └── log4j-slf4j-impl-2.6.1.jar
│   └── slf4j
│   └── slf4j-api-1.7.21.jar
├── resources
│   └── log4j2.xml
└── start.d
├── logging-log4j2.ini
....
[[example-logging-logback]]
==== Logging with Logback
It is possible to have the Jetty Server logging configured so that Logback controls the output of logging events produced by Jetty.
This is accomplished by configuring Jetty for logging to `Logback`, which uses http://slf4j.org/manual.html[Slf4j] and the http://logback.qos.ch/[Logback Implementation for Slf4j].
To set up Jetty logging via Logback, enable the `logging-logback` module.
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --add-to-start=logging-logback
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: logback-impl
+ Logback: the reliable, generic, fast and flexible logging framework.
+ Copyright (C) 1999-2012, QOS.ch. All rights reserved.
+ This program and the accompanying materials are dual-licensed under
+ either:
+ the terms of the Eclipse Public License v1.0
+ as published by the Eclipse Foundation:
+ http://www.eclipse.org/legal/epl-v10.html
+ or (per the licensee's choosing) under
+ the terms of the GNU Lesser General Public License version 2.1
+ as published by the Free Software Foundation:
+ http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api
INFO : logback-impl transitive, ini template available with --add-to-start=logback-impl
INFO : slf4j-logback transitive
INFO : logging-logback initialized in ${jetty.base}/start.d/logging-logback.ini
INFO : resources transitive
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.1.7/logback-core-1.1.7.jar to ${jetty.base}/lib/logback/logback-core-1.1.7.jar
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.1.7/logback-classic-1.1.7.jar to ${jetty.base}/lib/logback/logback-classic-1.1.7.jar
INFO : Base directory was modified
$ tree
.
├── lib
│   ├── logback
│   │   ├── logback-classic-1.1.7.jar
│   │   └── logback-core-1.1.7.jar
│   └── slf4j
│   └── slf4j-api-1.7.21.jar
├── resources
│   └── logback.xml
└── start.d
├── logging-logback.ini
....
At this point Jetty is configured so that the Jetty server itself will log using Logback, using the Logback configuration found in `{$jetty.base}/resources/logback.xml`.
==== Logging with Java Util Logging
[[example-logging-java-util-logging]]
===== Java Util Logging with SLF4J
It is possible to have the Jetty Server logging configured so that `java.util.logging` controls the output of logging events produced by Jetty.
This example demonstrates how to configuring Jetty for logging to `java.util.logging` via http://slf4j.org/manual.html[Slf4j] and the http://slf4j.org/manual.html#swapping[Slf4j binding layer for java.util.logging].
If you want to use the built-in native `java.util.logging` implementation, see link:#example-logging-java-util-logging-native[Native Java Util Logging].
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --add-to-start=logging-jul
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api
INFO : slf4j-jul transitive
INFO : logging-jul initialized in ${jetty.base}/start.d/logging-jul.ini
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-jdk14/1.7.21/slf4j-jdk14-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-jdk14-1.7.21.jar
INFO : Base directory was modified
$ tree
.
├── lib
│   └── slf4j
│   ├── slf4j-api-1.7.21.jar
│   └── slf4j-jdk14-1.7.21.jar
└── start.d
├── logging-jul.ini
....
==== Logging with Java Commons Logging
Jetty provides support of the Java Commons Logging (jcl) through the `logging-jcl` module, using Slf4j as a bridge.
This can be enabled as shown below:
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --add-to-start=logging-jcl
ALERT: There are enabled module(s) with licenses.
The following 2 module(s):
+ contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license
Module: jcl-impl
+ Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html
Module: slf4j-api
+ SLF4J is distributed under the MIT License.
+ Copyright (c) 2004-2013 QOS.ch
+ All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Proceed (y/N)? y
INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api
INFO : jcl-impl transitive, ini template available with --add-to-start=jcl-impl
INFO : slf4j-jcl transitive
INFO : logging-jcl initialized in ${jetty.base}/start.d/logging-jcl.ini
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
DOWNLOAD: http://central.maven.org/maven2/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar to ${jetty.base}/lib/jcl/commons-logging-1.1.3.jar
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-jcl/1.7.21/slf4j-jcl-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-jcl-1.7.21.jar
INFO : Base directory was modified
$ tree
.
├── lib
│   ├── jcl
│   │   └── commons-logging-1.1.3.jar
│   └── slf4j
│   ├── slf4j-api-1.7.21.jar
│   └── slf4j-jcl-1.7.21.jar
└── start.d
├── logging-jcl.ini
....

View File

@ -29,33 +29,26 @@ Included in the Jetty distribution is a logging module that is capable of perfor
To enable on this feature via the command line: To enable on this feature via the command line:
[source,bash] [source, screen, subs="{sub-order}"]
---- ....
[my-base]$ java -jar /opt/jetty/start.jar --module=logging [my-base]$ java -jar /opt/jetty/start.jar --add-to-start=logging-jetty
---- ....
You can also include the `--module=logging` command in your `${jetty.base}/start.ini`. The default configuration for logging output will create a file `${jetty.base}/logs/yyyy_mm_dd.stderrout.log` which allows configuration of the output directory by setting the `jetty.logs` property.
[source,bash]
----
[my-base]$ java -jar /opt/jetty/start.jar --add-to-start=logging
----
The default configuration for logging output will create a file `${jetty.logs}/yyyy_mm_dd.stderrout.log` which allows configuration of the output directory by setting the `jetty.logs` property.
For more advanced logging configurations, please consider use of a separate logging library. For more advanced logging configurations, please consider use of a separate logging library.
The recommended way to configure `StdErrLog` is to create a `${jetty.home}/resources/jetty-logging.properties` file, specify the log implementation to `StdErrLog` and then setup logging levels. The recommended way to configure `StdErrLog` is to create a `${jetty.base}/resources/jetty-logging.properties` file, specify the log implementation to `StdErrLog` and then setup logging levels.
[source,properties] [source, properties, subs="{sub-order}"]
---- ....
# Configure Jetty for StdErrLog Logging # Configure Jetty for StdErrLog Logging
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog
# Overall Logging Level is INFO # Overall Logging Level is INFO
org.eclipse.jetty.LEVEL=INFO org.eclipse.jetty.LEVEL=INFO
# Detail Logging for WebSocket # Detail Logging for WebSocket
org.eclipse.jetty.websocket.LEVEL=DEBUG org.eclipse.jetty.websocket.LEVEL=DEBUG
---- ....
There are a number of properties that can be defined in the configuration that will affect the behavior of `StdErrLog`. There are a number of properties that can be defined in the configuration that will affect the behavior of `StdErrLog`.
@ -82,9 +75,9 @@ There are a number of properties that can be defined in the configuration that w
When true, outputs logging events to `STDERR` using long form, fully qualified class names. When true, outputs logging events to `STDERR` using long form, fully qualified class names.
When false, uses abbreviated package names. When false, uses abbreviated package names.
Default is false. Default is false.
+ +
* Example when set to false: * Example when set to false:
+ +
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
.... ....
2014-06-03 14:36:16.013:INFO:oejs.Server:main: jetty-9.2.0.v20140526 2014-06-03 14:36:16.013:INFO:oejs.Server:main: jetty-9.2.0.v20140526
@ -93,9 +86,9 @@ There are a number of properties that can be defined in the configuration that w
2014-06-03 14:36:17.880:INFO:oejs.ServerConnector:main: Started ServerConnector@34f2d11a{HTTP/1.1}{0.0.0.0:8080} 2014-06-03 14:36:17.880:INFO:oejs.ServerConnector:main: Started ServerConnector@34f2d11a{HTTP/1.1}{0.0.0.0:8080}
2014-06-03 14:36:17.888:INFO:oejs.Server:main: Started @257ms 2014-06-03 14:36:17.888:INFO:oejs.Server:main: Started @257ms
.... ....
+ +
* Example when set to true: * Example when set to true:
+ +
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
.... ....
2014-06-03 14:38:19.019:INFO:org.eclipse.jetty.server.Server:main: jetty-9.2.0.v20140526 2014-06-03 14:38:19.019:INFO:org.eclipse.jetty.server.Server:main: jetty-9.2.0.v20140526

View File

@ -14,7 +14,6 @@
// You may elect to redistribute this code under either of these licenses. // You may elect to redistribute this code under either of these licenses.
// ======================================================================== // ========================================================================
[[example-logging-log4j]]
=== Example: Logging with Apache Log4j === Example: Logging with Apache Log4j
It is possible to have the Jetty Server logging configured so that Log4j controls the output of logging events produced by Jetty. It is possible to have the Jetty Server logging configured so that Log4j controls the output of logging events produced by Jetty.

View File

@ -14,7 +14,6 @@
// You may elect to redistribute this code under either of these licenses. // You may elect to redistribute this code under either of these licenses.
// ======================================================================== // ========================================================================
[[example-logging-java-util-logging-native]]
=== Example: Logging with Java's java.util.logging via JavaUtilLog === Example: Logging with Java's java.util.logging via JavaUtilLog
It is possible to have the Jetty Server logging configured so that It is possible to have the Jetty Server logging configured so that

View File

@ -14,7 +14,6 @@
// You may elect to redistribute this code under either of these licenses. // You may elect to redistribute this code under either of these licenses.
// ======================================================================== // ========================================================================
[[example-logging-java-util-logging]]
=== Example: Logging with Java's java.util.logging via Slf4j === Example: Logging with Java's java.util.logging via Slf4j
It is possible to have the Jetty Server logging configured so that `java.util.logging` controls the output of logging events produced by Jetty. It is possible to have the Jetty Server logging configured so that `java.util.logging` controls the output of logging events produced by Jetty.

View File

@ -14,7 +14,6 @@
// You may elect to redistribute this code under either of these licenses. // You may elect to redistribute this code under either of these licenses.
// ======================================================================== // ========================================================================
[[example-logging-logback]]
=== Example: Logging with Logback === Example: Logging with Logback
It is possible to have the Jetty Server logging configured so that Logback controls the output of logging events produced by Jetty. It is possible to have the Jetty Server logging configured so that Logback controls the output of logging events produced by Jetty.

View File

@ -29,6 +29,7 @@ include::session-configuration-jdbc.adoc[]
include::session-configuration-mongodb.adoc[] include::session-configuration-mongodb.adoc[]
include::session-configuration-infinispan.adoc[] include::session-configuration-infinispan.adoc[]
include::session-configuration-gcloud.adoc[] include::session-configuration-gcloud.adoc[]
include::session-configuration-gcloud-module.adoc[]
//include::setting-session-characteristics.adoc[] //include::setting-session-characteristics.adoc[]
//include::using-persistent-sessions.adoc[] //include::using-persistent-sessions.adoc[]
//include::session-clustering-jdbc.adoc[] //include::session-clustering-jdbc.adoc[]

View File

@ -36,7 +36,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== The gcloud-sessions Module ==== The gcloud-sessions Module
When using the jetty distribution, to enable Cloud Datastore session persistence, you will first need to enable the `gcloud-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. When using the jetty distribution, to enable Cloud Datastore session persistence, you will first need to enable the `gcloud-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar].
As part of the module installation, the necessary jars will be dynamically downloaded and installed to your `${jetty.base}/lib/gcloud` directory. As part of the module installation, the necessary jars will be dynamically downloaded and installed to your `${jetty.base}/lib/gcloud` directory.
If you need to up or downgrade the version of the jars, then you can delete the jars that were automatically installed and replace them. If you need to up or downgrade the version of the jars, then you can delete the jars that were automatically installed and replace them.
@ -168,7 +168,7 @@ maxQueryResults::
As an optimization, you can have Jetty store your session data into GCloud Datastore but also cache it into memcached. This serves two purposes: faster read-accesses and also better support for non-sticky load balancers (although using a non-sticky load balancer is highly undesirable and not recommended). As an optimization, you can have Jetty store your session data into GCloud Datastore but also cache it into memcached. This serves two purposes: faster read-accesses and also better support for non-sticky load balancers (although using a non-sticky load balancer is highly undesirable and not recommended).
You will need to enable the `gcloud-memcached-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. You will need to enable the `gcloud-memcached-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar].
If you already enabled the gcloud-sessions module, that's fine as the gcloud-memcached-sessions module depends on it anyway. If you already enabled the gcloud-sessions module, that's fine as the gcloud-memcached-sessions module depends on it anyway.

View File

@ -36,7 +36,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== The Infinispan Module ==== The Infinispan Module
When using the jetty distribution, to enable Infinispan session persistence, you will first need to enable the Infinispan link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. When using the jetty distribution, to enable Infinispan session persistence, you will first need to enable the Infinispan link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar].
As part of the module installation, the necessary Infinispan jars will be dynamically downloaded and installed to your `${jetty.base}/lib/infinispan` directory. As part of the module installation, the necessary Infinispan jars will be dynamically downloaded and installed to your `${jetty.base}/lib/infinispan` directory.
If you need to up or downgrade the version of the Infinispan jars, then you can delete the jars that were automatically installed and replace them. If you need to up or downgrade the version of the Infinispan jars, then you can delete the jars that were automatically installed and replace them.

View File

@ -40,7 +40,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== The jdbc-session Module ==== The jdbc-session Module
When using the jetty distribution, to enable jdbc session persistence, you will first need to enable the jdbc-session link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. When using the jetty distribution, to enable jdbc session persistence, you will first need to enable the jdbc-session link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar].
You will also find the following properties, either in your base's start.d/jdbc-session.ini file or appended to your start.ini, depending on how you enabled the module: You will also find the following properties, either in your base's start.d/jdbc-session.ini file or appended to your start.ini, depending on how you enabled the module:

View File

@ -41,7 +41,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== The nosql Module ==== The nosql Module
When using the jetty distribution, to enable the MongoDB session persistence mechanism, you will first need to enable the nosql link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. When using the jetty distribution, to enable the MongoDB session persistence mechanism, you will first need to enable the nosql link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar].
This module will automatically download the `mongodb-java-driver` and install it to your base's `lib/nosql` directory. This module will automatically download the `mongodb-java-driver` and install it to your base's `lib/nosql` directory.
As part of the module installation, the necessary mongo java driver jars will be dynamically downloaded and installed to your `${jetty.base}/lib/nosql` directory. As part of the module installation, the necessary mongo java driver jars will be dynamically downloaded and installed to your `${jetty.base}/lib/nosql` directory.

View File

@ -16,12 +16,15 @@
[[configuring-sessions-file-system]] [[configuring-sessions-file-system]]
=== Configuring Session Management using the File System === Non-Clustered Session Management: File System
When using the Jetty distribution, you will first need to enable the `session-store-file` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. When using the Jetty distribution, you will first need to enable the `session-store-file` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-file $ java -jar ../start.jar --add-to-start=session-store-file
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini
@ -32,12 +35,12 @@ INFO : Base directory was modified
//TODO - Callout default Session file location - note it is configurable //TODO - Callout default Session file location - note it is configurable
Doing this enables the File System Session module and any dependent modules or files needed for it to run on the server. Doing this enables the File System Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `{$jetty.base}` with nothing enabled. The example above is running an fresh `${jetty.base}` with nothing enabled.
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-file` module as well as the `sessions` and `server` modules, which are required for the File System session management to operate. When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-file` module as well as the `sessions` and `server` modules, which are required for the File System session management to operate.
Additionally a `${jetty.base}/sessions` directory was created. Additionally a `${jetty.base}/sessions` directory was created.
By default Session files will be saved to this directory. By default Session files will be saved to this directory.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
Opening the `start.d/session-store-file.ini` will show a list of all the configurable options for the file system session module: Opening the `start.d/session-store-file.ini` will show a list of all the configurable options for the file system session module:
@ -49,12 +52,12 @@ Opening the `start.d/session-store-file.ini` will show a list of all the configu
# --------------------------------------- # ---------------------------------------
--module=session-store-file --module=session-store-file
jetty.session.storeDir=${jetty.base}/sessions jetty.session.file.storeDir=${jetty.base}/sessions
#jetty.session.deleteUnrestorableFiles=false #jetty.session.file.deleteUnrestorableFiles=false
---- ----
jetty.session.storeDir:: jetty.session.storeDir::
This defines the location for storage of Session files. This defines the location for storage of Session files.
jetty.session.deleteUnrestorableFiles:: jetty.session.file.deleteUnrestorableFiles::
Boolean. Boolean.
If set to true, unreadable files will be deleted: this is useful to prevent repeated logging of the same error when the scavenger periodically (re-) attempts to load the corrupted information for a session in order to expire it. If set to true, unreadable files will be deleted: this is useful to prevent repeated logging of the same error when the scavenger periodically (re-) attempts to load the corrupted information for a session in order to expire it.

View File

@ -15,23 +15,68 @@
// ======================================================================== // ========================================================================
[[configuring-sessions-gcloud]] [[configuring-sessions-gcloud]]
=== Clustered Session Management: Google Cloud DataStore
=== Configuring Google Cloud DataStore ==== Preparation
You will first need to create a project and enable the Google Cloud api: https://cloud.google.com/docs/authentication#preparation.
Take note of the project id that you create in this step as you need to supply it in later steps.
===== Communicating with GCloudDataStore
====== When running Jetty outside of google infrastructure
Before running Jetty, you will need to choose one of the following methods to set up the local environment to enable remote GCloud DataStore communications.
1. Using the GCloud SDK:
* Ensure you have the GCloud SDK installed: https://cloud.google.com/sdk/?hl=en.
* Use the GCloud tool to set up the project you created in the preparation step: `gcloud config set project PROJECT_ID`
* Use the GCloud tool to authenticate a google account associated with the project created in the preparation step: `gcloud auth login ACCOUNT`
2. Using environment variables
* Define the environment variable `GCLOUD_PROJECT` with the project id you created in the preparation step.
* Generate a JSON link:https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts[service account key] and then define the environment variable `GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/key.json`
====== When Running Jetty Inside of Google Infrastructure
The Google deployment tools will automatically configure the project and authentication information for you.
==== Configuring Indexes for Session Data
Regardless of whether you're running inside or outside google infrastructure you will need to upload a file that defines some indexes that are needed by the GCloud datastore session data store.
This file is named `index.yaml` and you can find it in your distribution in `${jetty.base}/etc/sessions/gcloud/index.yaml`.
//TODO - Add index.yaml properties? Test with new 9.4.x. It needs uploaded to Google as part of config
Follow the instructions link:https://cloud.google.com/datastore/docs/tools/#the_development_workflow_using_gcloud[here] to upload the pre-generated `index.yaml` file.
===== Communicating with the GCloudDataStore Emulator
To enable communication using the GCloud Emulator:
* Ensure you have the GCloud SDK installed: https://cloud.google.com/sdk/?hl=en
* Follow the instructions link:https://cloud.google.com/datastore/docs/tools/datastore-emulator[here] on how to start the GCloud datastore emulator, and how to propagate the environment variables that it creates to the terminal in which you run Jetty.
==== Configuring the Google Cloud DataStore Module
When using the Jetty distribution, you will first need to enable the `session-store-gcloud` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. When using the Jetty distribution, you will first need to enable the `session-store-gcloud` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-gcloud $ java -jar ../start.jar --add-to-start=session-store-gcloud
ALERT: There are enabled module(s) with licenses. ALERT: There are enabled module(s) with licenses.
The following 1 module(s): The following 1 module(s):
+ contains software not provided by the Eclipse Foundation! + contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License! + contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license + has not been audited for compliance with its license
Module: session-store-gcloud Module: session-store-gcloud
+ GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license. + GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
+ https://github.com/GoogleCloudPlatform/gcloud-java + https://github.com/GoogleCloudPlatform/gcloud-java
+ http://www.apache.org/licenses/LICENSE-2.0.html + http://www.apache.org/licenses/LICENSE-2.0.html
@ -83,7 +128,7 @@ Usage: java -jar $JETTY_HOME/start.jar [options] [properties] [configs]
---- ----
Doing this enables the GCloud Session module and any dependent session modules or files needed for it to run on the server. Doing this enables the GCloud Session module and any dependent session modules or files needed for it to run on the server.
The example above is running an fresh `{$jetty.base}` with nothing enabled. The example above is running an fresh `${jetty.base}` with nothing enabled.
Because the Google Cloud DataStore is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). Because the Google Cloud DataStore is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
You will notice, however, that the above output presented a warning: GCloud requires certain Java Commons Logging features to work correctly. You will notice, however, that the above output presented a warning: GCloud requires certain Java Commons Logging features to work correctly.
As such, you will also need to enable either the `jcl` or `jcl-slf4j` module. As such, you will also need to enable either the `jcl` or `jcl-slf4j` module.
@ -94,11 +139,11 @@ $ java -jar ../start.jar --add-to-start=jcl
ALERT: There are enabled module(s) with licenses. ALERT: There are enabled module(s) with licenses.
The following 1 module(s): The following 1 module(s):
+ contains software not provided by the Eclipse Foundation! + contains software not provided by the Eclipse Foundation!
+ contains software not covered by the Eclipse Public License! + contains software not covered by the Eclipse Public License!
+ has not been audited for compliance with its license + has not been audited for compliance with its license
Module: jcl Module: jcl
+ Log4j is released under the Apache 2.0 license. + Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html + http://www.apache.org/licenses/LICENSE-2.0.html
@ -109,14 +154,14 @@ INFO : Base directory was modified
---- ----
When the `--add-to-start` argument was added to the command line the first time, it enabled the the `session-store-gcloud` module as well as the `sessions` and `server` modules, which are required for GCloud session management to operate; the `jcl` module was added when we ran it the second time. When the `--add-to-start` argument was added to the command line the first time, it enabled the the `session-store-gcloud` module as well as the `sessions` and `server` modules, which are required for GCloud session management to operate; the `jcl` module was added when we ran it the second time.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
____ ____
[NOTE] [NOTE]
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated `${jetty.base}/lib/` directory and use the `--skip-file-validation=<module name>` command line option to prevent errors when starting your server. If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated `${jetty.base}/lib/` directory and use the `--skip-file-validation=<module name>` command line option to prevent errors when starting your server.
____ ____
Opening the `start.d/session-store-gcloud.ini` will show a list of all the configurable options for the Google Cloud DataStore module: Opening the `start.d/session-store-gcloud.ini` will show a list of all the configurable properties for the Google Cloud DataStore module:
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
@ -128,13 +173,23 @@ Opening the `start.d/session-store-gcloud.ini` will show a list of all the confi
## GCloudDatastore Session config ## GCloudDatastore Session config
#jetty.gcloudSession.maxRetries=5 #jetty.session.gcloud.maxRetries=5
#jetty.gcloudSession.backoffMs=1000 #jetty.session.gcloud.backoffMs=1000
#jetty.session.gcloud.model.kind=GCloudSession
#jetty.session.gcloud.model.id=id
#jetty.session.gcloud.model.contextPath=contextPath
#jetty.session.gcloud.model.vhost=vhost
#jetty.session.gcloud.model.accessed=accessed
#jetty.session.gcloud.model.lastAccessed=lastAccessed
#jetty.session.gcloud.model.createTime=createTime
#jetty.session.gcloud.model.cookieSetTime=cookieSetTime
#jetty.session.gcloud.model.lastNode=lastNode
#jetty.session.gcloud.model.expiry=expiry
#jetty.session.gcloud.model.maxInactive=maxInactive
#jetty.session.gcloud.model.attributes=attributes
---- ----
jetty.gcloudSession.maxRetries:: jetty.session.gcloud.maxRetries::
Maxmium number of tries to connect to GCloud DataStore to write sessions. Maxmium number of tries to connect to GCloud DataStore to write sessions.
jetty.gcloudSession.backoffMs:: jetty.session.gcloud.backoffMs::
Amount of time, in milliseconds, between attempts to connect to the GCloud DataStore to write sessions. Amount of time, in milliseconds, between attempts to connect to the GCloud DataStore to write sessions.
//TODO - Add index.yaml properties?

View File

@ -16,12 +16,15 @@
[[configuring-sessions-infinispan]] [[configuring-sessions-infinispan]]
=== Configuring Remote Inifinspan Clustering === Clustered Session Management: Inifinspan
When using the Jetty distribution, you will first need to enable the `session-store-infinispan-remote` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. When using the Jetty distribution, you will first need to enable the `session-store-infinispan-remote` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-infinispan-remote $ java -jar ../start.jar --add-to-start=session-store-infinispan-remote
ALERT: There are enabled module(s) with licenses. ALERT: There are enabled module(s) with licenses.
@ -45,11 +48,11 @@ INFO : Base directory was modified
---- ----
Doing this enables the remote Infinispan Session module and any dependent modules or files needed for it to run on the server. Doing this enables the remote Infinispan Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `{$jetty.base}` with nothing enabled. The example above is running an fresh `${jetty.base}` with nothing enabled.
Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-remote` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate. When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-remote` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate.
It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them. It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
____ ____
[NOTE] [NOTE]
@ -66,18 +69,20 @@ Opening the `start.d/session-store-infinispan-remote.ini` will show a list of al
# --------------------------------------- # ---------------------------------------
--module=session-store-infinispan-remote --module=session-store-infinispan-remote
#jetty.session.remoteInfinispanCache.name=sessions #jetty.session.infinispan.remoteCacheName=sessions
#jetty.session.infinispanIdleTimeout.seconds=0 #jetty.session.infinispan.idleTimeout.seconds=0
#jetty.session.gracePeriod.seconds=3600 #jetty.session.gracePeriod.seconds=3600
---- ----
jetty.session.remoteInfinispanCache.name:: jetty.session.infinispan.remoteCacheName::
jetty.session.infinispanIdleTimeout.seconds:: Name of the cache in Infinispan where sessions will be stored.
jetty.session.infinispan.idleTimeout.seconds::
Amount of time, in seconds, that the system allows the connector to remain idle before closing the connection.
jetty.session.gracePeriod.seconds:: jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
=== Configuring Embedded Inifinspan Clustering ==== Configuring Embedded Inifinspan Clustering
During testing, it can be helpful to run an in-process instance of Infinispan. During testing, it can be helpful to run an in-process instance of Infinispan.
To enable this you will first need to enable the `session-store-infinispan-embedded` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. To enable this you will first need to enable the `session-store-infinispan-embedded` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
@ -106,8 +111,8 @@ INFO : Base directory was modified
---- ----
Doing this enables the embedded Infinispan Session module and any dependent modules or files needed for it to run on the server. Doing this enables the embedded Infinispan Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `{$jetty.base}` with nothing enabled. The example above is running an fresh `${jetty.base}` with nothing enabled.
Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-embedded` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate. When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-embedded` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate.
It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them. It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.

View File

@ -16,12 +16,15 @@
[[configuring-sessions-jdbc]] [[configuring-sessions-jdbc]]
=== Configuring JDBC Clustering === Clustered Session Management: JDBC
When using the Jetty distribution, you will first need to enable the `session-store-jdbc` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. When using the Jetty distribution, you will first need to enable the `session-store-jdbc` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-jdbc $ java -jar ../start.jar --add-to-start=session-store-jdbc
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini
@ -30,9 +33,9 @@ INFO : Base directory was modified
---- ----
Doing this enables the JDBC Session module and any dependent modules or files needed for it to run on the server. Doing this enables the JDBC Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `{$jetty.base}` with nothing enabled. The example above is running an fresh `${jetty.base}` with nothing enabled.
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-jdbc` module as well as the `sessions` and `server` modules, which are required for JDBC session management to operate. When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-jdbc` module as well as the `sessions` and `server` modules, which are required for JDBC session management to operate.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
Opening the `start.d/session-store-jdbc.ini` will show a list of all the configurable options for the JDBC module: Opening the `start.d/session-store-jdbc.ini` will show a list of all the configurable options for the JDBC module:
@ -52,49 +55,40 @@ Opening the `start.d/session-store-jdbc.ini` will show a list of all the configu
## Connection type:Datasource ## Connection type:Datasource
db-connection-type=datasource db-connection-type=datasource
#jetty.session.datasourceName=/jdbc/sessions #jetty.session.jdbc.datasourceName=/jdbc/sessions
## Connection type:driver ## Connection type:driver
#db-connection-type=driver #db-connection-type=driver
#jetty.session.driverClass= #jetty.session.jdbc.driverClass=
#jetty.session.driverUrl= #jetty.session.jdbc.driverUrl=
## Session table schema ## Session table schema
#jetty.sessionTableSchema.accessTimeColumn=accessTime #jetty.session.jdbc.schema.accessTimeColumn=accessTime
#jetty.sessionTableSchema.contextPathColumn=contextPath #jetty.session.jdbc.schema.contextPathColumn=contextPath
#jetty.sessionTableSchema.cookieTimeColumn=cookieTime #jetty.session.jdbc.schema.cookieTimeColumn=cookieTime
#jetty.sessionTableSchema.createTimeColumn=createTime #jetty.session.jdbc.schema.createTimeColumn=createTime
#jetty.sessionTableSchema.expiryTimeColumn=expiryTime #jetty.session.jdbc.schema.expiryTimeColumn=expiryTime
#jetty.sessionTableSchema.lastAccessTimeColumn=lastAccessTime #jetty.session.jdbc.schema.lastAccessTimeColumn=lastAccessTime
#jetty.sessionTableSchema.lastSavedTimeColumn=lastSavedTime #jetty.session.jdbc.schema.lastSavedTimeColumn=lastSavedTime
#jetty.sessionTableSchema.idColumn=sessionId #jetty.session.jdbc.schema.idColumn=sessionId
#jetty.sessionTableSchema.lastNodeColumn=lastNode #jetty.session.jdbc.schema.lastNodeColumn=lastNode
#jetty.sessionTableSchema.virtualHostColumn=virtualHost #jetty.session.jdbc.schema.virtualHostColumn=virtualHost
#jetty.sessionTableSchema.maxIntervalColumn=maxInterval #jetty.session.jdbc.schema.maxIntervalColumn=maxInterval
#jetty.sessionTableSchema.mapColumn=map #jetty.session.jdbc.schema.mapColumn=map
#jetty.sessionTableSchema.table=JettySessions #jetty.session.jdbc.schema.table=JettySessions
---- ----
jetty.session.gracePeriod.seconds:: jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
db-connection-type:: db-connection-type::
jetty.session.datasourceName:: Set to either `datasource` or `driver` depending on the type of connection being used.
jetty.session.jdbc.datasourceName::
Name of the remote datasource.
jetty.session.jdbc.driverClass::
Name of the JDBC driver that controls access to the remote database, such as `com.mysql.jdbc.Driver`
jetty.session.jdbc.driverUrl::
Url of the database which includes the driver type, host name and port, service name and any specific attributes unique to the database, such as a username.
As an example, here is a mysql connection with the username appended: `jdbc:mysql://127.0.0.1:3306/sessions?user=sessionsadmin`.
db-connection-type:: The `jetty.sessionTableSchema` values represent the names for the columns in the JDBC database and can be changed to suit your environment.
jetty.session.driverClass::
jetty.session.driverUrl::
jetty.sessionTableSchema.accessTimeColumn::
jetty.sessionTableSchema.contextPathColumn::
jetty.sessionTableSchema.cookieTimeColumn::
jetty.sessionTableSchema.createTimeColumn::
jetty.sessionTableSchema.expiryTimeColumn::
jetty.sessionTableSchema.lastAccessTimeColumn::
jetty.sessionTableSchema.lastSavedTimeColumn::
jetty.sessionTableSchema.idColumn::
jetty.sessionTableSchema.lastNodeColumn::
jetty.sessionTableSchema.virtualHostColumn::
jetty.sessionTableSchema.maxIntervalColumn::
jetty.sessionTableSchema.mapColumn::
jetty.sessionTableSchema.table::

View File

@ -16,12 +16,15 @@
[[configuring-sessions-mongo]] [[configuring-sessions-mongo]]
=== Configuring MongoDB Clustering === Clustered Session Management: MongoDB
When using the Jetty distribution, you will first need to enable the `session-store-mongo` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. When using the Jetty distribution, you will first need to enable the `session-store-mongo` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
$ java -jar ../start.jar --add-to-start=session-store-mongo $ java -jar ../start.jar --add-to-start=session-store-mongo
ALERT: There are enabled module(s) with licenses. ALERT: There are enabled module(s) with licenses.
@ -44,11 +47,11 @@ INFO : Base directory was modified
---- ----
Doing this enables the MongoDB Session module and any dependent modules or files needed for it to run on the server. Doing this enables the MongoDB Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `{$jetty.base}` with nothing enabled. The example above is running an fresh `${jetty.base}` with nothing enabled.
Because MongoDB is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). Because MongoDB is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-mongo` module as well as the `sessions` and `server` modules, which are required for MongoDB session management to operate.. When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-mongo` module as well as the `sessions` and `server` modules, which are required for MongoDB session management to operate..
It also downloaded the needed Mongo-specific jar file and created a directory named `${jetty.base}/lib/nosql/` to house it. It also downloaded the needed Mongo-specific jar file and created a directory named `${jetty.base}/lib/nosql/` to house it.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
____ ____
[NOTE] [NOTE]
@ -65,14 +68,20 @@ Opening the `start.d/session-store-mongo.ini` will show a list of all the config
# --------------------------------------- # ---------------------------------------
--module=session-store-mongo --module=session-store-mongo
#jetty.session.dbName=HttpSessions #jetty.session.mongo.dbName=HttpSessions
#jetty.session.collectionName=jettySessions #jetty.session.mongo.collectionName=jettySessions
#jetty.session.mongo.host=localhost
#jetty.session.mongo.port=27017
#jetty.session.gracePeriod.seconds=3600 #jetty.session.gracePeriod.seconds=3600
---- ----
jetty.session.dbName:: jetty.session.mongo.dbName::
Name of the database in Mongo used to store the Session collection. Name of the database in Mongo used to store the Session collection.
jetty.session.collectionName:: jetty.session.mongo.collectionName::
Name of the collection in Mongo used to keep all of the Sessions. Name of the collection in Mongo used to keep all of the Sessions.
jetty.session.mongo.host::
Host name or address for the remote Mongo instance.
jetty.session.mongo.port::
Port number for the remote Mongo instance.
jetty.session.gracePeriod.seconds:: jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.

View File

@ -42,12 +42,18 @@ However, it is possible to provide your own implementation that never shares Ses
Where the `SessionCache` handles Session information, Session data is stored in a `SessionDataStore` that is specific to the clustering technology being implemented. Where the `SessionCache` handles Session information, Session data is stored in a `SessionDataStore` that is specific to the clustering technology being implemented.
There is only one (1) `SessionDataStore` per `SessionCache`. There is only one (1) `SessionDataStore` per `SessionCache`.
//TODO : Information on memcache-d, when to use different config options. "Configuration Scenarios?"
// Null cache, memcache, non-sticky load-balancer
// in-memory caching
Visually the Session Hierarchy can be represented like this: Visually the Session Hierarchy can be represented like this:
image::images/SessionsHierarchy.png[] image::images/SessionsHierarchy.png[]
==== Configuring Sessions in the Jetty Distribution ==== Configuring Sessions in the Jetty Distribution
Jetty provides support for several different Session Management/Clustering technologies including JDBC, MongoDB, Inifinispan, Google Cloud Datastore and one for local file storage. Jetty provides support for several different Session Management technologies.
Both link:#configuring-sessions-file-system[local file storage] and in-memory session management can be implemented for standard implementations.
For implementations using clustered technologies, link:#configuring-sessions-jdbc[JDBC], link:#configuring-sessions-mongo[MongoDB], link:#configuring-sessions-infinispan[Inifinispan] and link:#configuring-sessions-gcloud[Google Cloud Datastore] are all supported.
Setting up these technologies is as easy as enabling it's link:#startup-modules[module] and editing it's associated ini file with any usernames, passwords or changes you need to make for your instance. Setting up these technologies is as easy as enabling it's link:#startup-modules[module] and editing it's associated ini file with any usernames, passwords or changes you need to make for your instance.
The following sections will cover how exactly to enable the required modules as well as an overview of what options are available for customization. The following sections will cover how exactly to enable the required modules as well as an overview of what options are available for customization.

View File

@ -20,8 +20,8 @@
include::startup-overview.adoc[] include::startup-overview.adoc[]
include::start-jar.adoc[] include::start-jar.adoc[]
include::startup-base-vs-home.adoc[] include::startup-base-vs-home.adoc[]
include::startup-xml-config.adoc[]
include::startup-classpath.adoc[] include::startup-classpath.adoc[]
include::startup-modules.adoc[] include::startup-modules.adoc[]
include::startup-xml-config.adoc[]
include::startup-unix-service.adoc[] include::startup-unix-service.adoc[]
include::startup-windows-service.adoc[] include::startup-windows-service.adoc[]

View File

@ -95,40 +95,31 @@ Enables debugging output of the startup procedure.
*Note*: This does not set up debug logging for Jetty itself. *Note*: This does not set up debug logging for Jetty itself.
For information on logging, please see the section on <<configuring-jetty-logging, Configuring Jetty Logging.>> For information on logging, please see the section on <<configuring-jetty-logging, Configuring Jetty Logging.>>
--start-log-file=<filename>:: --start-log-file=<filename>::
Sends all startup output to the filename specified. Sends all startup output to the filename specified.
+
Filename is relative to `${jetty.base}`. Filename is relative to `${jetty.base}`.
This is useful for capturing startup issues where the Jetty-specific logger has not yet kicked in due to a possible startup configuration error. This is useful for capturing startup issues where the Jetty-specific logger has not yet kicked in due to a possible startup configuration error.
--list-modules:: --list-modules::
Lists all the modules defined by the system. Lists all the modules defined by the system.
+
Looks for module files using the link:#startup-base-and-home[normal `${jetty.base}` and `${jetty.home}` resolution logic]. Looks for module files using the link:#startup-base-and-home[normal `${jetty.base}` and `${jetty.home}` resolution logic].
+
Also lists enabled state based on information present on the command line, and all active startup INI files. Also lists enabled state based on information present on the command line, and all active startup INI files.
--module=<name>,(<name>)*:: --module=<name>,(<name>)*::
Enables one or more modules by name (use `--list-modules` to see the list of available modules). Enables one or more modules by name (use `--list-modules` to see the list of available modules).
+
This enables all transitive (dependent) modules from the module system as well. This enables all transitive (dependent) modules from the module system as well.
+
If you use this from the shell command line, it is considered a temporary effect, useful for testing out a scenario. If you use this from the shell command line, it is considered a temporary effect, useful for testing out a scenario.
If you want this module to always be enabled, add this command to your `${jetty.base}/start.ini.` If you want this module to always be enabled, add this command to your `${jetty.base}/start.ini.`
--create-startd::
Creates a `${jetty.base}/start.d/` directory.
If a `${jetty.base}/start.ini` file already exists, it is copied to the `${jetty.base}/start.d` directory.
--add-to-start=<name>,(<name>)*:: --add-to-start=<name>,(<name>)*::
Enables a module by appending lines to the `${jetty.base}/start.ini` file. Enables a module by appending lines to the `${jetty.base}/start.ini` file.
+
The lines that are added are provided by the module-defined INI templates. The lines that are added are provided by the module-defined INI templates.
+
Note: Transitive modules are also appended. Note: Transitive modules are also appended.
--add-to-startd=<name>,(<name>)*::
Enables a module via creation of a module-specific INI file in the `${jetty.base}/start.d/` directory.
+
The content of the new INI is provided by the module-defined ini templates.
+
Note: Transitive modules are also created in the same directory as their own INI files.
[NOTE] [NOTE]
-- --
With respect to `start.ini` and `start.d/*.ini` files, only *one* of these methods should be implemented. With respect to `start.ini` and `start.d/*.ini` files, only *one* of these methods should be implemented.
Mixing a `start.ini` with module specific ini files in the `{$jetty.base}/start.d` directory can lead to server issues unless great care is taken. Mixing a `start.ini` with module specific ini files in the `{$jetty.base}/start.d` directory can lead to server issues unless great care is taken.
Please see link:#start-vs-startd[Start.ini vs. Start.d] for more information.
-- --
--write-module-graph=<filename>:: --write-module-graph=<filename>::

View File

@ -17,7 +17,7 @@
[[startup-modules]] [[startup-modules]]
=== Managing Startup Modules === Managing Startup Modules
Starting with Jetty 9.1, a new Module system was introduced, replacing the previous `start.config` + `OPTIONS` techniques from past Jetty Distributions. Jetty 9.1 a new Module system replacing the previous `start.config` + `OPTIONS` techniques from past Jetty Distributions.
The standard Jetty Distribution ships with several modules defined in `${jetty.home}/modules/`. The standard Jetty Distribution ships with several modules defined in `${jetty.home}/modules/`.
@ -43,7 +43,7 @@ List of Jetty IoC XML Configurations::
If the default XML is not sufficient to satisfy your needs, you can override this XML by making your own in the `${jetty.base}/etc/` directory, with the same name. If the default XML is not sufficient to satisfy your needs, you can override this XML by making your own in the `${jetty.base}/etc/` directory, with the same name.
The resolution steps for Jetty Base and Jetty Home will ensure that your copy from `${jetty.base}` will be picked up over the default one in `${jetty.home}`. The resolution steps for Jetty Base and Jetty Home will ensure that your copy from `${jetty.base}` will be picked up over the default one in `${jetty.home}`.
Jetty INI Template:: Jetty INI Template::
Each module can optionally declare a startup ini template that is used to insert/append/inject sample configuration elements into the `start.ini` or `start.d/*.ini` files when using the `--add-to-start=<name>` or `--add-to-startd=<name>` command line arguments in `start.jar`. Each module can optionally declare a startup ini template that is used to insert/append/inject sample configuration elements into the `start.ini` or `start.d/*.ini` files when using the `--add-to-start=<name>` command line argument in `start.jar`.
Commonly used to present some of the parameterized property options from the Jetty IoC XML configuration files also referenced in the same module. Commonly used to present some of the parameterized property options from the Jetty IoC XML configuration files also referenced in the same module.
The `[ini-template]` section declares this section of sample configuration. The `[ini-template]` section declares this section of sample configuration.
Required Files and Directories:: Required Files and Directories::
@ -62,15 +62,15 @@ Download File;;
[[enabling-modules]] [[enabling-modules]]
==== Enabling Modules ==== Enabling Modules
Jetty ships with many modules defined, and a small subset predefined in the `start.ini` found in the jetty distribution.
____ ____
[TIP] [TIP]
The default distribution has a co-mingled `${jetty.home}` and `${jetty.base}`. Where the directories for `${jetty.home}` and `${jetty.base}` point to the same location. The default distribution has a co-mingled `${jetty.home}` and `${jetty.base}` where the directories for `${jetty.home}` and `${jetty.base}` point to the same location.
It is highly encouraged that you learn about the differences in link:#startup-base-and-home[Jetty Base vs Jetty Home] and take full advantage of this setup. It is highly encouraged that you learn about the differences in link:#startup-base-and-home[Jetty Base vs Jetty Home] and take full advantage of this setup.
____ ____
When you want enable a module, you can use the `--module=<modulename>` syntax on the command line to enable that module and all of its dependent modules. Jetty ships with many modules defined in `${jetty.home}/modules`.
Enabling a module is a simple process: simply add the `--add-to-start` syntax on the command line.
Doing this will enable the module and any dependent modules.
An example of this, with a new, empty, base directory. An example of this, with a new, empty, base directory.
We can see from this output, that the directory is new. We can see from this output, that the directory is new.
@ -95,14 +95,95 @@ include::screen-http-webapp-deploy-listconfig.adoc[]
You now have a configured and functional server, albeit with no webapps deployed. You now have a configured and functional server, albeit with no webapps deployed.
At this point you can place a webapp (war file) in the `mybase/webapps/` directory and and start Jetty. At this point you can place a webapp (war file) in the `mybase/webapps/` directory and and start Jetty.
[[start-vs-startd]]
==== Start.ini vs. Start.d
In the above example, when a module is activated the contents of that module file are added in `${jetty.base}/start.ini`.
As additional modules are added, their contents are appended to this file.
This can be beneficial if you want all of your module configurations in a single file, but for large server instances with lots of modules it can pose a challenge to quickly find and make changes or to remove a module.
As an alternative to a single `start.ini` file you can opt to house modules in a `${jetty.base}/start.d` directory.
Modules activated when a `start.d` directory exists will be stored as a single file per module.
Below is an example of a fresh `${jetty.base}` that will create a `start.d` directory and activate several modules.
[source, screen, subs="{sub-order}"]
....
[jetty.home]$ mkdir mybase
[jetty.home]$ cd mybase/
[mybase]$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
[mybase]$ ls -all
total 0
drwxr-xr-x 3 staff staff 102 Aug 29 15:16 .
drwxr-xr-x@ 26 staff staff 884 Aug 29 15:16 ..
drwxr-xr-x 6 staff staff 204 Aug 29 15:19 start.d
[mybase]$ java -jar ../start.jar --add-to-start=server,client,webapp,websocket
INFO : webapp initialised in ${jetty.base}/start.d/webapp.ini
INFO : server initialised in ${jetty.base}/start.d/server.ini
INFO : websocket initialised in ${jetty.base}/start.d/websocket.ini
INFO : client initialised in ${jetty.base}/start.d/client.ini
INFO : Base directory was modified
[mybase]$ cd start.d/
[mybase]$ ls -all
total 32
drwxr-xr-x 6 staff staff 204 Aug 29 15:19 .
drwxr-xr-x 3 staff staff 102 Aug 29 15:16 ..
-rw-r--r-- 1 staff staff 175 Aug 29 15:19 client.ini
-rw-r--r-- 1 staff staff 2250 Aug 29 15:19 server.ini
-rw-r--r-- 1 staff staff 265 Aug 29 15:19 webapp.ini
-rw-r--r-- 1 staff staff 177 Aug 29 15:19 websocket.ini
....
In the example, we first create a new `${jetty.base}` and then create the `start.d` directory with the `--create-startd` command.
Next, we use the `--add-to-start` command which activates the modules and creates their respective ini files in the `start.d` directory.
If you have an existing `start.ini` file but would like to use the `start.d` structure for additional modules, you can use the `--create-startd` command as well.
Doing this will create the `start.d` directory and copy your existing `start.ini` file in to it.
Any new modules added to the server will have their own `<module name>.ini` file created in the `start.d` directory.
[source, screen, subs="{sub-order}"]
....
[mybase]$ java -jar ../start.jar --add-to-start=server,client,webapp,websocket
INFO : webapp initialised in ${jetty.base}/start.ini
INFO : server initialised in ${jetty.base}/start.ini
INFO : websocket initialised in ${jetty.base}/start.ini
INFO : client initialised in ${jetty.base}/start.ini
INFO : Base directory was modified
[mybase]$ java -jar ../start.jar --create-startd
INFO : Base directory was modified
[mybase]$ tree
.
└── start.d
└── start.ini
[mybase]$ java -jar ../start.jar --add-to-start=ssl
INFO : ssl initialised in ${jetty.base}/start.d/ssl.ini
INFO : Base directory was modified
[mybase]$ tree
.
├── etc
│   └── keystore
└── start.d
├── ssl.ini
└── start.ini
....
[NOTE]
--
It is *not* recommended to use both a `${jetty.base}/start.ini` file and a `${jetty.base}/start.d` directory at the same time and doing so can cause issues.
--
[[startup-configuring-modules]] [[startup-configuring-modules]]
==== Configuring Modules ==== Configuring Modules
Once a module has been enabled for the server, it can be further configured to meet your needs. Once a module has been enabled for the server, it can be further configured to meet your needs.
This is done by editing the associated ini file for the module. This is done by editing the associated ini file for the module.
If your server setup is using a centralized ini configuration, you will edit the `{$jetty.base}/server.ini` file. If your server setup is using a centralized ini configuration, you will edit the `${jetty.base}/server.ini` file.
If you have elected to manage each module within it's own ini file, you can find these files in the `{$jetty.base}/start.d` directory. If you have elected to manage each module within it's own ini file, you can find these files in the `${jetty.base}/start.d` directory.
When a module is activated, a number of properties are set by default. When a module is activated, a number of properties are set by default.
To view these defaults, open up the associated ini file. To view these defaults, open up the associated ini file.

View File

@ -136,7 +136,7 @@ Make sure to use persistent HTTP/1.1 connections.
====== JVM Tuning ====== JVM Tuning
* Tune the link:garbage-collection.html#examples[Garbage Collection] * Tune the link:#tuning-examples[Garbage Collection]
* Allocate sufficient memory * Allocate sufficient memory
* Use the -server option * Use the -server option
* Jetty Tuning * Jetty Tuning

View File

@ -24,29 +24,28 @@ This document provides an overview of how to configure SSL and TLS for Jetty.
Which browser/OS supports which protocols can be https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers[found on Wikipedia]. Which browser/OS supports which protocols can be https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers[found on Wikipedia].
* TLS v1.1 and v1.2: The protocols which should be used wherever possible. * TLS v1.2: The protocol which should be used wherever possible.
All CBC based ciphers are supported since Java 7, the new GCM modes are supported since Java 8. All CBC based ciphers are supported since Java 7, the new GCM modes are supported since Java 8.
===== Older Protocols ===== Older Protocols
Both TLS v1.0 and SSL v3 are no longer supported by default. If your Jetty implementation requires these protocols for legacy support, they can be enabled manually. TLS v1.0, v1.1 and SSL v3 are no longer supported by default. If your Jetty implementation requires these protocols for legacy support, they can be enabled manually.
____ ____
[NOTE] [NOTE]
Once TLS v1.3 is released, there will be no workaround available for TLS v1.0. Once TLS v1.3 is released, there will be no workaround available for TLS v1.0 or v1.1.
Plans for TLS v1.3 include banning ciphers with known vulnerabilities from being present at any level. Plans for TLS v1.3 include banning ciphers with known vulnerabilities from being present at any level.
It is recommended to upgrade any clients using these ciphers as soon as possible or face being locked into a outdated version of Jetty, Java or even OS. It is recommended to upgrade any clients using these ciphers as soon as possible or face being locked into a outdated version of Jetty, Java or even OS.
____ ____
By default, Jetty exclused these ciphers in the link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L253-L256[`SslContextFactory`.] By default, Jetty excludes these ciphers in the link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L249-L256[`SslContextFactory`.]
You can re-enable these by re-declaring the ciphers you want excluded in code: You can re-enable these by re-declaring the ciphers you want excluded in code:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
SslContextFactory sslContextFactory = new SslContextFactory(); SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setExcludeCipherSuites( sslContextFactory.setExcludeCipherSuites(
"SSL_DHE_DSS_WITH_DES_CBC_SHA", "^.*_(MD5|SHA|SHA1)$");
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
---- ----
If, after making these changes, you still have issues using these ciphers they are likely being blocked at the JVM level. If, after making these changes, you still have issues using these ciphers they are likely being blocked at the JVM level.
@ -355,6 +354,254 @@ $ keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destke
If you are updating your configuration to use a newer certificate, as when the old one is expiring, just load the newer certificate as described in the section, xref:loading-keys-and-certificates[]. If you are updating your configuration to use a newer certificate, as when the old one is expiring, just load the newer certificate as described in the section, xref:loading-keys-and-certificates[].
If you imported the key and certificate originally using the PKCS12 method, use an alias of "1" rather than "jetty", because that is the alias the PKCS12 process enters into the keystore. If you imported the key and certificate originally using the PKCS12 method, use an alias of "1" rather than "jetty", because that is the alias the PKCS12 process enters into the keystore.
==== Configuring SSL in Jetty Distribution
For those of you using the Jetty Distribution, enabling SSL support is as easy as activating the `ssl` module.
An example of this setup:
[source, plain, subs="{sub-order}"]
----
$ cd /path/to/mybase
$ java -jar /path/to/jetty-dist/start.jar --add-to-start=ssl
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO : ssl initialised in ${jetty.base}/start.d/ssl.ini
INFO : Base directory was modified
$ tree
.
├── etc
│   └── keystore
└── start.d
├── server.ini
└── ssl.ini
----
When you open `start.d/ssl.ini`, you will see many commented properties ready for you to configure the `SslContextFactory` basics.
To highlight some of the more commonly used properties:
jetty.ssl.host::
Configures which interfaces the SSL/TLS Connector should listen on.
jetty.ssl.port::
Configures which port the SSL/TLS Connector should listen on.
jetty.httpConfig.securePort::
If a webapp needs to redirect to a secure version of the same resource, then this is the port reported back on the response `location` line (having this be separate is useful if you have something sitting in front of Jetty, such as a Load Balancer or proxy).
jetty.sslContext.keyStorePath::
Sets the location of the `keystore` that you configured with your certificates.
jetty.sslContext.keyStorePassword::
Sets the Password for the `keystore`.
[[two-way-authentication]]
==== Two Way Authentication
To enable two-way authentication, you first need to activate the ssl module as shown in the previous section.
[source%nowrap,ini,linenums]
.start.d/ssl.ini
----
--module=ssl
jetty.secure.port=8443
jetty.keystore=etc/keystore
jetty.keystore.password=OBF:
jetty.keymanager.password=OBF:
jetty.truststore=etc/truststore
jetty.truststore.password=OBF:
# enable two way authentication
jetty.ssl.needClientAuth=true
----
[[layout-of-keystore-and-truststore]]
===== Layout of `keystore` and `truststore`
`keystore` only contains the server's private key and certificate.
[source%nowrap,plain,linenums]
----
$ keytool -list -keystore keystore -storetype jks -storepass '' -v
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: *.example.com
Creation date: Sep 12, 2016
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=*.example.com, OU=Web Servers, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: b63af619ff0b4c368735113ba5db8997
Valid from: Mon Sep 12 15:09:49 CST 2016 until: Wed Sep 12 15:09:49 CST 2018
Certificate fingerprints:
MD5: D9:26:CC:27:77:9D:26:FE:67:4C:BE:FF:E3:95:1E:97
SHA1: AF:DC:D2:65:6A:33:42:E3:81:9E:4D:19:0D:22:20:C7:6F:2F:11:D0
SHA256: 43:E8:21:5D:C6:FB:A0:7D:5D:7B:9C:8B:8D:E9:4B:52:BF:50:0D:90:4F:61:C2:18:9E:89:AA:4C:C2:93:BD:32
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k
0010: F5 A5 8F C1 ....
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
#3: ObjectId: 2.5.29.37 Criticality=true
ExtendedKeyUsages [
serverAuth
clientAuth
]
#4: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
Key_Encipherment
Data_Encipherment
]
#5: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 7D 26 36 73 61 5E 08 94 AD 25 13 46 DB DB 95 25 .&6sa^...%.F...%
0010: BF 82 5A CA ..Z.
]
]
*******************************************
*******************************************
----
`truststore` contains intermediary CA and root CA.
[source%nowrap,plain,linenums]
----
$ keytool -list -keystore truststore -storetype jks -storepass '' -v
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 2 entries
Alias name: example.com co.,ltd. etp ca
Creation date: Sep 12, 2016
Entry type: trustedCertEntry
Owner: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: f6e7b86f6fdb467f9498fb599310198f
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2035
Certificate fingerprints:
MD5: ED:A3:91:57:D8:B8:6E:B1:01:58:55:5C:33:14:F5:99
SHA1: D9:A4:93:9D:A6:F8:A3:F9:FD:85:51:E2:C5:2E:0B:EE:80:E7:D0:22
SHA256: BF:54:7A:F6:CA:0C:FA:EF:93:B6:6B:6E:2E:D7:44:A8:40:00:EC:69:3A:2C:CC:9A:F7:FE:8E:6F:C0:FA:22:38
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k
0010: F5 A5 8F C1 ....
]
]
*******************************************
*******************************************
Alias name: example.com co.,ltd. root ca
Creation date: Sep 12, 2016
Entry type: trustedCertEntry
Owner: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
Serial number: f0a45bc9972c458cbeae3f723055f1ac
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2114
Certificate fingerprints:
MD5: 50:61:62:22:71:60:F7:69:2E:27:42:6B:62:31:82:79
SHA1: 7A:6D:A6:48:B1:43:03:3B:EA:A0:29:2F:19:65:9C:9B:0E:B1:03:1A
SHA256: 05:3B:9C:5B:8E:18:61:61:D1:9C:AA:0E:8C:B1:EA:44:C2:6E:67:5D:96:30:EC:8C:F6:6F:E1:EC:AD:00:60:F1
Signature algorithm name: SHA256withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
#4: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
0010: E6 E6 04 46 ...F
]
]
*******************************************
*******************************************
----
____
[NOTE]
If you use a keystore which contains only one `PrivateKeyEntry` item as the `keystore` and the `truststore`, you may get a `javax.net.ssl.SSLHandshakeException` with `null cert chain` message.
____
[[configuring-sslcontextfactory]] [[configuring-sslcontextfactory]]
==== Configuring the Jetty SslContextFactory ==== Configuring the Jetty SslContextFactory
@ -401,52 +648,17 @@ setExcludeProtocols / setIncludeProtocols::
____ ____
[NOTE] [NOTE]
When working with Includes / Excludes, it is important to know that Excludes will always win. When working with Includes / Excludes, it is important to know that *Excludes will always win.*
The selection process is to process the JVM list of available Cipher Suites or Protocols against the include list, then remove the excluded ones. The selection process is to process the JVM list of available Cipher Suites or Protocols against the include list, then remove the excluded ones.
Be aware that each Include / Exclude list has a Set method (replace the list) or Add method (append the list). Be aware that each Include / Exclude list has a Set method (replace the list) or Add method (append the list).
____ ____
____ ____
[CAUTION] [CAUTION]
The key and truststore passwords may also be set using the system properties: `org.eclipse.jetty.ssl.keypassword` `org.eclipse.jetty.ssl.password`. The keystore and truststore passwords may also be set using the system properties: `org.eclipse.jetty.ssl.keypassword` `org.eclipse.jetty.ssl.password`.
This is _not_ a recommended usage. This is _not_ a recommended usage.
____ ____
==== Configuring SSL in Jetty Distribution
For those of you using the Jetty Distribution, the provided modules for https and http2 will automatically setup the `SslContextFactory`, the appropriate `SslConnectionFactory`, and associated `ServerConnectors` for you in the correct order.
An example of this setup:
[source, plain, subs="{sub-order}"]
----
$ cd /path/to/mybase
$ java -jar /path/to/jetty-dist/start.jar --add-to-start=https
INFO: ssl initialised (transitively) in ${jetty.base}/start.ini
INFO: https initialised in ${jetty.base}/start.ini
INFO: Base directory was modified
$ ls -l
drwxrwxr-x. 2 user group 4096 Feb 2 11:47 etc/
-rw-rw-r--. 1 user group 4259 Feb 2 11:47 start.ini
$ ls -l etc
-rw-rw-r--. 1 user group 3697 Feb 2 11:47 keystore
----
When you check the `start.ini`, you'll see many commented properties ready for you to configure the `SslContextFactory` basics.
To highlight some of the more commonly used properties:
jetty.ssl.host::
Configures which interfaces the SSL/TLS Connector should listen on.
jetty.ssl.port::
Configures which port the SSL/TLS Connector should listen on.
jetty.httpConfig.securePort::
If a webapp needs to redirect to a secure version of the same resource, then this is the port reported back on the response `location` line (having this be separate is useful if you have something sitting in front of Jetty, such as a Load Balancer or proxy).
jetty.sslContext.keyStorePath::
Sets the location of the `keystore` that you configured with your certificates.
jetty.sslContext.keyStorePassword::
Sets the Password for the `keystore`.
==== Configuring SNI ==== Configuring SNI
From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows a SSL connection handshake to indicate one or more DNS names that it applies to. From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows a SSL connection handshake to indicate one or more DNS names that it applies to.

View File

@ -81,8 +81,8 @@ For more information on the alternatives see the section on link:#startup-module
____ ____
. Edit the configuration for the `setuid` module to substitute the `userid` and `groupid` of the user to switch to after starting. . Edit the configuration for the `setuid` module to substitute the `userid` and `groupid` of the user to switch to after starting.
If you used the `--add-to-start` command, this configuration is in the `start.ini` file. If your server instance has a `${jetty.base/start.d}` directory, this configuration is in the `start.d/setuid.ini` file instead.
If you used the `--add-to-startd` command instead, this configuration is in the `start.d/setuid.ini` file instead. Otherwise. this configuration is in the `${jetty.base}start.ini` file.
Below are the lines to configure: Below are the lines to configure:
+ +

View File

@ -21,7 +21,7 @@ The auto discovery features of the Servlet specification can make deployments sl
Auto discovery of Web Application configuration can be useful during the development of a webapp as it allows new features and frameworks to be enabled simply by dropping in a jar file. Auto discovery of Web Application configuration can be useful during the development of a webapp as it allows new features and frameworks to be enabled simply by dropping in a jar file.
However, for deployment, the need to scan the contents of many jars can have a significant impact of the start time of a webapp. However, for deployment, the need to scan the contents of many jars can have a significant impact of the start time of a webapp.
From Jetty release 9.2.0.v20140526, the included quickstart module allows a webapp to be pre-scanned and preconfigured. With the release of Jetty 9.2, a quickstart module was included which allows a webapp to be pre-scanned and preconfigured.
This means that all the scanning is done prior to deployment and all configuration is encoded into an effective `web.xml`, called `WEB-INF/quickstart-web.xml`, which can be inspected to understand what will be deployed before deploying. This means that all the scanning is done prior to deployment and all configuration is encoded into an effective `web.xml`, called `WEB-INF/quickstart-web.xml`, which can be inspected to understand what will be deployed before deploying.
Not only does the `quickstart-web.xml` contain all the discovered Servlets, Filters and Constraints, but it also encodes as context parameters all discovered: Not only does the `quickstart-web.xml` contain all the discovered Servlets, Filters and Constraints, but it also encodes as context parameters all discovered:
@ -31,33 +31,91 @@ Not only does the `quickstart-web.xml` contain all the discovered Servlets, Filt
With the quickstart mechanism, Jetty is able to entirely bypass all scanning and discovery modes and start a webapp in a predictable and fast way. With the quickstart mechanism, Jetty is able to entirely bypass all scanning and discovery modes and start a webapp in a predictable and fast way.
Tests have shown that webapps that took many seconds to scan and deploy can now be deployed in a few hundred milliseconds. Tests have shown that webapps that took many seconds to scan and deploy can now be deployed in a few hundred milliseconds.
Additionally, if debug logging is enabled, the generated quickstart information is tagged with the origin of every element, which can be useful for debugging purposes.
==== Setting up Quickstart ==== Setting up Quickstart
To use quickstart the module has to be available to the Jetty instance. ===== Prerequisites
In a maven project this is done by adding a dependency on the artifact ID `jetty-quickstart`.
In a standard Jetty distribution it can be configured with the following command: ====== Jetty Distribution
In a standard Jetty distribution the quickstart module can be configured with the following command:
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
$ java -jar $JETTY_HOME/start.jar --add-to-startd=quickstart $ java -jar $JETTY_HOME/start.jar --add-to-start=quickstart
---- ----
Deployed webapps need to be instances of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`. ====== Embedded
If a web application already has a `webapps/myapp.xml` file, simply change the class in the Configure element.
Otherwise, create a `webapps/myapp.xml` file as follows: In a Maven project you add a dependency on the artifact `jetty-quickstart`.
[source, xml, subs="{sub-order}"]
----
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-quickstart</artifactId>
<version>{VERSION}</version>
</dependency>
----
===== Configuration
Webapps need to be instances of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`.
`org.eclipse.jetty.quickstart.QuickStartWebApp` instances offer the same setters as the familiar `org.eclipse.jetty.webapp.WebAppContext`, with the addition of:
autoPreconfigure::
(true/false).
If true, the first time the webapp is run, the WEB-INF/quickstart-web.xml is generated BEFORE the webapp is deployed.
Subsequent runs use the previously generated quickstart file.
====== In XML
If a web application already has a context xml file, eg `webapps/myapp.xml` file, simply change the class in the `Configure` element.
Otherwise, create a context xml file with the following information (in addition to the usual setting of contextPath, war etc):
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.quickstart.QuickStartWebApp"> <Configure class="org.eclipse.jetty.quickstart.QuickStartWebApp">
<Set name="war"><Property name="jetty.webapps" default="."/>/benchmark.war</Set>
<Set name="contextPath">/benchmark</Set>
<Set name="autoPreconfigure">true</Set> <Set name="autoPreconfigure">true</Set>
</Configure> </Configure>
---- ----
====== In Code
Create an instance of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`. You then use the QuickStartWebApp instance in exactly the same way that you would a WebAppContext.
Here's a snippet:
[source, java]
----
QuickStartWebApp webapp = new QuickStartWebApp();
webapp.setAutoPreconfigure(true);
----
====== Pre-generating the quickstart-web.xml file
Rather than use the `autoPreconfigure` feature of the QuickStartWebApp - which lazily generates the `quickstart-web.xml` file - you can eagerly pre-generate it for an existing war by invoking as a main class link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[`org.eclipse.jetty.quickstart.PreconfigureQuickStartWar`].
Note that you will need to provide all necessary jetty jars on the command line classpath.
This will unpack the war if necessary, and create the `quickstart-web.xml` before the first deployment:
[source, screen, subs="{sub-order}"]
----
$ java -cp [jetty classpath] org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war
----
Run the class with no arguments to see other runtime options.
Alternatively, you could use the link:#get-up-and-running[Jetty Maven Plugin] goal link:#jetty-effective-web-xml[`jetty:effective-web-xml`]: this will generate quickstart information, but print it to stderr.
The goal provides a configuration option to save the output to a file, which you can then copy into your webapp's WEB-INF dir.
Note that as the Jetty Maven Plugin is a general tool for running webapps, it may have more jars on its classpath than are needed by your application, and thus may generate extra quickstart information: we recommend that you use this goal only as a quick guide to the type of information that quickstart generates.
// ==== Preconfiguring the web application // ==== Preconfiguring the web application
// //
// If the `QuickStateWebApp` method `setAutoPreconfigure(true)` is called (see example in myapp.xml above), then the first time the webapp is deployed a `WEB-INF/quickstart-web.xml` file will be generated that contains the effective `web.xml` for all the discovered configuration. // If the `QuickStateWebApp` method `setAutoPreconfigure(true)` is called (see example in myapp.xml above), then the first time the webapp is deployed a `WEB-INF/quickstart-web.xml` file will be generated that contains the effective `web.xml` for all the discovered configuration.
@ -65,14 +123,8 @@ Otherwise, create a `webapps/myapp.xml` file as follows:
// //
// It is also possible to preconfigure a war file manually by running the class link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[org.eclipse.jetty.quickstart.PreconfigureQuickStartWar] with the jetty-all-uber (aggregate) jar: // It is also possible to preconfigure a war file manually by running the class link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[org.eclipse.jetty.quickstart.PreconfigureQuickStartWar] with the jetty-all-uber (aggregate) jar:
// //
// [source, screen, subs="{sub-order}"]
// ----
// $ java -cp jetty-all-{VERSION}-uber.jar org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war
// ----
// //
// This will create the `quickstart-web.xml` file before the first deployment. // This will create the `quickstart-web.xml` file before the first deployment.
// Note that this can also be a good debugging tool for discovered configuration and if run with debug turned on the origin of every element is included in the `quickstart-web.xml` file.
// Run the class with no arguments to see other runtime options.
==== Avoiding TLD Scans with precompiled JSPs ==== Avoiding TLD Scans with precompiled JSPs

View File

@ -148,10 +148,10 @@ There are 2 aspects to this:
To accomplish the above, use the Jetty link:#startup-overview[startup] link:#startup-modules[modules mechanism] to add the JAAS link:#startup-modules[module]: To accomplish the above, use the Jetty link:#startup-overview[startup] link:#startup-modules[modules mechanism] to add the JAAS link:#startup-modules[module]:
[source,bash] [source, screen, subs="{sub-order}"]
---- ....
java -jar start.jar --add-to-startd=jaas java -jar start.jar --add-to-start=jaas
---- ....
____ ____
[NOTE] [NOTE]

View File

@ -28,7 +28,7 @@ For example:
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
.... ....
$ java -jar start.jar --add-to-startd=spring $ java -jar start.jar --add-to-start=spring
.... ....
This (or the alternative link:#start-jar[--add-to-start]=spring command) creates a `${jetty.home}/lib/spring` directory and populates it with the jetty-spring integration jar. This (or the alternative link:#start-jar[--add-to-start]=spring command) creates a `${jetty.home}/lib/spring` directory and populates it with the jetty-spring integration jar.

View File

@ -723,6 +723,7 @@ mvn jetty:stop
The `stopPort` must be free on the machine you are running on. The `stopPort` must be free on the machine you are running on.
If this is not the case, you will get an "Address already in use" error message after the "Started ServerConnector ..." message. If this is not the case, you will get an "Address already in use" error message after the "Started ServerConnector ..." message.
[[jetty-effective-web-xml]]
==== jetty:effective-web-xml ==== jetty:effective-web-xml
This goal calculates a synthetic `web.xml` (the "effective web.xml") according to the rules of the Servlet Specification taking into account all sources of discoverable configuration of web components in your application: descriptors (`webdefault.xml`, `web.xml`, `web-fragment.xml`s, `web-override.xml`) and discovered annotations (`@WebServlet`, `@WebFilter`, `@WebListener`). This goal calculates a synthetic `web.xml` (the "effective web.xml") according to the rules of the Servlet Specification taking into account all sources of discoverable configuration of web components in your application: descriptors (`webdefault.xml`, `web.xml`, `web-fragment.xml`s, `web-override.xml`) and discovered annotations (`@WebServlet`, `@WebFilter`, `@WebListener`).

View File

@ -127,7 +127,9 @@ WARNING: Nothing to start, exiting ...
Usage: java -jar start.jar [options] [properties] [configs] Usage: java -jar start.jar [options] [properties] [configs]
java -jar start.jar --help # for more information java -jar start.jar --help # for more information
> java -jar $JETTY_HOME/start.jar --add-to-startd=http,deploy > java -jar $JETTY_HOME/start.jar --create-startd
INFO : Base directory was modified
> java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy
INFO: server initialised (transitively) in ${jetty.base}/start.d/server.ini INFO: server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO: http initialised in ${jetty.base}/start.d/http.ini INFO: http initialised in ${jetty.base}/start.d/http.ini
@ -186,7 +188,7 @@ To add HTTPS and HTTP2 connectors to a Jetty configuration, the modules can be a
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
> java -jar $JETTY_HOME/start.jar --add-to-startd=https,http2 > java -jar $JETTY_HOME/start.jar --add-to-start=https,http2
[...] [...]
> java -jar $JETTY_HOME/start.jar > java -jar $JETTY_HOME/start.jar
@ -196,7 +198,7 @@ To add HTTPS and HTTP2 connectors to a Jetty configuration, the modules can be a
[...] [...]
---- ----
The `--add-to-startd` command sets up the effective command line in the ini files to run an ssl connection that supports the HTTPS and HTTP2 protocols as follows: The `--add-to-start` command sets up the effective command line in the ini files to run an ssl connection that supports the HTTPS and HTTP2 protocols as follows:
* creates `start.d/ssl.ini` that configures an SSL connector (eg port, keystore etc.) by adding `etc/jetty-ssl.xml` and `etc/jetty-ssl-context.xml` to the effective command line. * creates `start.d/ssl.ini` that configures an SSL connector (eg port, keystore etc.) by adding `etc/jetty-ssl.xml` and `etc/jetty-ssl-context.xml` to the effective command line.
* creates `start.d/alpn.ini` that configures protocol negotiation on the SSL connector by adding `etc/jetty-alpn.xml` to the effective command line. * creates `start.d/alpn.ini` that configures protocol negotiation on the SSL connector by adding `etc/jetty-alpn.xml` to the effective command line.
@ -204,11 +206,6 @@ The `--add-to-startd` command sets up the effective command line in the ini file
* creates `start.d/http2.ini` that configures the HTTP/2 protocol on the SSL connector by adding `etc/jetty-http2.xml` to the effective command line. * creates `start.d/http2.ini` that configures the HTTP/2 protocol on the SSL connector by adding `etc/jetty-http2.xml` to the effective command line.
* checks for the existence of a `etc/keystore` file and if not present, downloads a demonstration keystore file. * checks for the existence of a `etc/keystore` file and if not present, downloads a demonstration keystore file.
____
[NOTE]
If a single `start.ini` file is preferred over individual `start.d/*.ini` files, then the option --add-to-start=module may be used to append the module activation to the start.ini file rather than create a file in start.d
____
[[quickstart-changing-https-port]] [[quickstart-changing-https-port]]
===== Changing the Jetty HTTPS Port ===== Changing the Jetty HTTPS Port
@ -220,9 +217,8 @@ You can configure the SSL connector to run on a different port by setting the `j
> java -jar $JETTY_HOME/start.jar jetty.ssl.port=8444 > java -jar $JETTY_HOME/start.jar jetty.ssl.port=8444
---- ----
Alternatively, property values can be added to the effective command line built from the `start.ini` file and `start.d/*.ini` files. Alternatively, property values can be added to the effective command line built from the `start.ini` file or `start.d/*.ini` files, depending on your set up.
If you used the `--add-to-startd` command to enable HTTPS , then you can edit this property in the `start.d/https.ini` file. Please see the section on link:#start-vs-startd[Start.ini vs. Start.d] for more information.
If you used `--add-to-start` command, then you can edit this property in the `start.ini` file.
==== More start.jar options ==== More start.jar options

View File

@ -27,7 +27,8 @@ While many people continue to use older versions of Jetty, we generally recommen
|Version |Year |Home |JVM |Protocols |Servlet |JSP |Status |Version |Year |Home |JVM |Protocols |Servlet |JSP |Status
|9.3 |2015 |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable |9.3 |2015 |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable
|9.2 |2014 |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Stable |9.2 |2014 |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Stable
|8 |2009- |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable |8.2 |2009- |Eclipse/Codehaus |1.7 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable
|8.1 |2009- |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable
|7 |2008- |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Venerable |7 |2008- |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Venerable
|6 |2006-2010 |Codehaus |1.4-1.5 |HTTP/1.1 RFC2616 |2.5 |2.0 |Deprecated |6 |2006-2010 |Codehaus |1.4-1.5 |HTTP/1.1 RFC2616 |2.5 |2.0 |Deprecated
|5 |2003-2009 |Sourceforge |1.2-1.5 |HTTP/1.1 RFC2616 |2.4 |2.0 |Deprecated |5 |2003-2009 |Sourceforge |1.2-1.5 |HTTP/1.1 RFC2616 |2.4 |2.0 |Deprecated

View File

@ -30,15 +30,12 @@ For a more in-depth look at the syntax, see xref:jetty-xml-syntax[].
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Configure class="org.eclipse.jetty.webapp.WebAppContext">
.. ..
</Configure> </Configure>
---- ----
____ ____

View File

@ -80,41 +80,27 @@ bar.getParent().setName("demo2");
===== Understanding DTD and Parsing ===== Understanding DTD and Parsing
The document type descriptor The document type descriptor
(link:{GITBROWSEURL}/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd?h=release-9[configure.dtd]) (link:{GITBROWSEURL}/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd?h=release-9[configure.dtd]) describes all valid elements in a Jetty XML configuration file using the Jetty IoC format.
describes all valid elements in a Jetty XML configuration file using the The first two lines of an XML must reference the DTD to be used to validate the XML like:
Jetty IoC format. The first two lines of an XML must reference the DTD
to be used to validate the XML like:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
... ...
---- ----
Typcically a good XML editor will fetch the DTD from the URL and use it Typcically a good XML editor will fetch the DTD from the URL and use it to give syntax highlighting and validation while a configuration file is being edited.
to give syntax highlighting and validation while a configuration file is Some editors also allows DTD files to be locally cached.
being edited. Some editors also allows DTD files to be locally cached. The URL may point to configure.dtd if you want the latest current version, or to a specific version like configure_9_0.dtd if you want a particular validation feature set.
The URL may point to configure.dtd if you want the latest current
version, or to a specific version like configure_9_0.dtd if you want a
particular validation feature set.
Files that conform to the configure.dtd format are processed in Jetty by Files that conform to the configure.dtd format are processed in Jetty by the `XmlConfiguration` class which may also validate the XML (using a version of the DTD from the classes jar file), but is by default run in a forgiving mode that tries to work around validation failures.
the `XmlConfiguration` class which may also validate the XML (using a
version of the DTD from the classes jar file), but is by default run in
a forgiving mode that tries to work around validation failures.
===== Jetty XML Configuration Scope ===== Jetty XML Configuration Scope
The configuration of object instances with Jetty IoC XML is done on a The configuration of object instances with Jetty IoC XML is done on a scoped basis, so that for any given XML element there is a corresponding Object in scope and the nested XML elements apply to that.
scoped basis, so that for any given XML element there is a corresponding The outer most scope is given by a Configure element and elements like Call, New and Get establish new scopes.
Object in scope and the nested XML elements apply to that. The outer The following example uses the name fields to explain the scope.
most scope is given by a Configure element and elements like Call, New
and Get establish new scopes. The following example uses the name fields
to explain the scope
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -134,50 +120,36 @@ to explain the scope
<Call name="methodOnObjectReturnedByMethodOnFooWithNoArgs"/> <Call name="methodOnObjectReturnedByMethodOnFooWithNoArgs"/>
</Call> </Call>
</Configure> </Configure>
---- ----
===== Coercing Arguments to a Type ===== Coercing Arguments to a Type
When trying to match XML elements to java elements, Jetty When trying to match XML elements to java elements, Jetty `XmlConfiguration` may need to coerces values to match method arguments.
XmlConfiguration may need to coerces values to match method arguments. By default it does so on a best effort basis, but you can also specify explicit types with the `type` attribute.
By default it does so on a best effort basis, but you can also specify Supported values for type are: `String`, `Character`, `Short`, `Byte`, `Integer`, `Long`, `Boolean`, `Float`, `Double`, `char`, `short`, `byte`, `int`, `long`, `boolean`, `float`, `double`, `URL`, `InetAddress`, `InetAddrPort`, and `void`.
explicit types with the `type` attribute. Supported values for type are:
String, Character, Short, Byte, Integer, Long, Boolean, Float, Double,
char, short, byte, int, long, boolean, float, double, URL, InetAddress,
InetAddrPort, void
===== Referring to a Class ===== Referring to a Class
If you do not specify the classname, Jetty assumes you are calling the If you do not specify the classname, Jetty assumes you are calling the method on the object that is current in scope (eg the object of the surrounding `Configure`, `New` or `Get` clause).
method on the object that is current in scope (eg the object of the If the class attribute is specified to a fully-qualified class name, then it is either used to create a new instance (`Configure` and `New` elements) or is used to access a static (`Call`, `Set` or `Get` elements).
surrounding Configure, New or Get clause). If the class attribute is
specified to a fully-qualified class name, then it is either used to
create a new instance (Configure and New elements) or is used to access
a static (Call, Set or Get elements).
===== Referring to an Object ===== Referring to an Object
You can use the id attribute to store a reference to the current object You can use the id attribute to store a reference to the current object when first creating or referring to this object.
when first creating or referring to this object. You can then use the You can then use the link:#jetty-xml-ref[Ref element] to reference the object later.
link:#jetty-xml-ref[Ref element] to reference the object later. The id The ID must be unique for each object you create.
must be unique for each object you create.
===== Attribute vs Element Style ===== Attribute vs Element Style
For XML elements that contain only other XML Elements, there is a choice For XML elements that contain only other XML Elements, there is a choice of using attributes or elements style.
of using attributes or elements style. The following is an example of The following is an example of attribute style:
attribute style:
.... ....
<Call id="result" class="org.example.SomeClass" name="someMethod" arg="value0,value1"/> <Call id="result" class="org.example.SomeClass" name="someMethod" arg="value0,value1"/>
.... ....
Attribute style has the benefit of brevity, but is limited by: values Attribute style has the benefit of brevity, but is limited by: values can only be Strings; multivalued items can not contain ','; values may not be subject to property expansion or other elements that return values.
can only be Strings; multivalued items can not contain ','; values may Thus, the more verbose element style is available and the following is semantically equivalent to the attribute style above:
not be subject to property expansion or other elements that return
values. Thus the more verbose element style is available and the
following is semantically equivalent to the attribute style above:
.... ....
<Call> <Call>
@ -189,11 +161,8 @@ following is semantically equivalent to the attribute style above:
</Call> </Call>
.... ....
Note that multivalued elements like Arg, must be repeated and may not be Note that multivalued elements like `Arg` must be repeated and may not be comma-separated like they are when provided as attributes.
comma separated like they are when provided as attributes. It is It is possible to use a mix of styles and the following example shows a moretypical example that uses property expansion as the reason for element style:
possible to use a mix of styles and the following example shows a more
typical example that uses property expansion as the reason for element
style:
.... ....
<Call id="result" name="someMethod"> <Call id="result" name="someMethod">
@ -205,16 +174,14 @@ style:
</Call> </Call>
.... ....
Attributes may not be expressed as elements when their parent element is Attributes may not be expressed as elements when their parent element is one that contains data.
one that contains data. Thus Arg, Item, Set, Put and Get elements may Thus `Arg`, `Item`, `Set`, `Put` and `Get` elements may not have their attributes expressed as elements.
not have their attributes expressed as elements.
[[jetty-xml-configure]] [[jetty-xml-configure]]
==== <Configure> ==== <Configure>
This is the root element that specifies the class of object that is to This is the root element that specifies the class of object that is to be configured.
be configured. It is usually either the Server, in `jetty.xml`, or a It is usually either the Server, in `jetty.xml`, or a `WebAppContext` in `jetty-web.xml`.
WebAppContext in `jetty-web.xml`.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -226,8 +193,8 @@ You can use this to break up configuration of an object (such as the
Server) across multiple files. Server) across multiple files.
|class |no |The fully qualified classname of the object to be |class |no |The fully qualified classname of the object to be
configured. Could be org.eclipse.jetty.server.Server, configured. Could be `org.eclipse.jetty.server.Server`,
org.eclipse.jetty.webapp.WebAppContext, a handler, etc. `org.eclipse.jetty.webapp.WebAppContext`, a handler, etc.
|======================================================================= |=======================================================================
===== Can Contain ===== Can Contain
@ -257,10 +224,9 @@ org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server();
server.setPort(8080); server.setPort(8080);
---- ----
====== Using id to break up configuration of one object across multiple ====== Using id to break up configuration of one object across multiple files
files
(etc/jetty.xml) In `etc/jetty.xml`:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -269,7 +235,7 @@ files
</Configure> </Configure>
---- ----
(etc/jetty-logging.xml) In `etc/jetty-logging.xml`:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -287,13 +253,11 @@ java -jar start.jar etc/jetty.xml jetty-logging.xml
[[jetty-xml-set]] [[jetty-xml-set]]
==== <Set> ==== <Set>
A Set element maps to a call to a setter method or field on the current A Set element maps to a call to a setter method or field on the current object.
object. It can contain text and/or elements such as Call, New, It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc., as values.
SystemProperty, etc., as values. The name and optional type attributes The name and optional type attributes are used to select the setter method.
are used to select the setter method. If you do not specify a value If you do not specify a value type, white space is trimmed out of the value.
type, white space is trimmed out of the value. If it contains multiple If it contains multiple elements as values, they are added as strings before being converted to any specified type.
elements as values, they are added as strings before being converted to
any specified type.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -370,15 +334,14 @@ server.setThreadPool(threadPool);
---- ----
<Configure id="server" class="org.eclipse.jetty.server.Server"> <Configure id="server" class="org.eclipse.jetty.server.Server">
<Set class="org.eclipse.jetty.util.log.Log" name="logToParent">loggerName</Set> <Set class="org.eclipse.jetty.util.log.Log" name="logToParent">loggerName</Set>
</Configure"> </Configure>
---- ----
[[jetty-xml-get]] [[jetty-xml-get]]
==== <Get> ==== <Get>
A Get element maps to a call to a getter method or field on the current A Get element maps to a call to a getter method or field on the current object.
object. It can contain nested elements such as Set, Put, Call, etc.; It can contain nested elements such as `Set`, `Put`, `Call`, etc.; these act on the object returned by the `Get` call.
these act on the object returned by the Get call.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -406,8 +369,8 @@ link:#jetty-xml-property[Property element]
====== Basic Example ====== Basic Example
This simple example doesn't do much on its own. You would normally use This simple example doesn't do much on its own.
this in conjunction with a <Ref id="Logger" />. You would normally use this in conjunction with a `<Ref id="Logger" />`.
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -432,12 +395,10 @@ this in conjunction with a <Ref id="Logger" />.
[[jetty-xml-put]] [[jetty-xml-put]]
==== <Put> ==== <Put>
A Put element maps to a call to a put method on the current object, A Put element maps to a call to a put method on the current object, which must implement the Map interface.
which must implement the Map interface. It can contain text and/or It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc. as values.
elements such as Call, New, SystemProperty, etc. as values. If you do If you do not specify a no value type, white space is trimmed out of the value.
not specify a no value type, white space is trimmed out of the value. If If it contains multiple elements as values, they are added as strings before being converted to any specified type.
it contains multiple elements as values, they are added as strings
before being converted to any specified type.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -450,7 +411,7 @@ Arg for how to define null and empty string values.
===== Can Contain ===== Can Contain
value text , link:#jetty-xml-get[Get element], link:#jetty-xml-call[Call value text, link:#jetty-xml-get[Get element], link:#jetty-xml-call[Call
element], link:#jetty-xml-new[New element], link:#jetty-xml-ref[Ref element], link:#jetty-xml-new[New element], link:#jetty-xml-ref[Ref
element], link:#jetty-xml-array[Array element], link:#jetty-xml-map[Map element], link:#jetty-xml-array[Array element], link:#jetty-xml-map[Map
element], link:#jetty-xml-system-property[System Property element], element], link:#jetty-xml-system-property[System Property element],
@ -468,11 +429,9 @@ link:#jetty-xml-property[Property element]
[[jetty-xml-call]] [[jetty-xml-call]]
==== <Call> ==== <Call>
A Call element maps to an arbitrary call to a method on the current A `Call` element maps to an arbitrary call to a method on the current object.
object. It can contain a sequence of Arg elements followed by a sequence It can contain a sequence of Arg elements followed by a sequence of configuration elements, such as Set, Put, Call.
of configuration elements, such as Set, Put, Call. The <Arg>s are passed The <Arg>s are passed as arguments to the method; the sequence of configuration elements act on the object returned by the original call.
as arguments to the method; the sequence of configuration elements act
on the object returned by the original call.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -527,7 +486,7 @@ o2.setTest("1, 2, 3");
</Call> </Call>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -548,7 +507,7 @@ com.acme.Foo.setString("somestring");
</Configure> </Configure>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -562,13 +521,11 @@ com.acme.Environment.setPort( server.getPort() );
An Arg element can be an argument of either a method or a constructor. An Arg element can be an argument of either a method or a constructor.
Use it within xref:jetty-syntax-call[] and xref:jetty-syntax-new[]. Use it within xref:jetty-syntax-call[] and xref:jetty-syntax-new[].
It can contain text and/or elements, such as Call, New, SystemProperty, It can contain text and/or elements, such as `Call`, `New`, `SystemProperty`, etc., as values.
etc., as values. The optional type attribute can force the type of the The optional type attribute can force the type of the value.
value. If you don't specify a type, white space is trimmed out of the If you don't specify a type, white space is trimmed out of the value.
value. If it contains multiple elements as values, they are added as If it contains multiple elements as values, they are added as strings before being converted to any specified type.
strings before being converted to any specified type. Simple String Simple `String` arguments can also be specified as a string separated arg attribute on the parent element.
arguments can also be specified as a string separated arg attribute on
the parent element.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -597,7 +554,7 @@ link:#jetty-xml-property[Property element]
<Arg>1</Arg> <!-- int, long, short, float, double --> <Arg>1</Arg> <!-- int, long, short, float, double -->
<Arg><Ref refid="foo" /></Arg> <!-- any object; reference a previously created object with id "foo", and pass it as a parameter --> <Arg><Ref refid="foo" /></Arg> <!-- any object; reference a previously created object with id "foo", and pass it as a parameter -->
<Arg></Arg> <!-- null value --> <Arg></Arg> <!-- null value -->
<Arg type="String"></Arg> <!-- empty string "" -> <Arg type="String"></Arg> <!-- empty string "" -->
---- ----
====== Coercing Type ====== Coercing Type
@ -611,8 +568,7 @@ This explicitly coerces the type to a boolean:
====== As a Parameter ====== As a Parameter
Here are a couple of examples of link:#jetty-xml-arg[Arg element] being Here are a couple of examples of link:#jetty-xml-arg[Arg element] being used as a parameter to methods and to constructors:
used as a parameter to methods and to constructors:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -653,13 +609,11 @@ new com.acme.Baz(com.acme.MyStaticObjectFactory.createObject(2));
[[jetty-xml-new]] [[jetty-xml-new]]
==== <New> ==== <New>
Instantiates an object. Equivalent to new in Java, and allows the Instantiates an object.
creation of a new object. A New element can contain a sequence of Equivalent to `new` in Java, and allows the creation of a new object.
link:#jetty-xml-arg[Arg element]'s, followed by a sequence of A `New` element can contain a sequence of link:#jetty-xml-arg[`Arg` element]'s, followed by a sequence of configuration elements (`Set`, `Put`, etc).
configuration elements (Set, Put, etc). link:#jetty-xml-arg[Arg link:#jetty-xml-arg[`Arg` element]'s are used to select a constructor for the object to be created.
element]'s are used to select a constructor for the object to be The sequence of configuration elements then acts on the newly-created object.
created. The sequence of configuration elements then acts on the
newly-created object.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -694,7 +648,7 @@ element], link:#jetty-xml-property[Property element]
</New> </New>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -708,7 +662,7 @@ com.acme.Foo foo = new com.acme.Foo("bar");
<New class="com.acme.Foo" /> <New class="com.acme.Foo" />
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -726,7 +680,7 @@ com.acme.Foo foo = new com.acme.Foo();
</New> </New>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -737,17 +691,14 @@ foo.setTest("1, 2, 3");
[[jetty-xml-ref]] [[jetty-xml-ref]]
==== <Ref> ==== <Ref>
A Ref element allows a previously created object to be referenced by a A `Ref` element allows a previously created object to be referenced by a unique id.
unique id. It can contain a sequence of elements, such as Set or Put It can contain a sequence of elements, such as `Set` or `Put` which then act on the referenced object.
which then act on the referenced object. You can also use a Ref element You can also use a `Ref` element as a value for other elements such as `Set` and `Arg`.
as a value for other elements such as Set and Arg.
The Ref element provides convenience and eases readability. You can The `Ref` element provides convenience and eases readability.
usually achieve the effect of the Ref by nesting elements (method You can usually achieve the effect of the `Ref` by nesting elements (method calls), but this can get complicated very easily.
calls), but this can get complicated very easily. The Ref element makes The Ref element makes it possible to refer to the same object if you're using it multiple times, or passing it into multiple methods.
it possible to refer to the same object if you're using it multiple It also makes it possible to split up configuration across multiple files.
times, or passing it into multiple methods. It also makes it possible to
split up configuration across multiple files.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -768,8 +719,7 @@ link:#jetty-xml-property[Property element]
====== Basic example ====== Basic example
Use the referenced object as an argument to a method call or Use the referenced object as an argument to a method call or constructor:
constructor:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -805,8 +755,8 @@ foo.setTest("1, 2, 3");
====== Ref vs. Nested Elements ====== Ref vs. Nested Elements
Here is an example of the difference in syntax between using the Ref Here is an example of the difference in syntax between using the `Ref` element, and nesting method calls.
element, and nesting method calls. They are exactly equivalent: They are exactly equivalent:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -825,8 +775,7 @@ element, and nesting method calls. They are exactly equivalent:
</Configure> </Configure>
---- ----
Here is a more practical example, taken from the handler configuration Here is a more practical example, taken from the handler configuration section in `etc/jetty.xml`:
section in ` etc/jetty.xml`:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -868,7 +817,7 @@ section in ` etc/jetty.xml`:
[[jetty-xml-array]] [[jetty-xml-array]]
==== <Array> ==== <Array>
An Array element allows the creation of a new array. An `Array` element allows the creation of a new array.
[cols=",,",options="header",] [cols=",,",options="header",]
|================================================================== |==================================================================
@ -901,7 +850,7 @@ String[] a = new String[] { "value0", new String("value1") };
[[jetty-xml-item]] [[jetty-xml-item]]
==== <Item> ==== <Item>
An Item element defines an entry for Array and Map elements. An `Item` element defines an entry for Array and Map elements.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -921,8 +870,7 @@ link:#jetty-xml-property[Property element]
[[jetty-xml-map]] [[jetty-xml-map]]
==== <Map> ==== <Map>
A Map element allows the creation of a new HashMap and to populate it A `Map` element allows the creation of a new HashMap and to populate it with `(key, value)` pairs.
with (key, value) pairs.
[cols=",,",options="header",] [cols=",,",options="header",]
|================================================================ |================================================================
@ -957,8 +905,7 @@ m.put("keyName", new String("value1"));
[[jetty-xml-entry]] [[jetty-xml-entry]]
==== <Entry> ==== <Entry>
An Entry element contains a key-value link:#jetty-xml-item[Item element] An `Entry` element contains a key-value link:#jetty-xml-item[Item element] pair for a `Map`.
pair for a Map.
===== Can Contain ===== Can Contain
@ -967,8 +914,8 @@ link:#jetty-xml-item[Item element]
[[jetty-xml-system-property]] [[jetty-xml-system-property]]
==== <SystemProperty> ==== <SystemProperty>
A SystemProperty element gets the value of a JVM system property. It can A `SystemProperty` element gets the value of a JVM system property.
be used within elements that accept values, such as Set, Put, Arg. It can be used within elements that accept values, such as `Set`, `Put`, `Arg`.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -983,7 +930,7 @@ later.
===== Can Contain ===== Can Contain
Only attributes as Elements (Id, Name, Default). Only attributes as Elements (`Id`, `Name`, `Default`).
===== Example ===== Example
@ -999,15 +946,14 @@ That is equivalent to:
System.getProperty("jetty.http.port", "8080"); System.getProperty("jetty.http.port", "8080");
---- ----
Both try to retrieve the value of jetty.http.port. If jetty.http.port is Both try to retrieve the value of `jetty.http.port`.
not set, then 8080 is used. If `jetty.http.port` is not set, then 8080 is used.
[[jetty-xml-property]] [[jetty-xml-property]]
==== <Property> ==== <Property>
A Property element allows arbitrary properties to be retrieved by name. A `Property` element allows arbitrary properties to be retrieved by name.
It can contain a sequence of elements, such as Set, Put, Call that act It can contain a sequence of elements, such as `Set`, `Put`, `Call` that act on the retrieved object.
on the retrieved object.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -1020,17 +966,13 @@ on the retrieved object.
later. later.
|======================================================================= |=======================================================================
The `name` attribute may be a comma separated list of property names, The `Name` attribute may be a comma separated list of property names, with the first property name being the "official" name, and the others names being old, deprecated property names that are kept for backward compatibility.
with the first property name being the "official" name, and the others A warning log is issued when deprecated property names are used.
names being old, deprecated property names that are kept for backward The `Default` attribute contains the value to use in case none of the property names is found.
compatibility. A warning log is issued when deprecated property names
are used. The `default` attribute contains the value to use in case none
of the property names is found.
===== Can Contain ===== Can Contain
The attributes may be expressed as contained Elements (Id, Name, The attributes may be expressed as contained Elements (`Id`, `Name`, `Default`).
Default).
===== Example ===== Example

View File

@ -18,7 +18,7 @@
=== Jetty XML Usage === Jetty XML Usage
Jetty provides an XML-based configuration. Jetty provides an XML-based configuration.
It is grounded in Java's Reflection API. Classes in the java.lang.reflect represent Java methods and classes, such that you can instantiate objects and invoke their methods based on their names and argument types. It is grounded in Java's Reflection API. Classes in the `java.lang.reflect` represent Java methods and classes, such that you can instantiate objects and invoke their methods based on their names and argument types.
Behind the scenes, Jetty's XML config parser translates the XML elements and attributes into Reflection calls. Behind the scenes, Jetty's XML config parser translates the XML elements and attributes into Reflection calls.
[[using-jettyxml]] [[using-jettyxml]]
@ -48,7 +48,7 @@ If you use the same ID across multiple configuration files, those configurations
[[setting-parameters-in-configuration-files]] [[setting-parameters-in-configuration-files]]
==== Setting Parameters in Configuration Files ==== Setting Parameters in Configuration Files
You can set parameters in configuration files either with system properties (using ` <SystemProperty>`) or properties files (using `<Property>`) passed via the command line. You can set parameters in configuration files either with system properties (using `<SystemProperty>`) or properties files (using `<Property>`) passed via the command line.
For example, this code in `jetty.xml` allows the port to be defined on the command line, falling back onto `8080`if the port is not specified: For example, this code in `jetty.xml` allows the port to be defined on the command line, falling back onto `8080`if the port is not specified:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]

View File

@ -22,17 +22,18 @@ The challenge is to do so without changing the webapp itself. You can use a `jet
But there are some changes that `jetty.xml` cannot accomplish, for example, modifications to servlet init-params and context init-params. But there are some changes that `jetty.xml` cannot accomplish, for example, modifications to servlet init-params and context init-params.
Using `webdefault.xml` is not an option because Jetty applies `webdefault.xml` to a web application _before_ the application's own `WEB-INF/web.xml`, which means that it cannot override values inside the webapp's ` web.xml`. Using `webdefault.xml` is not an option because Jetty applies `webdefault.xml` to a web application _before_ the application's own `WEB-INF/web.xml`, which means that it cannot override values inside the webapp's ` web.xml`.
The solution is `override-web.xml`. It is a `web.xml` file that Jetty applies to a web application _after_ the application's own `WEB-INF/web.xml`, which means that it can override values or add new elements. The solution is `override-web.xml`.
You define it per-webapp, using the xref:jetty-xml-syntax[]. It is a `web.xml` file that Jetty applies to a web application _after_ the application's own `WEB-INF/web.xml`, which means that it can override values or add new elements.
This is defined on a per-webapp basis, using the xref:jetty-xml-syntax[].
[[using-override-web-xml]] [[using-override-web-xml]]
==== Using `override-web.xml` ==== Using override-web.xml
You can specify the `override-web.xml` to use for an individual web application, in that webapp's xref:jetty-web-xml-config[]. You can specify the `override-web.xml` to use for an individual web application in a deployable xml file located in Jetty webapps folder .
For example, if you had a webapp named MyApp, you would place a deployable xml file named `myapp.xml` in `${jetty.base}/webapps` which includes an `overrideDescriptor` entry for the `override-web.xml` file.
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Configure class="org.eclipse.jetty.webapp.WebAppContext">
... ...
<!-- Set up the path to the custom override descriptor, <!-- Set up the path to the custom override descriptor,
@ -40,15 +41,12 @@ You can specify the `override-web.xml` to use for an individual web application,
<Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/my/path/to/override-web.xml</Set> <Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/my/path/to/override-web.xml</Set>
... ...
</Configure> </Configure>
---- ----
The equivalent in code is: The equivalent in code is:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
... ...
@ -58,11 +56,9 @@ import org.eclipse.jetty.webapp.WebAppContext;
//Set the path to the override descriptor, based on your $(jetty.home) directory //Set the path to the override descriptor, based on your $(jetty.home) directory
wac.setOverrideDescriptor(System.getProperty("jetty.home")+"/my/path/to/override-web.xml"); wac.setOverrideDescriptor(System.getProperty("jetty.home")+"/my/path/to/override-web.xml");
... ...
---- ----
Alternatively, use the classloader (xref:jetty-classloading[]) to get the path to the override descriptor as a resource. Alternatively, you can use the classloader (xref:jetty-classloading[]) to get the path to the override descriptor as a resource.
[[override-using-jetty-maven-plugin]] [[override-using-jetty-maven-plugin]]
==== Using the Jetty Maven Plugin ==== Using the Jetty Maven Plugin
@ -71,7 +67,6 @@ Use the `<overrideDescriptor>` tag as follows:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<project> <project>
... ...
<plugins> <plugins>
@ -89,8 +84,6 @@ Use the `<overrideDescriptor>` tag as follows:
</plugins> </plugins>
... ...
</project> </project>
---- ----
[[override-web-xml-additional-resources]] [[override-web-xml-additional-resources]]

View File

@ -7,7 +7,7 @@
<baseDirectory>${project.version}</baseDirectory> <baseDirectory>${project.version}</baseDirectory>
<fileSets> <fileSets>
<fileSet> <fileSet>
<directory>${project.basedir}/target/docbkx/html/index</directory> <directory>${project.basedir}/target/docbkx/html</directory>
<outputDirectory></outputDirectory> <outputDirectory></outputDirectory>
<includes> <includes>
<include>**</include> <include>**</include>

View File

@ -19,10 +19,10 @@
package org.eclipse.jetty.fcgi.generator; package org.eclipse.jetty.fcgi.generator;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Queue; import java.util.Queue;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.ConcurrentArrayQueue;
import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.IteratingCallback;
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;
@ -31,7 +31,7 @@ public class Flusher
{ {
private static final Logger LOG = Log.getLogger(Flusher.class); private static final Logger LOG = Log.getLogger(Flusher.class);
private final Queue<Generator.Result> queue = new ConcurrentArrayQueue<>(); private final Queue<Generator.Result> queue = new ArrayDeque<>();
private final IteratingCallback flushCallback = new FlushCallback(); private final IteratingCallback flushCallback = new FlushCallback();
private final EndPoint endPoint; private final EndPoint endPoint;
@ -43,10 +43,26 @@ public class Flusher
public void flush(Generator.Result... results) public void flush(Generator.Result... results)
{ {
for (Generator.Result result : results) for (Generator.Result result : results)
queue.offer(result); offer(result);
flushCallback.iterate(); flushCallback.iterate();
} }
private void offer(Generator.Result result)
{
synchronized (this)
{
queue.offer(result);
}
}
private Generator.Result poll()
{
synchronized (this)
{
return queue.poll();
}
}
public void shutdown() public void shutdown()
{ {
flush(new ShutdownResult()); flush(new ShutdownResult());
@ -60,7 +76,7 @@ public class Flusher
protected Action process() throws Exception protected Action process() throws Exception
{ {
// Look if other writes are needed. // Look if other writes are needed.
Generator.Result result = queue.poll(); Generator.Result result = poll();
if (result == null) if (result == null)
{ {
// No more writes to do, return. // No more writes to do, return.
@ -71,7 +87,7 @@ public class Flusher
// Most often there is another result in the // Most often there is another result in the
// queue so this is a real optimization because // queue so this is a real optimization because
// it sends both results in just one TCP packet. // it sends both results in just one TCP packet.
Generator.Result other = queue.poll(); Generator.Result other = poll();
if (other != null) if (other != null)
result = result.join(other); result = result.join(other);
@ -106,7 +122,7 @@ public class Flusher
while (true) while (true)
{ {
Generator.Result result = queue.poll(); Generator.Result result = poll();
if (result == null) if (result == null)
break; break;
result.failed(x); result.failed(x);

View File

@ -18,7 +18,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.cloud</groupId> <groupId>com.google.cloud</groupId>
<artifactId>gcloud-java-datastore</artifactId> <artifactId>google-cloud-datastore</artifactId>
<version>${gcloud.version}</version> <version>${gcloud.version}</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -11,8 +11,49 @@
<Arg> <Arg>
<New id="sessionDataStoreFactory" class="org.eclipse.jetty.gcloud.session.GCloudSessionDataStoreFactory"> <New id="sessionDataStoreFactory" class="org.eclipse.jetty.gcloud.session.GCloudSessionDataStoreFactory">
<Set name="gracePeriodSec"><Property name="jetty.session.gracePeriod.seconds" default="3600" /></Set> <Set name="gracePeriodSec"><Property name="jetty.session.gracePeriod.seconds" default="3600" /></Set>
<Set name="maxRetries"><Property name="jetty.gcloudSession.maxRetries" default="5"/></Set> <Set name="maxRetries"><Property name="jetty.session.gcloud.maxRetries" default="5"/></Set>
<Set name="backoffMs"><Property name="jetty.gcloudSession.backoffMs" default="1000"/></Set> <Set name="backoffMs"><Property name="jetty.session.gcloud.backoffMs" default="1000"/></Set>
<Set name="namespace"><Property name="jetty.session.gcloud.namespace" default=""/></Set>
<Set name="entityDataModel">
<New class="org.eclipse.jetty.gcloud.session.GCloudSessionDataStore$EntityDataModel">
<Set name="kind">
<Property name="jetty.session.gcloud.model.kind" default="GCloudSession" />
</Set>
<Set name="id">
<Property name="jetty.session.gcloud.model.id" default="id" />
</Set>
<Set name="contextPath">
<Property name="jetty.session.gcloud.model.contextPath" default="contextPath" />
</Set>
<Set name="vhost">
<Property name="jetty.session.gcloud.model.vhost" default="vhost" />
</Set>
<Set name="accessed">
<Property name="jetty.session.gcloud.model.accessed" default="accessed" />
</Set>
<Set name="lastAccessed">
<Property name="jetty.session.gcloud.model.lastAccessed" default="lastAccessed" />
</Set>
<Set name="createTime">
<Property name="jetty.session.gcloud.model.createTime" default="createTime" />
</Set>
<Set name="cookieSetTime">
<Property name="jetty.session.gcloud.model.cookieSetTime" default="cookieSetTime" />
</Set>
<Set name="lastNode">
<Property name="jetty.session.gcloud.model.lastNode" default="lastNode" />
</Set>
<Set name="expiry">
<Property name="jetty.session.gcloud.model.expiry" default="expiry" />
</Set>
<Set name="maxInactive">
<Property name="jetty.session.gcloud.model.maxInactive" default="maxInactive" />
</Set>
<Set name="attributes">
<Property name="jetty.session.gcloud.model.attributes" default="attributes" />
</Set>
</New>
</Set>
</New> </New>
</Arg> </Arg>
</Call> </Call>

View File

@ -0,0 +1,72 @@
[description]
Enables GCloud Datastore API and implementation
[Tags]
3rdparty
gcloud
[depends]
gcloud
jcl-api
jcl-impl
[files]
maven://com.google.cloud/google-cloud-datastore/0.3.0|lib/gcloud/google-cloud-datastore-0.3.0.jar
maven://com.google.cloud/google-cloud-core/0.3.0|lib/gcloud/google-cloud-core-0.3.0.jar
maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar
maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar
maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar
maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar
maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar
maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar
maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar
maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar
maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar
maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar
maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar
maven://com.google.protobuf/protobuf-java/3.0.0-beta-3|lib/gcloud/protobuf-java-3.0.0-beta-3.jar
maven://com.google.api/gax/0.0.16|lib/gcloud/gax-0.0.16.jar
maven://io.grpc/grpc-all/0.15.0|lib/gcloud/grpc-all-0.15.0.jar
maven://io.grpc/grpc-auth/0.15.0|lib/gcloud/grpc-auth-0.15.0.jar
maven://io.grpc/grpc-netty/0.15.0|lib/gcloud/grpc-netty-0.15.0.jar
maven://io.netty/netty-codec-http2/4.1.1.Final|lib/gcloud/netty-codec-http2-4.1.1.jar
maven://io.netty/netty-codec-http/4.1.1.Final|lib/gcloud/netty-codec-http-4.1.1.Final.jar
maven://io.netty/netty-codec/4.1.1.Final|lib/gcloud/netty-codec-4.1.1.Final.jar
maven://io.netty/netty-handler/4.1.1.Final|lib/gcloud/netty-handler-4.1.1.Final.jar
maven://io.netty/netty-buffer/4.1.1.Final|lib/gcloud/netty-buffer-4.1.1.Final.jar
maven://io.netty/netty-common/4.1.1.Final|lib/gcloud/netty-common-4.1.1.Final.jar
maven://io.netty/netty-transport/4.1.1.Final|lib/gcloud/netty-transport-4.1.1.Final.jar
maven://io.netty/netty-resolver/4.1.1.Final|lib/gcloud/netty-resolver-4.1.1.Final.jar
maven://io.grpc/grpc-okhttp/0.15.0|lib/gcloud/grpc-okhttp-0.15.0.jar
maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar
maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar
maven://io.grpc/grpc-protobuf-nano/0.15.0|lib/gcloud/grpc-protobuf-nano-0.15.0.jar
maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano-3.0.0-alpha-5.jar
maven://io.grpc/grpc-stub/0.15.0|lib/gcloud/grpc-stub-0.15.0.jar
maven://io.grpc/grpc-protobuf/0.15.0|lib/gcloud/grpc-protobuf-0.15.0.jar
maven://com.google.protobuf/protobuf-java-util/3.0.0-beta-3|lib/gcloud/protobuf-java-util-3.0.0-beta-3.jar
maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar
maven://io.grpc/grpc-protobuf-lite/0.15.0|lib/gcloud/grpc-protobuf-lite-0.15.0.jar
maven://io.grpc/grpc-core/0.15.0|lib/gcloud/grpc-core-0.15.0.jar
maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar
maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar
maven://javax.inject/javax.inject/1|lib/gcloud/javax.inject-1.jar
maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar
maven://com.google.api.grpc/grpc-google-common-protos/0.0.7|lib/gcloud/grpc-google-common-protos-0.0.7.jar
maven://org.json/json/20151123|lib/gcloud/json-20151123.jar
maven://com.google.cloud.datastore/datastore-v1-protos/1.0.1|lib/gcloud/datastore-v1-protos-1.0.1-beta.jar
maven://com.google.cloud.datastore/datastore-v1-proto-client/1.1.0|lib/gcloud/datastore-v1-proto-client-1.1.0.jar
maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar
maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar
maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar

View File

@ -0,0 +1,18 @@
[description]
Control GCloud API classpath
[Tags]
3rdparty
gcloud
[lib]
lib/gcloud/*.jar
[license]
GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
https://github.com/GoogleCloudPlatform/gcloud-java
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
## Hide the gcloud libraries from deployed webapps
jetty.webapp.addServerClasses,=file:${jetty.base}/lib/gcloud/

View File

@ -1,67 +1,44 @@
[description] [description]
Enables GCloudDatastore session management. Enables GCloudDatastore session management.
[Tags]
session
gcloud
[provides] [provides]
session-store session-store
[depends] [depends]
gcloud-datastore
annotations annotations
webapp webapp
sessions sessions
jcl-api
jcl-impl
[files] [files]
basehome:etc/sessions/gcloud/index.yaml|etc/index.yaml basehome:modules/gcloud/index.yaml|etc/index.yaml
maven://com.google.cloud/gcloud-java-datastore/0.2.3|lib/gcloud/gcloud-java-datastore-0.2.3.jar
maven://com.google.cloud/gcloud-java-core/0.2.3|lib/gcloud/gcloud-java-core-0.2.3.jar
maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar
maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar
maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar
maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar
maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar
maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar
maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar
maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar
maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar
maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar
maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar
maven://org.json/json/20151123|lib/gcloud/json-20151123.jar
maven://com.google.cloud.datastore/datastore-v1beta3-protos/1.0.0-beta|lib/gcloud/datastore-v1beta3-protos-1.0.0-beta.jar
maven://com.google.protobuf/protobuf-java/3.0.0-beta-1|lib/gcloud/protobuf-java-3.0.0-beta-1.jar
maven://com.google.cloud.datastore/datastore-v1beta3-proto-client/1.0.0-beta.2|lib/gcloud/datastore-v1beta3-proto-client-1.0.0-beta.2.jar
maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar
maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar
maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar
[lib] [lib]
lib/jetty-gcloud-session-manager-${jetty.version}.jar lib/jetty-gcloud-session-manager-${jetty.version}.jar
lib/gcloud/*.jar
[xml] [xml]
etc/sessions/gcloud/session-store.xml etc/sessions/gcloud/session-store.xml
[license]
GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
https://github.com/GoogleCloudPlatform/gcloud-java
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template] [ini-template]
## GCloudDatastore Session config ## GCloudDatastore Session config
#jetty.gcloudSession.maxRetries=5 #jetty.session.gcloud.maxRetries=5
#jetty.gcloudSession.backoffMs=1000 #jetty.session.gcloud.backoffMs=1000
#jetty.session.gcloud.namespace=
#jetty.session.gcloud.model.kind=GCloudSession
#jetty.session.gcloud.model.id=id
#jetty.session.gcloud.model.contextPath=contextPath
#jetty.session.gcloud.model.vhost=vhost
#jetty.session.gcloud.model.accessed=accessed
#jetty.session.gcloud.model.lastAccessed=lastAccessed
#jetty.session.gcloud.model.createTime=createTime
#jetty.session.gcloud.model.cookieSetTime=cookieSetTime
#jetty.session.gcloud.model.lastNode=lastNode
#jetty.session.gcloud.model.expiry=expiry
#jetty.session.gcloud.model.maxInactive=maxInactive
#jetty.session.gcloud.model.attributes=attributes

View File

@ -59,6 +59,33 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
{ {
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
public static final int DEFAULT_MAX_QUERY_RESULTS = 100;
public static final int DEFAULT_MAX_RETRIES = 5;
public static final int DEFAULT_BACKOFF_MS = 1000;
protected Datastore _datastore;
protected KeyFactory _keyFactory;
protected int _maxResults = DEFAULT_MAX_QUERY_RESULTS;
protected int _maxRetries = DEFAULT_MAX_RETRIES;
protected int _backoff = DEFAULT_BACKOFF_MS;
protected boolean _dsProvided = false;
protected boolean _indexesPresent = false;
protected EntityDataModel _model;
private String _namespace;
/**
* EntityDataModel
*
* Names of type of Entity and Entity properties for sessions.
*/
public static class EntityDataModel
{
public static final String ID = "id"; public static final String ID = "id";
public static final String CONTEXTPATH = "contextPath"; public static final String CONTEXTPATH = "contextPath";
public static final String VHOST = "vhost"; public static final String VHOST = "vhost";
@ -72,18 +99,271 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
public static final String ATTRIBUTES = "attributes"; public static final String ATTRIBUTES = "attributes";
public static final String KIND = "GCloudSession"; public static final String KIND = "GCloudSession";
public static final int DEFAULT_MAX_QUERY_RESULTS = 100; protected String _kind = KIND;
public static final int DEFAULT_MAX_RETRIES = 5; protected String _id = ID;
public static final int DEFAULT_BACKOFF_MS = 1000; protected String _contextPath = CONTEXTPATH;
protected String _vhost = VHOST;
protected String _accessed = ACCESSED;
protected String _lastAccessed = LASTACCESSED;
protected String _lastNode = LASTNODE;
protected String _createTime = CREATETIME;
protected String _cookieSetTime = COOKIESETTIME;
protected String _expiry = EXPIRY;
protected String _maxInactive = MAXINACTIVE;
protected String _attributes = ATTRIBUTES;
private Datastore _datastore;
private KeyFactory _keyFactory;
private int _maxResults = DEFAULT_MAX_QUERY_RESULTS;
private int _maxRetries = DEFAULT_MAX_RETRIES;
private int _backoff = DEFAULT_BACKOFF_MS;
private boolean _dsProvided = false; private void checkNotNull(String s)
{
if (s == null)
throw new IllegalArgumentException(s);
}
/**
* @return the lastNode
*/
public String getLastNode()
{
return _lastNode;
}
/**
* @param lastNode the lastNode to set
*/
public void setLastNode(String lastNode)
{
_lastNode = lastNode;
}
/**
* @return the kind
*/
public String getKind()
{
return _kind;
}
/**
* @param kind the kind to set
*/
public void setKind(String kind)
{
checkNotNull(kind);
_kind = kind;
}
/**
* @return the id
*/
public String getId()
{
return _id;
}
/**
* @param id the id to set
*/
public void setId(String id)
{
checkNotNull(id);
_id = id;
}
/**
* @return the contextPath
*/
public String getContextPath()
{
return _contextPath;
}
/**
* @param contextPath the contextPath to set
*/
public void setContextPath(String contextPath)
{
checkNotNull(contextPath);
_contextPath = contextPath;
}
/**
* @return the vhost
*/
public String getVhost()
{
return _vhost;
}
/**
* @param vhost the vhost to set
*/
public void setVhost(String vhost)
{
checkNotNull(vhost);
_vhost = vhost;
}
/**
* @return the accessed
*/
public String getAccessed()
{
return _accessed;
}
/**
* @param accessed the accessed to set
*/
public void setAccessed(String accessed)
{
checkNotNull(accessed);
_accessed = accessed;
}
/**
* @return the lastAccessed
*/
public String getLastAccessed()
{
return _lastAccessed;
}
/**
* @param lastAccessed the lastAccessed to set
*/
public void setLastAccessed(String lastAccessed)
{
checkNotNull(lastAccessed);
_lastAccessed = lastAccessed;
}
/**
* @return the createTime
*/
public String getCreateTime()
{
return _createTime;
}
/**
* @param createTime the createTime to set
*/
public void setCreateTime(String createTime)
{
checkNotNull(createTime);
_createTime = createTime;
}
/**
* @return the cookieSetTime
*/
public String getCookieSetTime()
{
return _cookieSetTime;
}
/**
* @param cookieSetTime the cookieSetTime to set
*/
public void setCookieSetTime(String cookieSetTime)
{
checkNotNull(cookieSetTime);
_cookieSetTime = cookieSetTime;
}
/**
* @return the expiry
*/
public String getExpiry()
{
return _expiry;
}
/**
* @param expiry the expiry to set
*/
public void setExpiry(String expiry)
{
checkNotNull(expiry);
_expiry = expiry;
}
/**
* @return the maxInactive
*/
public String getMaxInactive()
{
return _maxInactive;
}
/**
* @param maxInactive the maxInactive to set
*/
public void setMaxInactive(String maxInactive)
{
checkNotNull(maxInactive);
_maxInactive = maxInactive;
}
/**
* @return the attributes
*/
public String getAttributes()
{
return _attributes;
}
/**
* @param attributes the attributes to set
*/
public void setAttributes(String attributes)
{
checkNotNull(attributes);
_attributes = attributes;
}
}
/**
* ExpiryInfo
*
* Information related to session expiry
*/
public static class ExpiryInfo
{
String _id;
String _lastNode;
long _expiry;
/**
* @param id session id
* @param lastNode last node id to manage the session
* @param expiry timestamp of expiry
*/
public ExpiryInfo (String id, String lastNode, long expiry)
{
_id = id;
_lastNode = lastNode;
_expiry = expiry;
}
/**
* @return the id
*/
public String getId()
{
return _id;
}
/**
* @return the lastNode
*/
public String getLastNode()
{
return _lastNode;
}
/**
* @return the expiry time
*/
public long getExpiry()
{
return _expiry;
}
}
public void setEntityDataModel(EntityDataModel model)
{
_model = model;
}
public EntityDataModel getEntityDataModel ()
{
return _model;
}
public void setBackoffMs (int ms) public void setBackoffMs (int ms)
@ -91,6 +371,15 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
_backoff = ms; _backoff = ms;
} }
public void setNamespace (String namespace)
{
_namespace = namespace;
}
public String getNamespace ()
{
return _namespace;
}
public int getBackoffMs () public int getBackoffMs ()
{ {
@ -116,9 +405,22 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
protected void doStart() throws Exception protected void doStart() throws Exception
{ {
if (!_dsProvided) if (!_dsProvided)
{
if (!StringUtil.isBlank(getNamespace()))
_datastore = DatastoreOptions.builder().namespace(getNamespace()).build().service();
else
_datastore = DatastoreOptions.defaultInstance().service(); _datastore = DatastoreOptions.defaultInstance().service();
}
if (_model == null)
_model = new EntityDataModel();
_keyFactory = _datastore.newKeyFactory().kind(_model.getKind());
_indexesPresent = checkIndexes();
if (!_indexesPresent)
LOG.warn("Session indexes not uploaded, falling back to less efficient queries");
_keyFactory = _datastore.newKeyFactory().kind(KIND);
super.doStart(); super.doStart();
} }
@ -198,43 +500,34 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
try try
{ {
//get up to maxResult number of sessions that have expired Set<ExpiryInfo> info = null;
Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder() if (_indexesPresent)
.kind(KIND) info = queryExpiryByIndex();
.projection(ID, LASTNODE, EXPIRY) else
.filter(CompositeFilter.and(PropertyFilter.gt(EXPIRY, 0), PropertyFilter.le(EXPIRY, now))) info = queryExpiryByEntity();
.limit(_maxResults)
.build();
QueryResults<ProjectionEntity> presults = _datastore.run(query); for (ExpiryInfo item:info)
while (presults.hasNext())
{ {
ProjectionEntity pe = presults.next(); if (StringUtil.isBlank(item.getLastNode()))
String id = pe.getString(ID); expired.add(item.getId()); //nobody managing it
String lastNode = pe.getString(LASTNODE);
long expiry = pe.getLong(EXPIRY);
if (StringUtil.isBlank(lastNode))
expired.add(id); //nobody managing it
else else
{ {
if (_context.getWorkerName().equals(lastNode)) if (_context.getWorkerName().equals(item.getLastNode()))
expired.add(id); //we're managing it, we can expire it expired.add(item.getId()); //we're managing it, we can expire it
else else
{ {
if (_lastExpiryCheckTime <= 0) if (_lastExpiryCheckTime <= 0)
{ {
//our first check, just look for sessions that we managed by another node that //our first check, just look for sessions that we managed by another node that
//expired at least 3 graceperiods ago //expired at least 3 graceperiods ago
if (expiry < (now - (1000L * (3 * _gracePeriodSec)))) if (item.getExpiry() < (now - (1000L * (3 * _gracePeriodSec))))
expired.add(id); expired.add(item.getId());
} }
else else
{ {
//another node was last managing it, only expire it if it expired a graceperiod ago //another node was last managing it, only expire it if it expired a graceperiod ago
if (expiry < (now - (1000L * _gracePeriodSec))) if (item.getExpiry() < (now - (1000L * _gracePeriodSec)))
expired.add(id); expired.add(item.getId());
} }
} }
} }
@ -254,8 +547,8 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
try try
{ {
Query<Key> q = Query.keyQueryBuilder() Query<Key> q = Query.keyQueryBuilder()
.kind(KIND) .kind(_model.getKind())
.filter(PropertyFilter.eq(ID, s)) .filter(PropertyFilter.eq(_model.getId(), s))
.build(); .build();
QueryResults<Key> res = _datastore.run(q); QueryResults<Key> res = _datastore.run(q);
if (!res.hasNext()) if (!res.hasNext())
@ -279,6 +572,77 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
} }
/**
* A less efficient query to find sessions whose expiry time has passed:
* retrieves the whole Entity.
* @return set of ExpiryInfo representing the id, lastNode and expiry time of
* sessions that are expired
* @throws Exception if datastore experiences a problem
*/
protected Set<ExpiryInfo> queryExpiryByEntity () throws Exception
{
Set<ExpiryInfo> info = new HashSet<>();
//get up to maxResult number of sessions that have expired
Query<Entity> query = Query.entityQueryBuilder()
.kind(_model.getKind())
.filter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), System.currentTimeMillis())))
.limit(_maxResults)
.build();
QueryResults<Entity> results;
if (LOG.isDebugEnabled())
{
long start = System.currentTimeMillis();
results = _datastore.run(query);
LOG.debug("Expiry query no index in {}ms", System.currentTimeMillis()-start);
}
else
results = _datastore.run(query);
while (results.hasNext())
{
Entity entity = results.next();
info.add(new ExpiryInfo(entity.getString(_model.getId()),entity.getString(_model.getLastNode()), entity.getLong(_model.getExpiry())));
}
return info;
}
/** An efficient query to find sessions whose expiry time has passed:
* uses a projection query, which requires indexes to be uploaded.
* @return id,lastnode and expiry time of sessions that have expired
* @throws Exception if datastore experiences a problem
*/
protected Set<ExpiryInfo> queryExpiryByIndex () throws Exception
{
Set<ExpiryInfo> info = new HashSet<>();
Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder()
.kind(_model.getKind())
.projection(_model.getId(), _model.getLastNode(), _model.getExpiry())
.filter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), System.currentTimeMillis())))
.limit(_maxResults)
.build();
QueryResults<ProjectionEntity> presults;
if (LOG.isDebugEnabled())
{
long start = System.currentTimeMillis();
presults = _datastore.run(query);
LOG.debug("Expiry query by index in {}ms", System.currentTimeMillis()-start);
}
else
presults = _datastore.run(query);
while (presults.hasNext())
{
ProjectionEntity pe = presults.next();
info.add(new ExpiryInfo(pe.getString(_model.getId()),pe.getString(_model.getLastNode()), pe.getLong(_model.getExpiry())));
}
return info;
}
@ -287,28 +651,73 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
*/ */
@Override @Override
public boolean exists(String id) throws Exception public boolean exists(String id) throws Exception
{
if (_indexesPresent)
{ {
Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder() Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder()
.kind(KIND) .kind(_model.getKind())
.projection(EXPIRY) .projection(_model.getExpiry())
.filter(PropertyFilter.eq(ID, id)) .filter(PropertyFilter.eq(_model.getId(), id))
.build(); .build();
QueryResults<ProjectionEntity> presults;
QueryResults<ProjectionEntity> presults = _datastore.run(query); if (LOG.isDebugEnabled())
{
long start = System.currentTimeMillis();
presults = _datastore.run(query);
LOG.debug("Exists query by index in {}ms", System.currentTimeMillis()-start);
}
else
presults = _datastore.run(query);
if (presults.hasNext()) if (presults.hasNext())
{ {
ProjectionEntity pe = presults.next(); ProjectionEntity pe = presults.next();
long expiry = pe.getLong(EXPIRY); return !isExpired(pe.getLong(_model.getExpiry()));
if (expiry <= 0)
return true; //never expires
else
return (expiry > System.currentTimeMillis()); //not expired yet
} }
else else
return false; return false;
} }
else
{
Query<Entity> query = Query.entityQueryBuilder()
.kind(_model.getKind())
.filter(PropertyFilter.eq(_model.getId(), id))
.build();
QueryResults<Entity> results;
if (LOG.isDebugEnabled())
{
long start = System.currentTimeMillis();
results = _datastore.run(query);
LOG.debug("Exists query no index in {}ms", System.currentTimeMillis()-start);
}
else
results = _datastore.run(query);
if (results.hasNext())
{
Entity entity = results.next();
return !isExpired(entity.getLong(_model.getExpiry()));
}
else
return false;
}
}
/**
* Check to see if the given time is in the past.
*
* @param timestamp the time to check
* @return false if the timestamp is 0 or less, true if it is in the past
*/
protected boolean isExpired (long timestamp)
{
if (timestamp <= 0)
return false;
else
return timestamp < System.currentTimeMillis();
}
/** /**
* @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(java.lang.String, org.eclipse.jetty.server.session.SessionData, long) * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(java.lang.String, org.eclipse.jetty.server.session.SessionData, long)
@ -371,21 +780,48 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
* @param context the session context * @param context the session context
* @return the key * @return the key
*/ */
private Key makeKey (String id, SessionContext context) protected Key makeKey (String id, SessionContext context)
{ {
String key = context.getCanonicalContextPath()+"_"+context.getVhost()+"_"+id; String key = context.getCanonicalContextPath()+"_"+context.getVhost()+"_"+id;
return _keyFactory.newKey(key); return _keyFactory.newKey(key);
} }
/**
* Check to see if indexes are available, in which case
* we can do more performant queries.
* @return
*/
protected boolean checkIndexes ()
{
try
{
Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder()
.kind(_model.getKind())
.projection(_model.getExpiry())
.filter(PropertyFilter.eq(_model.getId(), "-"))
.build();
_datastore.run(query);
return true;
}
catch (DatastoreException e)
{
//need to assume that the problem is the index doesn't exist, because there
//is no specific code for that
if (LOG.isDebugEnabled())
LOG.debug("Check for indexes", e);
return false;
}
}
/** /**
* Generate a gcloud datastore Entity from SessionData * Generate a gcloud datastore Entity from SessionData
* @param session the session data * @param session the session data
* @param key the key * @param key the key
* @return the entity * @return the entity
* @throws Exception * @throws Exception if there is a deserialization error
*/ */
private Entity entityFromSession (SessionData session, Key key) throws Exception protected Entity entityFromSession (SessionData session, Key key) throws Exception
{ {
if (session == null) if (session == null)
return null; return null;
@ -400,17 +836,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
//turn a session into an entity //turn a session into an entity
entity = Entity.builder(key) entity = Entity.builder(key)
.set(ID, session.getId()) .set(_model.getId(), session.getId())
.set(CONTEXTPATH, session.getContextPath()) .set(_model.getContextPath(), session.getContextPath())
.set(VHOST, session.getVhost()) .set(_model.getVhost(), session.getVhost())
.set(ACCESSED, session.getAccessed()) .set(_model.getAccessed(), session.getAccessed())
.set(LASTACCESSED, session.getLastAccessed()) .set(_model.getLastAccessed(), session.getLastAccessed())
.set(CREATETIME, session.getCreated()) .set(_model.getCreateTime(), session.getCreated())
.set(COOKIESETTIME, session.getCookieSet()) .set(_model.getCookieSetTime(), session.getCookieSet())
.set(LASTNODE,session.getLastNode()) .set(_model.getLastNode(),session.getLastNode())
.set(EXPIRY, session.getExpiry()) .set(_model.getExpiry(), session.getExpiry())
.set(MAXINACTIVE, session.getMaxInactiveMs()) .set(_model.getMaxInactive(), session.getMaxInactiveMs())
.set(ATTRIBUTES, BlobValue.builder(Blob.copyFrom(baos.toByteArray())).excludeFromIndexes(true).build()).build(); .set(_model.getAttributes(), BlobValue.builder(Blob.copyFrom(baos.toByteArray())).excludeFromIndexes(true).build()).build();
return entity; return entity;
@ -422,7 +858,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
* @return the session data * @return the session data
* @throws Exception if unable to get the entity * @throws Exception if unable to get the entity
*/ */
private SessionData sessionFromEntity (Entity entity) throws Exception protected SessionData sessionFromEntity (Entity entity) throws Exception
{ {
if (entity == null) if (entity == null)
return null; return null;
@ -436,17 +872,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
try try
{ {
//turn an Entity into a Session //turn an Entity into a Session
String id = entity.getString(ID); String id = entity.getString(_model.getId());
String contextPath = entity.getString(CONTEXTPATH); String contextPath = entity.getString(_model.getContextPath());
String vhost = entity.getString(VHOST); String vhost = entity.getString(_model.getVhost());
long accessed = entity.getLong(ACCESSED); long accessed = entity.getLong(_model.getAccessed());
long lastAccessed = entity.getLong(LASTACCESSED); long lastAccessed = entity.getLong(_model.getLastAccessed());
long createTime = entity.getLong(CREATETIME); long createTime = entity.getLong(_model.getCreateTime());
long cookieSet = entity.getLong(COOKIESETTIME); long cookieSet = entity.getLong(_model.getCookieSetTime());
String lastNode = entity.getString(LASTNODE); String lastNode = entity.getString(_model.getLastNode());
long expiry = entity.getLong(EXPIRY); long expiry = entity.getLong(_model.getExpiry());
long maxInactive = entity.getLong(MAXINACTIVE); long maxInactive = entity.getLong(_model.getMaxInactive());
Blob blob = (Blob) entity.getBlob(ATTRIBUTES); Blob blob = (Blob) entity.getBlob(_model.getAttributes());
SessionData session = newSessionData (id, createTime, accessed, lastAccessed, maxInactive); SessionData session = newSessionData (id, createTime, accessed, lastAccessed, maxInactive);
session.setLastNode(lastNode); session.setLastNode(lastNode);

View File

@ -30,10 +30,21 @@ import org.eclipse.jetty.server.session.SessionHandler;
*/ */
public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFactory public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFactory
{ {
private String _namespace;
private int _maxRetries; private int _maxRetries;
private int _backoffMs; private int _backoffMs;
private GCloudSessionDataStore.EntityDataModel _model;
public GCloudSessionDataStore.EntityDataModel getEntityDataModel()
{
return _model;
}
public void setEntityDataModel(GCloudSessionDataStore.EntityDataModel model)
{
_model = model;
}
public int getMaxRetries() public int getMaxRetries()
{ {
@ -56,6 +67,22 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto
} }
/**
* @return the namespace
*/
public String getNamespace()
{
return _namespace;
}
/**
* @param namespace the namespace to set
*/
public void setNamespace(String namespace)
{
_namespace = namespace;
}
/** /**
* @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler) * @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler)
*/ */
@ -66,6 +93,7 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto
ds.setBackoffMs(getBackoffMs()); ds.setBackoffMs(getBackoffMs());
ds.setMaxRetries(getMaxRetries()); ds.setMaxRetries(getMaxRetries());
ds.setGracePeriodSec(getGracePeriodSec()); ds.setGracePeriodSec(getGracePeriodSec());
ds.setNamespace(_namespace);
return ds; return ds;
} }

View File

@ -13,7 +13,7 @@
<name>Jetty :: GCloud</name> <name>Jetty :: GCloud</name>
<properties> <properties>
<gcloud.version>0.2.3</gcloud.version> <gcloud.version>0.4.0</gcloud.version>
</properties> </properties>
<modules> <modules>

View File

@ -1,6 +1,9 @@
[description] [description]
Deploys the Hawtio console as a webapplication. Deploys the Hawtio console as a webapplication.
[Tags]
3rdparty
[depend] [depend]
stats stats
deploy deploy
@ -13,6 +16,7 @@ etc/hawtio.xml
etc/hawtio/ etc/hawtio/
lib/hawtio/ lib/hawtio/
https://oss.sonatype.org/content/repositories/public/io/hawt/hawtio-default/1.4.16/hawtio-default-1.4.16.war|lib/hawtio/hawtio.war https://oss.sonatype.org/content/repositories/public/io/hawt/hawtio-default/1.4.16/hawtio-default-1.4.16.war|lib/hawtio/hawtio.war
basehome:modules/hawtio/hawtio.xml|etc/hawtio.xml
[license] [license]
Hawtio is a redhat JBoss project released under the Apache License, v2.0 Hawtio is a redhat JBoss project released under the Apache License, v2.0

View File

@ -1,6 +1,9 @@
[description] [description]
Deploys the JAMon webapplication Deploys the JAMon webapplication
[Tags]
3rdparty
[depend] [depend]
stats stats
deploy deploy
@ -12,8 +15,9 @@ etc/jamon.xml
[files] [files]
lib/jamon/ lib/jamon/
maven://com.jamonapi/jamon/2.79|lib/jamon/jamon-2.79.jar maven://com.jamonapi/jamon/2.81|lib/jamon/jamon-2.81.jar
maven://com.jamonapi/jamon_war/2.79/war|lib/jamon/jamon.war maven://com.jamonapi/jamon_war/2.81/war|lib/jamon/jamon.war
basehome:modules/jamon/jamon.xml|etc/jamon.xml
[lib] [lib]
lib/jamon/**.jar lib/jamon/**.jar

View File

@ -1,6 +1,9 @@
[description] [description]
Deploys the Jminix JMX Console within the server Deploys the Jminix JMX Console within the server
[Tags]
3rdparty
[depend] [depend]
stats stats
jmx jmx
@ -26,6 +29,7 @@ maven://commons-collections/commons-collections/3.2|lib/jminix/commons-collectio
maven://net.sf.ezmorph/ezmorph/1.0.6|lib/jminix/ezmorph-1.0.6.jar maven://net.sf.ezmorph/ezmorph/1.0.6|lib/jminix/ezmorph-1.0.6.jar
maven://org.jgroups/jgroups/2.12.1.3.Final|lib/jminix/jgroups-2.12.1.3.Final.jar maven://org.jgroups/jgroups/2.12.1.3.Final|lib/jminix/jgroups-2.12.1.3.Final.jar
maven://org.jasypt/jasypt/1.8|lib/jminix/jasypt-1.8.jar maven://org.jasypt/jasypt/1.8|lib/jminix/jasypt-1.8.jar
basehome:modules/jminix/jminix.xml|etc/jminix.xml
[lib] [lib]
lib/jminix/**.jar lib/jminix/**.jar

View File

@ -1,6 +1,9 @@
[description] [description]
Deploys the Jolokia console as a web application. Deploys the Jolokia console as a web application.
[Tags]
3rdparty
[depend] [depend]
stats stats
deploy deploy
@ -11,6 +14,7 @@ etc/jolokia.xml
[files] [files]
maven://org.jolokia/jolokia-war/1.2.2/war|lib/jolokia/jolokia.war maven://org.jolokia/jolokia-war/1.2.2/war|lib/jolokia/jolokia.war
basehome:modules/jolokia/jolokia.xml|etc/jolokia.xml
[license] [license]
Jolokia is released under the Apache License 2.0 Jolokia is released under the Apache License 2.0

View File

@ -18,6 +18,11 @@
<artifactId>jetty-util</artifactId> <artifactId>jetty-util</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId> <artifactId>jetty-test-helper</artifactId>

View File

@ -0,0 +1,423 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.http;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.component.Destroyable;
/**
* Decoder for the "gzip" encoding.
* <p>
* A decoder that inflates gzip compressed data that has been
* optimized for async usage with minimal data copies.
*/
public class GZIPContentDecoder implements Destroyable
{
private final Inflater _inflater = new Inflater(true);
private final ByteBufferPool _pool;
private final int _bufferSize;
private State _state;
private int _size;
private int _value;
private byte _flags;
private ByteBuffer _inflated;
public GZIPContentDecoder()
{
this(null,2048);
}
public GZIPContentDecoder(int bufferSize)
{
this(null,bufferSize);
}
public GZIPContentDecoder(ByteBufferPool pool, int bufferSize)
{
_bufferSize = bufferSize;
_pool = pool;
reset();
}
/** Inflate compressed data from a buffer.
*
* @param compressed Buffer containing compressed data.
* @return Buffer containing inflated data.
*/
public ByteBuffer decode(ByteBuffer compressed)
{
decodeChunks(compressed);
if (BufferUtil.isEmpty(_inflated) || _state==State.CRC || _state==State.ISIZE )
return BufferUtil.EMPTY_BUFFER;
ByteBuffer result = _inflated;
_inflated = null;
return result;
}
/** Called when a chunk of data is inflated.
* <p>The default implementation aggregates all the chunks
* into a single buffer returned from {@link #decode(ByteBuffer)}.
* Derived implementations may choose to consume chunks individually
* and return false to prevent further inflation until a subsequent
* call to {@link #decode(ByteBuffer)} or {@link #decodeChunks(ByteBuffer)}.
*
* @param chunk The inflated chunk of data
* @return False if inflating should continue, or True if the call
* to {@link #decodeChunks(ByteBuffer)} or {@link #decode(ByteBuffer)}
* should return, allowing back pressure of compressed data.
*/
protected boolean decodedChunk(ByteBuffer chunk)
{
if (_inflated==null)
{
_inflated=chunk;
}
else
{
int size = _inflated.remaining() + chunk.remaining();
if (size<=_inflated.capacity())
{
BufferUtil.append(_inflated,chunk);
BufferUtil.put(chunk,_inflated);
release(chunk);
}
else
{
ByteBuffer bigger=acquire(size);
int pos=BufferUtil.flipToFill(bigger);
BufferUtil.put(_inflated,bigger);
BufferUtil.put(chunk,bigger);
BufferUtil.flipToFlush(bigger,pos);
release(_inflated);
release(chunk);
_inflated = bigger;
}
}
return false;
}
/**
* Inflate compressed data.
* <p>Inflation continues until the compressed block end is reached, there is no
* more compressed data or a call to {@link #decodedChunk(ByteBuffer)} returns true.
* @param compressed Buffer of compressed data to inflate
*/
protected void decodeChunks(ByteBuffer compressed)
{
ByteBuffer buffer = null;
try
{
while (true)
{
switch (_state)
{
case INITIAL:
{
_state = State.ID;
break;
}
case FLAGS:
{
if ((_flags & 0x04) == 0x04)
{
_state = State.EXTRA_LENGTH;
_size = 0;
_value = 0;
}
else if ((_flags & 0x08) == 0x08)
_state = State.NAME;
else if ((_flags & 0x10) == 0x10)
_state = State.COMMENT;
else if ((_flags & 0x2) == 0x2)
{
_state = State.HCRC;
_size = 0;
_value = 0;
}
else
{
_state = State.DATA;
continue;
}
break;
}
case DATA:
{
while (true)
{
if (buffer==null)
buffer = acquire(_bufferSize);
try
{
int length = _inflater.inflate(buffer.array(),buffer.arrayOffset(),buffer.capacity());
buffer.limit(length);
}
catch (DataFormatException x)
{
throw new ZipException(x.getMessage());
}
if (buffer.hasRemaining())
{
ByteBuffer chunk = buffer;
buffer = null;
if (decodedChunk(chunk))
return;
}
else if (_inflater.needsInput())
{
if (!compressed.hasRemaining())
return;
if (compressed.hasArray())
{
_inflater.setInput(compressed.array(),compressed.arrayOffset()+compressed.position(),compressed.remaining());
compressed.position(compressed.limit());
}
else
{
// TODO use the pool
byte[] input = new byte[compressed.remaining()];
compressed.get(input);
_inflater.setInput(input);
}
}
else if (_inflater.finished())
{
int remaining = _inflater.getRemaining();
compressed.position(compressed.limit() - remaining);
_state = State.CRC;
_size = 0;
_value = 0;
break;
}
}
continue;
}
default:
break;
}
if (!compressed.hasRemaining())
break;
byte currByte = compressed.get();
switch (_state)
{
case ID:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 2)
{
if (_value != 0x8B1F)
throw new ZipException("Invalid gzip bytes");
_state = State.CM;
}
break;
}
case CM:
{
if ((currByte & 0xFF) != 0x08)
throw new ZipException("Invalid gzip compression method");
_state = State.FLG;
break;
}
case FLG:
{
_flags = currByte;
_state = State.MTIME;
_size = 0;
_value = 0;
break;
}
case MTIME:
{
// Skip the 4 MTIME bytes
++_size;
if (_size == 4)
_state = State.XFL;
break;
}
case XFL:
{
// Skip XFL
_state = State.OS;
break;
}
case OS:
{
// Skip OS
_state = State.FLAGS;
break;
}
case EXTRA_LENGTH:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 2)
_state = State.EXTRA;
break;
}
case EXTRA:
{
// Skip EXTRA bytes
--_value;
if (_value == 0)
{
// Clear the EXTRA flag and loop on the flags
_flags &= ~0x04;
_state = State.FLAGS;
}
break;
}
case NAME:
{
// Skip NAME bytes
if (currByte == 0)
{
// Clear the NAME flag and loop on the flags
_flags &= ~0x08;
_state = State.FLAGS;
}
break;
}
case COMMENT:
{
// Skip COMMENT bytes
if (currByte == 0)
{
// Clear the COMMENT flag and loop on the flags
_flags &= ~0x10;
_state = State.FLAGS;
}
break;
}
case HCRC:
{
// Skip HCRC
++_size;
if (_size == 2)
{
// Clear the HCRC flag and loop on the flags
_flags &= ~0x02;
_state = State.FLAGS;
}
break;
}
case CRC:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 4)
{
// From RFC 1952, compliant decoders need not to verify the CRC
_state = State.ISIZE;
_size = 0;
_value = 0;
}
break;
}
case ISIZE:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 4)
{
if (_value != _inflater.getBytesWritten())
throw new ZipException("Invalid input size");
// TODO ByteBuffer result = output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output);
reset();
return ;
}
break;
}
default:
throw new ZipException();
}
}
}
catch (ZipException x)
{
throw new RuntimeException(x);
}
finally
{
if (buffer!=null)
release(buffer);
}
}
private void reset()
{
_inflater.reset();
_state = State.INITIAL;
_size = 0;
_value = 0;
_flags = 0;
}
@Override
public void destroy()
{
_inflater.end();
}
public boolean isFinished()
{
return _state == State.INITIAL;
}
private enum State
{
INITIAL, ID, CM, FLG, MTIME, XFL, OS, FLAGS, EXTRA_LENGTH, EXTRA, NAME, COMMENT, HCRC, DATA, CRC, ISIZE
}
/**
* @return An indirect buffer of the configured buffersize either from the pool or freshly allocated.
*/
public ByteBuffer acquire(int capacity)
{
return _pool==null?BufferUtil.allocate(capacity):_pool.acquire(capacity,false);
}
/**
* Release an allocated buffer.
* <p>This method will called {@link ByteBufferPool#release(ByteBuffer)} if a buffer pool has
* been configured. This method should be called once for all buffers returned from {@link #decode(ByteBuffer)}
* or passed to {@link #decodedChunk(ByteBuffer)}.
* @param buffer The buffer to release.
*/
public void release(ByteBuffer buffer)
{
if (_pool!=null && buffer!=BufferUtil.EMPTY_BUFFER)
_pool.release(buffer);
}
}

View File

@ -19,7 +19,7 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.HostPort;
@ -28,57 +28,20 @@ import org.eclipse.jetty.util.StringUtil;
*/ */
public class HostPortHttpField extends HttpField public class HostPortHttpField extends HttpField
{ {
private final String _host; final HostPort _hostPort;
private final int _port;
public HostPortHttpField(String authority) public HostPortHttpField(String authority)
{ {
this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority); this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority);
} }
public HostPortHttpField(HttpHeader header, String name, String authority) /* ------------------------------------------------------------ */
protected HostPortHttpField(HttpHeader header, String name, String authority)
{ {
super(header,name,authority); super(header,name,authority);
if (authority==null || authority.length()==0)
throw new IllegalArgumentException("No Authority");
try try
{ {
if (authority.charAt(0)=='[') _hostPort=new HostPort(authority);
{
// ipv6reference
int close=authority.lastIndexOf(']');
if (close<0)
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6");
_host=authority.substring(0,close+1);
if (authority.length()>close+1)
{
if (authority.charAt(close+1)!=':')
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port");
_port=StringUtil.toInt(authority,close+2);
}
else
_port=0;
}
else
{
// ipv4address or hostname
int c = authority.lastIndexOf(':');
if (c>=0)
{
_host=authority.substring(0,c);
_port=StringUtil.toInt(authority,c+1);
}
else
{
_host=authority;
_port=0;
}
}
}
catch (BadMessageException bm)
{
throw bm;
} }
catch(Exception e) catch(Exception e)
{ {
@ -92,7 +55,7 @@ public class HostPortHttpField extends HttpField
*/ */
public String getHost() public String getHost()
{ {
return _host; return _hostPort.getHost();
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -101,6 +64,16 @@ public class HostPortHttpField extends HttpField
*/ */
public int getPort() public int getPort()
{ {
return _port; return _hostPort.getPort();
}
/* ------------------------------------------------------------ */
/** Get the port.
* @param defaultPort The default port to return if no port set
* @return the port
*/
public int getPort(int defaultPort)
{
return _hostPort.getPort(defaultPort);
} }
} }

View File

@ -18,7 +18,6 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
@ -86,112 +85,8 @@ public class HttpField
if (_value == null) if (_value == null)
return null; return null;
ArrayList<String> list = new ArrayList<>(); QuotedCSV list = new QuotedCSV(false,_value);
int state = 0; return list.getValues().toArray(new String[list.size()]);
int start=0;
int end=0;
StringBuilder builder = new StringBuilder();
for (int i=0;i<_value.length();i++)
{
char c = _value.charAt(i);
switch(state)
{
case 0: // initial white space
switch(c)
{
case '"': // open quote
state=2;
break;
case ',': // ignore leading empty field
break;
case ' ': // more white space
case '\t':
break;
default: // character
start=i;
end=i;
state=1;
}
break;
case 1: // In token
switch(c)
{
case ',': // next field
list.add(_value.substring(start,end+1));
state=0;
break;
case ' ': // more white space
case '\t':
break;
default:
end=i;
}
break;
case 2: // In Quoted
switch(c)
{
case '\\': // next field
state=3;
break;
case '"': // end quote
list.add(builder.toString());
builder.setLength(0);
state=4;
break;
default:
builder.append(c);
}
break;
case 3: // In Quoted Quoted
builder.append(c);
state=2;
break;
case 4: // WS after end quote
switch(c)
{
case ' ': // white space
case '\t': // white space
break;
case ',': // white space
state=0;
break;
default:
throw new IllegalArgumentException("c="+(int)c);
}
break;
}
}
switch(state)
{
case 0:
break;
case 1:
list.add(_value.substring(start,end+1));
break;
case 4:
break;
default:
throw new IllegalArgumentException("state="+state);
}
return list.toArray(new String[list.size()]);
} }
/** /**

View File

@ -282,6 +282,100 @@ public class HttpFields implements Iterable<HttpField>
return list; return list;
} }
/**
* Add comma separated values, but only if not already
* present.
* @param header The header to add the value(s) to
* @param values The value(s) to add
* @return True if headers were modified
*/
public boolean addCSV(HttpHeader header,String... values)
{
QuotedCSV existing = null;
for (HttpField f : this)
{
if (f.getHeader()==header)
{
if (existing==null)
existing = new QuotedCSV(false);
existing.addValue(f.getValue());
}
}
String value = addCSV(existing,values);
if (value!=null)
{
add(header,value);
return true;
}
return false;
}
/**
* Add comma separated values, but only if not already
* present.
* @param name The header to add the value(s) to
* @param values The value(s) to add
* @return True if headers were modified
*/
public boolean addCSV(String name,String... values)
{
QuotedCSV existing = null;
for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name))
{
if (existing==null)
existing = new QuotedCSV(false);
existing.addValue(f.getValue());
}
}
String value = addCSV(existing,values);
if (value!=null)
{
add(name,value);
return true;
}
return false;
}
protected String addCSV(QuotedCSV existing,String... values)
{
// remove any existing values from the new values
boolean add = true;
if (existing!=null && !existing.isEmpty())
{
add = false;
for (int i=values.length;i-->0;)
{
String unquoted = QuotedCSV.unquote(values[i]);
if (existing.getValues().contains(unquoted))
values[i] = null;
else
add = true;
}
}
if (add)
{
StringBuilder value = new StringBuilder();
for (String v:values)
{
if (v==null)
continue;
if (value.length()>0)
value.append(", ");
value.append(v);
}
if (value.length()>0)
return value.toString();
}
return null;
}
/** /**
* Get multiple field values of the same name, split * Get multiple field values of the same name, split
* as a {@link QuotedCSV} * as a {@link QuotedCSV}
@ -292,11 +386,17 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getCSV(HttpHeader header,boolean keepQuotes) public List<String> getCSV(HttpHeader header,boolean keepQuotes)
{ {
QuotedCSV values = new QuotedCSV(keepQuotes); QuotedCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getHeader()==header) if (f.getHeader()==header)
{
if (values==null)
values = new QuotedCSV(keepQuotes);
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**
@ -309,11 +409,17 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getCSV(String name,boolean keepQuotes) public List<String> getCSV(String name,boolean keepQuotes)
{ {
QuotedCSV values = new QuotedCSV(keepQuotes); QuotedCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
{
if (values==null)
values = new QuotedCSV(keepQuotes);
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**
@ -325,11 +431,18 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getQualityCSV(HttpHeader header) public List<String> getQualityCSV(HttpHeader header)
{ {
QuotedQualityCSV values = new QuotedQualityCSV(); QuotedQualityCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getHeader()==header) if (f.getHeader()==header)
{
if (values==null)
values = new QuotedQualityCSV();
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**
@ -341,11 +454,17 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getQualityCSV(String name) public List<String> getQualityCSV(String name)
{ {
QuotedQualityCSV values = new QuotedQualityCSV(); QuotedQualityCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
{
if (values==null)
values = new QuotedQualityCSV();
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**

View File

@ -18,7 +18,6 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.nio.BufferOverflowException; import java.nio.BufferOverflowException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;

View File

@ -28,6 +28,8 @@ import org.eclipse.jetty.http.HttpTokens.EndOfContent;
import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.Utf8StringBuilder;
@ -933,6 +935,7 @@ public class HttpParser
break; break;
default: break; default: break;
} }
if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null) if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null)

View File

@ -22,6 +22,8 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.eclipse.jetty.util.QuotedStringTokenizer;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Implements a quoted comma separated list of values * Implements a quoted comma separated list of values
@ -52,6 +54,9 @@ public class QuotedCSV implements Iterable<String>
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Add and parse a value string(s)
* @param value A value that may contain one or more Quoted CSV items.
*/
public void addValue(String value) public void addValue(String value)
{ {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
@ -241,6 +246,15 @@ public class QuotedCSV implements Iterable<String>
{ {
} }
public int size()
{
return _values.size();
}
public boolean isEmpty()
{
return _values.isEmpty();
}
public List<String> getValues() public List<String> getValues()
{ {

View File

@ -42,10 +42,9 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
private final List<Double> _quality = new ArrayList<>(); private final List<Double> _quality = new ArrayList<>();
private boolean _sorted = false; private boolean _sorted = false;
private final Function<String, Integer> secondaryOrderingFunction; private final Function<String, Integer> _secondaryOrdering;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Sorts values with equal quality according to the length of the value String. * Sorts values with equal quality according to the length of the value String.
*/ */
@ -54,32 +53,35 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
this((s) -> s.length()); this((s) -> s.length());
} }
/* ------------------------------------------------------------ */
/** /**
* Sorts values with equal quality according to given order. * Sorts values with equal quality according to given order.
* @param preferredOrder Array indicating the preferred order of known values
*/ */
public QuotedQualityCSV(String[] serverPreferredValueOrder) public QuotedQualityCSV(String[] preferredOrder)
{ {
this((s) -> { this((s) -> {
for (int i=0;i<serverPreferredValueOrder.length;++i) for (int i=0;i<preferredOrder.length;++i)
if (serverPreferredValueOrder[i].equals(s)) if (preferredOrder[i].equals(s))
return serverPreferredValueOrder.length-i; return preferredOrder.length-i;
if ("*".equals(s)) if ("*".equals(s))
return serverPreferredValueOrder.length; return preferredOrder.length;
return MIN_VALUE; return MIN_VALUE;
}); });
} }
/* ------------------------------------------------------------ */
/** /**
* Orders values with equal quality with the given function. * Orders values with equal quality with the given function.
* @param secondaryOrdering Function to apply an ordering other than specified by quality
*/ */
public QuotedQualityCSV(Function<String, Integer> secondaryOrderingFunction) public QuotedQualityCSV(Function<String, Integer> secondaryOrdering)
{ {
this.secondaryOrderingFunction = secondaryOrderingFunction; this._secondaryOrdering = secondaryOrdering;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public void addValue(String value) public void addValue(String value)
{ {
@ -148,7 +150,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
Double q = _quality.get(i); Double q = _quality.get(i);
int compare=last.compareTo(q); int compare=last.compareTo(q);
if (compare>0 || (compare==0 && secondaryOrderingFunction.apply(v)<lastOrderIndex)) if (compare>0 || (compare==0 && _secondaryOrdering.apply(v)<lastOrderIndex))
{ {
_values.set(i, _values.get(i + 1)); _values.set(i, _values.get(i + 1));
_values.set(i + 1, v); _values.set(i + 1, v);
@ -161,7 +163,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
} }
last=q; last=q;
lastOrderIndex=secondaryOrderingFunction.apply(v); lastOrderIndex=_secondaryOrdering.apply(v);
} }
int last_element=_quality.size(); int last_element=_quality.size();

View File

@ -0,0 +1,343 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.http;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.eclipse.jetty.io.ArrayByteBufferPool;
import org.eclipse.jetty.toolchain.test.TestTracker;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
public class GZIPContentDecoderTest
{
@Rule
public final TestTracker tracker = new TestTracker();
ArrayByteBufferPool pool;
AtomicInteger buffers = new AtomicInteger(0);
@Before
public void beforeClass() throws Exception
{
buffers.set(0);
pool = new ArrayByteBufferPool()
{
@Override
public ByteBuffer acquire(int size, boolean direct)
{
buffers.incrementAndGet();
return super.acquire(size,direct);
}
@Override
public void release(ByteBuffer buffer)
{
buffers.decrementAndGet();
super.release(buffer);
}
};
}
@After
public void afterClass() throws Exception
{
assertEquals(0,buffers.get());
}
@Test
public void testStreamNoBlocks() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.close();
byte[] bytes = baos.toByteArray();
GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1);
int read = input.read();
assertEquals(-1, read);
}
@Test
public void testStreamBigBlockOneByteAtATime() throws Exception
{
String data = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
baos = new ByteArrayOutputStream();
GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1);
int read;
while ((read = input.read()) >= 0)
baos.write(read);
assertEquals(data, new String(baos.toByteArray(), StandardCharsets.UTF_8));
}
@Test
public void testNoBlocks() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.close();
byte[] bytes = baos.toByteArray();
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
assertEquals(0, decoded.remaining());
}
@Test
public void testSmallBlock() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
}
@Test
public void testSmallBlockWithGZIPChunkedAtBegin() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// The header is 10 bytes, chunk at 11 bytes
byte[] bytes1 = new byte[11];
System.arraycopy(bytes, 0, bytes1, 0, bytes1.length);
byte[] bytes2 = new byte[bytes.length - bytes1.length];
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.capacity());
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
}
@Test
public void testSmallBlockWithGZIPChunkedAtEnd() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// The trailer is 8 bytes, chunk the last 9 bytes
byte[] bytes1 = new byte[bytes.length - 9];
System.arraycopy(bytes, 0, bytes1, 0, bytes1.length);
byte[] bytes2 = new byte[bytes.length - bytes1.length];
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
assertFalse(decoder.isFinished());
decoder.release(decoded);
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(0, decoded.remaining());
assertTrue(decoder.isFinished());
decoder.release(decoded);
}
@Test
public void testSmallBlockWithGZIPTrailerChunked() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// The trailer is 4+4 bytes, chunk the last 3 bytes
byte[] bytes1 = new byte[bytes.length - 3];
System.arraycopy(bytes, 0, bytes1, 0, bytes1.length);
byte[] bytes2 = new byte[bytes.length - bytes1.length];
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.capacity());
decoder.release(decoded);
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
}
@Test
public void testTwoSmallBlocks() throws Exception
{
String data1 = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data1.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes1 = baos.toByteArray();
String data2 = "1";
baos = new ByteArrayOutputStream();
output = new GZIPOutputStream(baos);
output.write(data2.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes2 = baos.toByteArray();
byte[] bytes = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, bytes, 0, bytes1.length);
System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
ByteBuffer decoded = decoder.decode(buffer);
assertEquals(data1, StandardCharsets.UTF_8.decode(decoded).toString());
assertTrue(decoder.isFinished());
assertTrue(buffer.hasRemaining());
decoder.release(decoded);
decoded = decoder.decode(buffer);
assertEquals(data2, StandardCharsets.UTF_8.decode(decoded).toString());
assertTrue(decoder.isFinished());
assertFalse(buffer.hasRemaining());
decoder.release(decoded);
}
@Test
public void testBigBlock() throws Exception
{
String data = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
String result = "";
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(buffer);
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
}
assertEquals(data, result);
}
@Test
public void testBigBlockOneByteAtATime() throws Exception
{
String data = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
String result = "";
GZIPContentDecoder decoder = new GZIPContentDecoder(64);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(new byte[]{buffer.get()}));
if (decoded.hasRemaining())
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
}
assertEquals(data, result);
assertTrue(decoder.isFinished());
}
@Test
public void testBigBlockWithExtraBytes() throws Exception
{
String data1 = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data1 += data1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data1.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes1 = baos.toByteArray();
String data2 = "HELLO";
byte[] bytes2 = data2.getBytes(StandardCharsets.UTF_8);
byte[] bytes = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, bytes, 0, bytes1.length);
System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length);
String result = "";
GZIPContentDecoder decoder = new GZIPContentDecoder(64);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(buffer);
if (decoded.hasRemaining())
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
if (decoder.isFinished())
break;
}
assertEquals(data1, result);
assertTrue(buffer.hasRemaining());
assertEquals(data2, StandardCharsets.UTF_8.decode(buffer).toString());
}
}

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -340,7 +341,89 @@ public class HttpFieldsTest
} }
@Test @Test
public void testGetQualityValues() throws Exception public void testGetCSV() throws Exception
{
HttpFields fields = new HttpFields();
fields.put("name0", "value0A,value0B");
fields.add("name0", "value0C,value0D");
fields.put("name1", "value1A, \"value\t, 1B\" ");
fields.add("name1", "\"value1C\",\tvalue1D");
Enumeration<String> e = fields.getValues("name0");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0A,value0B");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0C,value0D");
assertEquals(false, e.hasMoreElements());
e = Collections.enumeration(fields.getCSV("name0",false));
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0A");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0B");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0C");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0D");
assertEquals(false, e.hasMoreElements());
e = Collections.enumeration(fields.getCSV("name1",false));
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value1A");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value\t, 1B");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value1C");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value1D");
assertEquals(false, e.hasMoreElements());
}
@Test
public void testAddQuotedCSV() throws Exception
{
HttpFields fields = new HttpFields();
fields.put("some", "value");
fields.add("name", "\"zero\"");
fields.add("name", "one, \"1 + 1\"");
fields.put("other", "value");
fields.add("name", "three");
fields.add("name", "four, I V");
List<String> list = fields.getCSV("name",false);
assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null));
assertEquals("three",HttpFields.valueParameters(list.get(3),null));
assertEquals("four",HttpFields.valueParameters(list.get(4),null));
assertEquals("I V",HttpFields.valueParameters(list.get(5),null));
fields.addCSV("name","six");
list = fields.getCSV("name",false);
assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null));
assertEquals("three",HttpFields.valueParameters(list.get(3),null));
assertEquals("four",HttpFields.valueParameters(list.get(4),null));
assertEquals("I V",HttpFields.valueParameters(list.get(5),null));
assertEquals("six",HttpFields.valueParameters(list.get(6),null));
fields.addCSV("name","1 + 1","7","zero");
list = fields.getCSV("name",false);
assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null));
assertEquals("three",HttpFields.valueParameters(list.get(3),null));
assertEquals("four",HttpFields.valueParameters(list.get(4),null));
assertEquals("I V",HttpFields.valueParameters(list.get(5),null));
assertEquals("six",HttpFields.valueParameters(list.get(6),null));
assertEquals("7",HttpFields.valueParameters(list.get(7),null));
}
@Test
public void testGetQualityCSV() throws Exception
{ {
HttpFields fields = new HttpFields(); HttpFields fields = new HttpFields();
@ -351,7 +434,8 @@ public class HttpFieldsTest
fields.add("name", "one;q=0.4"); fields.add("name", "one;q=0.4");
fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3"); fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3");
List<String> list = HttpFields.qualityList(fields.getValues("name",","));
List<String> list = fields.getQualityCSV("name");
assertEquals("zero",HttpFields.valueParameters(list.get(0),null)); assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null)); assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("two",HttpFields.valueParameters(list.get(2),null)); assertEquals("two",HttpFields.valueParameters(list.get(2),null));

View File

@ -25,6 +25,7 @@ import java.util.List;
import org.eclipse.jetty.http.HttpParser.State; import org.eclipse.jetty.http.HttpParser.State;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -1631,6 +1632,8 @@ public class HttpParserTest
@Test @Test
public void testBadIPv6Host() throws Exception public void testBadIPv6Host() throws Exception
{
try(StacklessLogging s = new StacklessLogging(HttpParser.class))
{ {
ByteBuffer buffer = BufferUtil.toBuffer( ByteBuffer buffer = BufferUtil.toBuffer(
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
@ -1643,6 +1646,7 @@ public class HttpParserTest
parser.parseNext(buffer); parser.parseNext(buffer);
Assert.assertThat(_bad, Matchers.containsString("Bad")); Assert.assertThat(_bad, Matchers.containsString("Bad"));
} }
}
@Test @Test
public void testHostPort() throws Exception public void testHostPort() throws Exception

View File

@ -320,7 +320,7 @@ public class HttpTester
@Override @Override
public void parsedHeader(HttpField field) public void parsedHeader(HttpField field)
{ {
put(field.getName(),field.getValue()); add(field.getName(),field.getValue());
} }
@Override @Override

Some files were not shown because too many files have changed in this diff Show More