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

12
Jenkinsfile vendored
View File

@ -20,7 +20,9 @@ node {
{
stage 'Compile'
withEnv(mvnEnv) {
sh "mvn -B clean install -Dtest=None"
timeout(15) {
sh "mvn -B clean install -Dtest=None"
}
}
} catch(Exception e) {
notifyBuild("Compile Failure")
@ -31,7 +33,9 @@ node {
{
stage 'Javadoc'
withEnv(mvnEnv) {
sh "mvn -B javadoc:javadoc"
timeout(15) {
sh "mvn -B javadoc:javadoc"
}
}
} catch(Exception e) {
notifyBuild("Javadoc Failure")
@ -41,8 +45,8 @@ node {
try
{
stage 'Test'
timeout(60) {
withEnv(mvnEnv) {
withEnv(mvnEnv) {
timeout(60) {
// Run test phase / ignore test failures
sh "mvn -B install -Dmaven.test.failure.ignore=true"
// 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}"
</Export-Package>
<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>
</instructions>
</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.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
/**
* 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
// 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();
// 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.
resource_handler.setDirectoriesListed(true);
@ -48,11 +48,9 @@ public class FileServer
resource_handler.setResourceBase(".");
// Add the ResourceHandler to the server.
GzipHandler gzip = new GzipHandler();
server.setHandler(gzip);
HandlerList handlers = new HandlerList();
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.
// 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.rewrite.handler.RewriteHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.ConnectorStatistics;
import org.eclipse.jetty.server.DebugListener;
import org.eclipse.jetty.server.Handler;
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.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnectionStatistics;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
@ -193,7 +193,7 @@ public class LikeJettyXml
StatisticsHandler stats = new StatisticsHandler();
stats.setHandler(server.getHandler());
server.setHandler(stats);
ConnectorStatistics.addToAllConnectors(server);
ServerConnectionStatistics.addToAllConnectors(server);
// === Rewrite Handler
RewriteHandler rewrite = new RewriteHandler();

View File

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

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.annotations;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
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.MultiException;
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.Logger;
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<ParserTask> _parserTasks;
protected WebAppClassNameResolver _webAppClassNameResolver;
protected ContainerClassNameResolver _containerClassNameResolver;
protected CounterStatistic _containerPathStats;
protected CounterStatistic _webInfLibStats;
@ -138,15 +136,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected Exception _exception;
protected final AnnotationParser _parser;
protected final Set<? extends Handler> _handlers;
protected final ClassNameResolver _resolver;
protected final Resource _resource;
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;
_handlers = handlers;
_resolver = resolver;
_resource = resource;
}
@ -160,7 +156,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_stat != null)
_stat.start();
if (_parser != null)
_parser.parse(_handlers, _resource, _resolver);
_parser.parse(_handlers, _resource);
if (_stat != null)
_stat.end();
return null;
@ -174,83 +170,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getResource()
{
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
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);
_sciExcludePattern = (tmp==null?null:Pattern.compile(tmp));
}
@ -445,15 +363,15 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
scanForAnnotations(context);
// Resolve container initializers
List<ContainerInitializer> initializers =
(List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
(List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
if (initializers != null && initializers.size()>0)
{
Map<String, Set<String>> map = ( Map<String, Set<String>>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
for (ContainerInitializer i : initializers)
i.resolveClasses(context,map);
i.resolveClasses(context,map);
}
}
@ -723,23 +641,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getJarFor (ServletContainerInitializer service)
throws MalformedURLException, IOException
{
//try the thread context classloader to get the jar that loaded the class
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);
return TypeUtil.getLoadedFrom(service.getClass());
}
/**
@ -760,26 +662,41 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (context == 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
//of WEB-INF/lib jars
if (isFromContainerClassPath(context, sci))
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} from container classpath", sci);
return false;
}
//If no ordering, nothing is excluded
if (context.getMetaData().getOrdering() == null)
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} no ordering", sci);
return false;
}
List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
//there is an ordering, but there are no jars resulting from the ordering, everything excluded
if (orderedJars.isEmpty())
{
if (LOG.isDebugEnabled())
LOG.debug("Excluded {} empty ordering", sci);
return true;
}
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();
boolean found = false;
@ -790,10 +707,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
found = r.getURI().equals(loadingJarURI);
}
if (LOG.isDebugEnabled())
LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found);
return !found;
}
/**
* Test if the ServletContainerIntializer is excluded by the
* o.e.j.containerInitializerExclusionPattern
@ -808,7 +726,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
return false;
//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();
}
@ -866,17 +785,18 @@ public class AnnotationConfiguration extends AbstractConfiguration
//because containerInitializerOrdering omits it
for (ServletContainerInitializer sci:_loadedInitializers)
{
if (matchesExclusionPattern(sci))
{
if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci);
if (LOG.isDebugEnabled())
LOG.debug("{} excluded by pattern", sci);
continue;
}
Resource sciResource = getJarFor(sci);
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;
}
@ -885,7 +805,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (initializerOrdering != null
&& (!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;
}
@ -912,12 +833,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
//no web.xml ordering defined, add SCIs in any order
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());
}
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())
{
//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
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver);
ParserTask task = new ParserTask(parser, handlers, r);
_parserTasks.add(task);
_containerPathStats.increment();
if (LOG.isDebugEnabled())
@ -1054,7 +977,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers,r, _webAppClassNameResolver);
ParserTask task = new ParserTask(parser, handlers,r);
_parserTasks.add (task);
_webInfLibStats.increment();
if (LOG.isDebugEnabled())
@ -1087,7 +1010,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver);
ParserTask task = new ParserTask(parser, handlers, dir);
_parserTasks.add(task);
_webInfClassesStats.increment();
if (LOG.isDebugEnabled())

View File

@ -544,28 +544,24 @@ public class AnnotationParser
*
* @param handlers the set of handlers to find class
* @param className the class name to parse
* @param resolver the class name resolver to use
* @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
{
if (className == null)
return;
if (!resolver.isExcluded(className))
if (!isParsed(className))
{
if (!isParsed(className) || resolver.shouldOverride(className))
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
{
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
@ -578,33 +574,30 @@ public class AnnotationParser
*
* @param handlers the handlers to look for class in
* @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
* @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
{
Class<?> cz = clazz;
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";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
{
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
if (visitSuperClasses)
cz = cz.getSuperclass();
else
@ -619,16 +612,15 @@ public class AnnotationParser
*
* @param handlers the set of handlers to look for class in
* @param classNames the class name
* @param resolver the class name resolver
* @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
{
if (classNames == null)
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 classNames the class names
* @param resolver the class name resolver
* @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
{
MultiException me = new MultiException();
@ -649,7 +640,7 @@ public class AnnotationParser
{
try
{
if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
if (!isParsed(s))
{
s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(s);
@ -677,10 +668,9 @@ public class AnnotationParser
*
* @param handlers the set of handlers to look for classes in
* @param dir the resource directory to look for classes
* @param resolver the class name resolver
* @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
{
// skip dirs whose name start with . (ie hidden)
@ -696,7 +686,7 @@ public class AnnotationParser
{
Resource res = dir.addPath(files[f]);
if (res.isDirectory())
parseDir(handlers, res, resolver);
parseDir(handlers, res);
else
{
//we've already verified the directories, so just verify the class file name
@ -706,7 +696,7 @@ public class AnnotationParser
try
{
String name = res.getName();
if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
if (!isParsed(name))
{
Resource r = Resource.newResource(res.getURL());
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);};
@ -741,10 +731,9 @@ public class AnnotationParser
* @param loader the classloader for the classes
* @param visitParents if true, visit parent classloaders too
* @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
*/
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
{
if (loader==null)
@ -762,7 +751,7 @@ public class AnnotationParser
{
try
{
parseJarEntry(handlers, Resource.newResource(jarUri), entry, resolver);
parseJarEntry(handlers, Resource.newResource(jarUri), entry);
}
catch (Exception e)
{
@ -782,10 +771,9 @@ public class AnnotationParser
*
* @param handlers the handlers to look for classes in
* @param uris the uris for the jars
* @param resolver the class name resolver
* @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
{
if (uris==null)
@ -797,7 +785,7 @@ public class AnnotationParser
{
try
{
parse(handlers, uri, resolver);
parse(handlers, uri);
}
catch (Exception e)
{
@ -812,16 +800,15 @@ public class AnnotationParser
*
* @param handlers the handlers to look for classes in
* @param uri the uri for the jar
* @param resolver the class name resolver
* @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
{
if (uri == null)
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 r the resource to parse
* @param resolver the class name resolver
* @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
{
if (r == null)
@ -841,14 +827,14 @@ public class AnnotationParser
if (r.exists() && r.isDirectory())
{
parseDir(handlers, r, resolver);
parseDir(handlers, r);
return;
}
String fullname = r.toString();
if (fullname.endsWith(".jar"))
{
parseJar(handlers, r, resolver);
parseJar(handlers, r);
return;
}
@ -872,10 +858,9 @@ public class AnnotationParser
*
* @param handlers the handlers to look for classes in
* @param jarResource the jar resource to parse
* @param resolver the class name resolver
* @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
{
if (jarResource == null)
@ -899,7 +884,7 @@ public class AnnotationParser
{
try
{
parseJarEntry(handlers, jarResource, entry, resolver);
parseJarEntry(handlers, jarResource, entry);
}
catch (Exception e)
{
@ -927,10 +912,9 @@ public class AnnotationParser
* @param handlers the handlers to look for classes in
* @param jar 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
*/
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
{
if (jar == null || entry == null)
@ -947,9 +931,7 @@ public class AnnotationParser
{
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null)
||
(!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
if (!isParsed(shortName))
{
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);};

View File

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

View File

@ -111,19 +111,7 @@ public class TestAnnotationParser
}
//long start = System.currentTimeMillis();
parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames);
//long end = System.currentTimeMillis();
//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
@ -171,7 +159,7 @@ public class TestAnnotationParser
File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar");
AnnotationParser parser = new AnnotationParser();
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
}
@ -196,7 +184,7 @@ public class TestAnnotationParser
AnnotationParser parser = new AnnotationParser();
// Parse
parser.parse(Collections.singleton(tracker), basedir.toURI(),null);
parser.parse(Collections.singleton(tracker), basedir.toURI());
// Validate
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);
parser.parse(Collections.singleton(handler), classes, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
parser.parse(Collections.singleton(handler), classes);
assertEquals(1, results.size());

View File

@ -1,4 +1,21 @@
<?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">
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>

View File

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

View File

@ -18,26 +18,13 @@
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.
*
*/
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()
{
@ -46,285 +33,7 @@ public class GZIPContentDecoder implements ContentDecoder
public GZIPContentDecoder(int bufferSize)
{
this.bytes = new byte[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;
super(null,bufferSize);
}
/**
@ -351,9 +60,4 @@ public class GZIPContentDecoder implements ContentDecoder
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)
continue;
String name = field.getName();
String value = field.getValue();
if (!newRequest.getHeaders().contains(header, value))
newRequest.header(field.getName(), value);
if (!newRequest.getHeaders().contains(name, value))
newRequest.header(name, value);
}
return newRequest;
}
@ -564,18 +565,12 @@ public class HttpClient extends ContainerLifeCycle
{
context.put(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY, new Promise.Wrapper<Connection>(promise)
{
@Override
public void succeeded(Connection result)
{
getPromise().succeeded(result);
}
@Override
public void failed(Throwable x)
{
int nextIndex = index + 1;
if (nextIndex == socketAddresses.size())
getPromise().failed(x);
super.failed(x);
else
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.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -68,21 +67,23 @@ public abstract class HttpConnection implements Connection
@Override
public void send(Request request, Response.CompleteListener listener)
{
ArrayList<Response.ResponseListener> listeners = new ArrayList<>(2);
if (request.getTimeout() > 0)
HttpRequest httpRequest = (HttpRequest)request;
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());
listeners.add(timeoutListener);
}
if (listener != null)
listeners.add(listener);
HttpExchange exchange = new HttpExchange(getHttpDestination(), (HttpRequest)request, listeners);
HttpExchange exchange = new HttpExchange(getHttpDestination(), httpRequest, listeners);
SendFailure result = send(exchange);
if (result != null)
request.abort(result.failure);
httpRequest.abort(result.failure);
}
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.util.BlockingArrayQueue;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ -87,7 +88,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
}
this.connectionFactory = connectionFactory;
String host = getHost();
String host = HostPort.normalizeHost(getHost());
if (!client.isDefaultPort(getScheme(), getPort()))
host += ":" + getPort();
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.Callback;
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.Logger;
@ -470,6 +471,7 @@ public abstract class HttpReceiver
*/
protected void reset()
{
destroyDecoder(decoder);
decoder = null;
}
@ -482,9 +484,18 @@ public abstract class HttpReceiver
*/
protected void dispose()
{
destroyDecoder(decoder);
decoder = null;
}
private static void destroyDecoder(ContentDecoder decoder)
{
if (decoder instanceof Destroyable)
{
((Destroyable)decoder).destroy();
}
}
public boolean abort(HttpExchange exchange, Throwable failure)
{
// Update the state to avoid more response processing.

View File

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

View File

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

View File

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

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.client;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
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.HttpDestinationOverHTTP;
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.ssl.SslContextFactory;
import org.junit.Assert;
@ -65,7 +66,6 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe
}
}
@Slow
@Test
public void testExplicitConnectionIsClosedOnRemoteClose() throws Exception
{
@ -98,4 +98,26 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe
Assert.assertTrue(connectionPool.getActiveConnections().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.OutputStream;
import java.net.HttpCookie;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.log.StacklessLogging;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Rule;
@ -811,10 +811,23 @@ public class HttpClientTest extends AbstractHttpClientServerTest
@Test
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());
final CountDownLatch latch = new CountDownLatch(1);
client.newRequest("idontexist", 80)
client.newRequest(host, port)
.send(result ->
{
Assert.assertTrue(result.isFailed());
@ -828,19 +841,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest
@Test
public void testConnectHostWithMultipleAddresses() throws Exception
{
String host = "google.com";
try
{
// Likely that the DNS for google.com returns multiple addresses.
Assume.assumeTrue(InetAddress.getAllByName(host).length > 1);
}
catch (Throwable x)
{
Assume.assumeNoException(x);
}
start(new EmptyServerHandler());
startClient();
client.setFollowRedirects(false); // Avoid redirects from 80 to 443.
client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), client.getConnectTimeout())
{
@Override
@ -853,7 +855,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
{
// Add as first address an invalid address so that we test
// 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);
}
@ -866,9 +868,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest
}
});
// Response code may be 200 or 302;
// if no exceptions the test passes.
client.newRequest(host, 80)
// If no exceptions the test passes.
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.header(HttpHeader.CONNECTION, "close")
.send();
}
@ -1232,7 +1234,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
// before closing the connection, so we need to wait before checking
// that the connection is closed to avoid races.
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
{
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.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>
*/
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());
File file = resource.getFile();
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();

View File

@ -329,7 +329,7 @@
<arguments>
<argument>jetty.home=${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>
</configuration>
<goals>

View File

@ -72,6 +72,7 @@
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.17</version>
<executions>
<execution>
<id>html</id>
@ -81,10 +82,10 @@
</goals>
<configuration>
<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>
<!-- 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">
<include name="**/*.png" />
<include name="**/*.jpg" />
@ -92,16 +93,16 @@
<include name="**/*.dot" />
</fileset>
</copy>
<copy todir="target/docbkx/html/index/images">
<copy todir="target/docbkx/html/images">
<fileset dir="src/main/docbkx-resources/images" />
</copy>
<copy todir="target/docbkx/html/index/css">
<copy todir="target/docbkx/html/css">
<fileset dir="src/main/docbkx-resources/css" />
</copy>
<copy todir="target/docbkx/html/index/fonts">
<copy todir="target/docbkx/html/fonts">
<fileset dir="src/main/docbkx-resources/fonts" />
</copy>
<copy todir="target/docbkx/html/index/js">
<copy todir="target/docbkx/html/js">
<fileset dir="src/main/docbkx-resources/js" />
</copy>
</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="port"><Property name="jetty.http.port" default="8080" /></Set>
<Set name="idleTimeout">30000</Set>
<!-- Enable Connector Statistics -->
<!-- Enable Connection Statistics -->
<Call name="addBean">
<Arg>
<New id="ConnectorStatistics" class="org.eclipse.jetty.server.ConnectorStatistics"/>
<New id="ConnectionStatistics" class="org.eclipse.jetty.io.ConnectionStatistics"/>
</Arg>
</Call>
</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
$ 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`.
@ -152,7 +152,7 @@ Enabling the `http2` is easy; in additions to the modules you have enabled above
[source, screen, subs="{sub-order}"]
....
$ 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.

View File

@ -65,5 +65,5 @@ Currently there are very few HTTP/2 configuration properties and the default val
|=======================================================================
|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.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
$ mkdir $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).
@ -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}"]
....
$ 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.
@ -61,7 +61,7 @@ HTTP/2 can be enabled on the plain text connector and the server restarted with
[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
..
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.
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 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.
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.
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 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::default-logging-with-stderrlog.adoc[]
include::configuring-jetty-request-logs.adoc[]
include::example-apache-log4j.adoc[]
include::example-java-util-logging.adoc[]
include::example-java-util-logging-native.adoc[]
include::example-logback.adoc[]
include::example-slf4j-multiple-loggers.adoc[]
include::configuring-logging-modules.adoc[]
// TODO - Remove following
// include::example-apache-log4j.adoc[]
// include::example-java-util-logging.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::dump-tool.adoc[]

View File

@ -51,7 +51,7 @@ Configure the Jetty logging layer via the `org.eclipse.jetty.util.log.Log` class
* If no logger implementation is specified, default to `org.eclipse.jetty.util.log.StdErrLog`.
____
[NOTE]
You can create your own custom logging by providing an implementation of the link:{JDURL}org/eclipse/jetty/util/log/Logger.html[Jetty Logger API].
You can create your own custom logging by providing an implementation of the link:{JDURL}org/eclipse/jetty/util/log/Logger.html[Jetty Logger API].
For an example of a custom logger, see link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java[JavaUtilLog.java].
____
@ -60,7 +60,7 @@ ____
By default, the internal Jetty Logging discovery mechanism will load logging specific properties from a classpath resource called `jetty-logging.properties` and then initialize the Logging from a combination of properties found in that file, along with any System Properties.
A typical jetty-logging.properties file will include at least the declaration of which logging implementation you want to use by defining a value for the `org.eclipse.jetty.util.log.class` property.
Examples for various logging frameworks can be found later in this documentation.
* Default Logging with link:#default-logging-with-stderrlog[Jetty's StdErrLog]

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}"]
----
$ 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
MKDIR: ${jetty.base}/logs
INFO: Base directory was modified
----
The above command will add a new `requestlog.ini` file to your `{$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 above command will add a new `requestlog.ini` file to your link:#start-vs-startd[`{$jetty.base}/start.d` directory].
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

@ -20,7 +20,7 @@
[[stderrlog-configuration]]
==== StdErrLog Configuration
If you do nothing to configure a separate logging framework, Jetty will default to using an internal `org.eclipse.jetty.util.log.StdErrLog` implementation.
If you do nothing to configure a separate logging framework, Jetty will default to using an internal `org.eclipse.jetty.util.log.StdErrLog` implementation.
This will output all logging events to STDERR (aka `System.err`).
Simply use Jetty and `StdErrLog` based logging is output.
@ -29,62 +29,55 @@ Included in the Jetty distribution is a logging module that is capable of perfor
To enable on this feature via the command line:
[source,bash]
----
[my-base]$ java -jar /opt/jetty/start.jar --module=logging
----
[source, screen, subs="{sub-order}"]
....
[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`.
[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.
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.
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
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog
# Overall Logging Level is INFO
org.eclipse.jetty.LEVEL=INFO
# Detail Logging for WebSocket
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`.
`<name>.LEVEL=<level>`::
Sets the logging level for all loggers within the `name` specified to the level, which can be (in increasing order of restriction) `ALL`, `DEBUG`, `INFO`, `WARN`, `OFF`.
Sets the logging level for all loggers within the `name` specified to the level, which can be (in increasing order of restriction) `ALL`, `DEBUG`, `INFO`, `WARN`, `OFF`.
The name (or hierarchy) can be a specific fully qualified class or a package namespace.
For example, `org.eclipse.jetty.http.LEVEL=DEBUG` is a package namespace approach to turn all loggers in the Jetty HTTP package to DEBUG level, and `org.eclipse.jetty.io.ChanelEndPoint.LEVEL=ALL` turns on all logging events for the specific class, including `DEBUG`, `INFO`, `WARN` (and even special internally ignored exception classes).
For example, `org.eclipse.jetty.http.LEVEL=DEBUG` is a package namespace approach to turn all loggers in the Jetty HTTP package to DEBUG level, and `org.eclipse.jetty.io.ChanelEndPoint.LEVEL=ALL` turns on all logging events for the specific class, including `DEBUG`, `INFO`, `WARN` (and even special internally ignored exception classes).
If more than one system property specifies a logging level, the most specific one applies.
`<name>.SOURCE=<boolean>`::
Named Logger specific, attempts to print the Java source file name and line number from where the logging event originated.
Name must be a fully qualified class name (this configurable does not support package name hierarchy).
Default is false.
Named Logger specific, attempts to print the Java source file name and line number from where the logging event originated.
Name must be a fully qualified class name (this configurable does not support package name hierarchy).
Default is false.
Be aware that this is a slow operation and has an impact on performance.
`<name>.STACKS=<boolean>`::
Named Logger specific, controls the display of stacktraces.
Named Logger specific, controls the display of stacktraces.
Name must be a fully qualified class name (this configurable does not support package name hierarchy).
Default is true.
`org.eclipse.jetty.util.log.stderr.SOURCE=<boolean>`::
Special Global Configuration.
Attempts to print the Java source file name and line number from where the logging event originated.
Special Global Configuration.
Attempts to print the Java source file name and line number from where the logging event originated.
Default is false.
`org.eclipse.jetty.util.log.stderr.LONG=<boolean>`::
Special Global Configuration.
When true, outputs logging events to `STDERR` using long form, fully qualified class names.
Special Global Configuration.
When true, outputs logging events to `STDERR` using long form, fully qualified class names.
When false, uses abbreviated package names.
Default is false.
+
+
* Example when set to false:
+
+
[source, screen, subs="{sub-order}"]
....
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.888:INFO:oejs.Server:main: Started @257ms
....
+
+
* Example when set to true:
+
+
[source, screen, subs="{sub-order}"]
....
2014-06-03 14:38:19.019:INFO:org.eclipse.jetty.server.Server:main: jetty-9.2.0.v20140526
@ -108,7 +101,7 @@ There are a number of properties that can be defined in the configuration that w
[[deprecated-parameters]]
==== Deprecated Parameters
These parameters existed in prior versions of Jetty, and are no longer supported.
These parameters existed in prior versions of Jetty, and are no longer supported.
They are included here for historical (and search engine) reasons.
`org.eclipse.jetty.util.log.DEBUG`::

View File

@ -14,10 +14,9 @@
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
[[example-logging-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.
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].
A convenient replacement `logging` module has been created to bootstrap your `${jetty.base}` directory for logging with log4j.

View File

@ -14,7 +14,6 @@
// 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
It is possible to have the Jetty Server logging configured so that
@ -26,7 +25,7 @@ This example demonstrates how to configuring Jetty for logging to
____
[IMPORTANT]
While this is a valid setup, the Jetty project recommends always using the link:#example-logging-java-util-logging[slf4j to java.util.logging configuration] for memory and performance reasons.
While this is a valid setup, the Jetty project recommends always using the link:#example-logging-java-util-logging[slf4j to java.util.logging configuration] for memory and performance reasons.
This native implementation is very non-performant and is not guaranteed to exist in the future.
____
@ -87,4 +86,4 @@ Other logging frameworks are more reliable in that they always initialize and co
* While it is possible to configure `java.util.logging` sooner, even at JVM startup, the example demonstrated here does not show this technique.
For more information consult the official `java.util.logging.LogManager` javadoc http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html[documentation from Oracle].
____
____

View File

@ -14,7 +14,6 @@
// 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
It is possible to have the Jetty Server logging configured so that `java.util.logging` controls the output of logging events produced by Jetty.
@ -82,4 +81,4 @@ Other logging frameworks are more reliable in that they always initialize and co
* While it is possible to configure `java.util.logging` sooner, even at JVM startup, the example demonstrated here does not show this technique.
For more information consult the official `java.util.logging.LogManager` javadoc http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html[documentation from Oracle].
____
____

View File

@ -14,10 +14,9 @@
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
[[example-logging-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.
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].
A convenient replacement `logging` module has been created to bootstrap the `${jetty.base}` directory for logging with logback.

View File

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

View File

@ -17,12 +17,12 @@
[[session-clustering-gcloud-datastore]]
=== Session Clustering with Google Cloud Datastore
Jetty can support session clustering by persisting sessions to https://cloud.google.com/datastore/docs/concepts/overview[Google Cloud Datastore].
Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the Datastore as the request exits the server.
Jetty can support session clustering by persisting sessions to https://cloud.google.com/datastore/docs/concepts/overview[Google Cloud Datastore].
Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the Datastore as the request exits the server.
Sessions must obey the Serialization contract, and servlets must call the `Session.setAttribute()` method to ensure that changes are persisted.
The persistent session mechanism works in conjunction with a load balancer that supports stickiness.
Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism.
The persistent session mechanism works in conjunction with a load balancer that supports stickiness.
Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism.
For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing.
==== Configuration
@ -36,16 +36,16 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== 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.
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.
Once you've done that, you will need to prevent jetty's startup checks from detecting the missing jars.
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.
Once you've done that, you will need to prevent jetty's startup checks from detecting the missing jars.
To do that, you can use `--skip-file-validation=glcoud-sessions` argument to start.jar on the command line, or place that line inside `${jetty.base}/start.ini` to ensure it is used for every start.
===== Configuring the GCloudSessionIdManager
The gcloud-sessions module will have installed file called `${jetty.home}/etc/jetty-gcloud-sessions.xml`.
The gcloud-sessions module will have installed file called `${jetty.home}/etc/jetty-gcloud-sessions.xml`.
This file configures an instance of the `GCloudSessionIdManager` that will be shared across all webapps deployed on that server. It looks like this:
[source, xml, subs="{sub-order}"]
@ -53,13 +53,13 @@ This file configures an instance of the `GCloudSessionIdManager` that will be sh
include::{SRCDIR}/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/jetty-gcloud-sessions.xml[]
----
You configure it by setting values for properties.
You configure it by setting values for properties.
The properties will either be inserted as commented out in your `start.ini`, or your `start.d/gcloud-sessions.ini` file, depending on how you enabled the module.
The only property you always need to set is the name of the node in the cluster:
jetty.gcloudSession.workerName::
The name that uniquely identifies this node in the cluster.
The name that uniquely identifies this node in the cluster.
This value will also be used by the sticky load balancer to identify the node.
Don't forget to change the value of this property on *each* node on which you enable gcloud datastore session clustering.
@ -95,7 +95,7 @@ Follow the instructions on the https://cloud.google.com/datastore/docs/tools/dat
===== Configuring the GCloudSessionManager
As mentioned elsewhere, there must be one `SessionManager` per context (e.g. webapp).
As mentioned elsewhere, there must be one `SessionManager` per context (e.g. webapp).
Each SessionManager needs to reference the single `GCloudSessionIdManager`.
The way you configure a `GCloudSessionManager` depends on whether you're configuring from a context xml file, a `jetty-web.xml` file or code.
@ -104,7 +104,7 @@ The basic difference is how you get a reference to the Jetty `org.eclipse.jetty.
From a context xml file, you reference the Server instance as a Ref:
[source, xml, subs="{sub-order}"]
----
----
<!-- Get a reference to the GCloudSessionIdManager -->
<Ref id="Server">
<Call id="idMgr" name="getSessionIdManager"/>
@ -152,23 +152,23 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc
The `GCloudSessionManager` supports the following configuration setters:
scavengeIntervalSec::
Time in seconds between runs of a scavenger task that looks for expired old sessions to delete.
The default is 10 minutes.
Time in seconds between runs of a scavenger task that looks for expired old sessions to delete.
The default is 10 minutes.
If set to 0, no scavenging is done.
staleIntervalSec::
The length of time a session can be in memory without being checked against the cluster.
A value of 0 indicates that the session is never checked against the cluster - the current node is considered to be the master for the session.
maxQueryResults::
The maximum number of results to return for a query to find expired sessions.
For efficiency it is important to limit the size of the result.
The default is 100.
The maximum number of results to return for a query to find expired sessions.
For efficiency it is important to limit the size of the result.
The default is 100.
If 0 or negative numbers are set, the default is used instead.
===== The gcloud-memcached-sessions module
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.
@ -191,7 +191,7 @@ If you have installed memcached on a host and port other than the defaults of `l
*Note that* you will be configuring a `GCloudMemcachedSessionManager` 'instead of' a `GCloudSessionManager`.
As usual, there must be only one per context (e.g. webapp).
As usual, there must be only one per context (e.g. webapp).
Each GCloudMemcachedSessionManager needs to reference the single `GCloudSessionIdManager`.
@ -201,7 +201,7 @@ The basic difference is how you get a reference to the Jetty `org.eclipse.jetty.
From a context xml file, you reference the Server instance as a Ref:
[source, xml, subs="{sub-order}"]
----
----
<!-- Get a reference to the GCloudSessionIdManager -->
<Ref id="Server">
<Call id="idMgr" name="getSessionIdManager"/>
@ -255,16 +255,16 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc
The `GCloudMemcachedSessionManager` supports the following configuration setters:
scavengeIntervalSec::
Time in seconds between runs of a scavenger task that looks for expired old sessions to delete.
The default is 10 minutes.
Time in seconds between runs of a scavenger task that looks for expired old sessions to delete.
The default is 10 minutes.
If set to 0, no scavenging is done.
staleIntervalSec::
The length of time a session can be in memory without being checked against the cluster.
A value of 0 indicates that the session is never checked against the cluster - the current node is considered to be the master for the session.
maxQueryResults::
The maximum number of results to return for a query to find expired sessions.
For efficiency it is important to limit the size of the result.
The default is 100.
The maximum number of results to return for a query to find expired sessions.
For efficiency it is important to limit the size of the result.
The default is 100.
If 0 or negative numbers are set, the default is used instead.
host::
The address of the host where the memcached server is running. Defaults to "localhost".

View File

@ -36,7 +36,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== 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.
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

@ -17,16 +17,16 @@
[[session-clustering-jdbc]]
=== Session Clustering with a Database
Jetty can support session clustering by persisting sessions to a shared database.
Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the database as the request exits the server.
Jetty can support session clustering by persisting sessions to a shared database.
Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the database as the request exits the server.
Sessions must obey the Serialization contract, and servlets must call the `Session.setAttribute()` method to ensure that changes are persisted.
The persistent session mechanism works in conjunction with a load balancer that supports stickiness.
Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism.
The persistent session mechanism works in conjunction with a load balancer that supports stickiness.
Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism.
For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing.
In this type of solution, the database can become both a bottleneck and a single point of failure.
Jetty takes steps to reduce the load on the database (discussed below), but in a heavily loaded environment you might need to investigate other optimization strategies such as local caching and database replication.
In this type of solution, the database can become both a bottleneck and a single point of failure.
Jetty takes steps to reduce the load on the database (discussed below), but in a heavily loaded environment you might need to investigate other optimization strategies such as local caching and database replication.
You should also consult your database vendor's documentation for information on how to ensure high availability and failover of your database.
==== Configuration
@ -40,7 +40,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== 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:
@ -56,26 +56,26 @@ jetty.jdbcSession.connectionURL=jdbc:derby:sessions;create=true
----
jetty.jdbcSession.workerName::
The name that uniquely identifies this node in the cluster.
The name that uniquely identifies this node in the cluster.
This value will also be used by the sticky load balancer to identify the node.
Don't forget to change the value of this property on *each* node on which you enable jdbc session clustering.
jetty.jdbcSession.scavenge::
The time in seconds between sweeps of a task which scavenges old expired sessions.
The default is 10 minutess.
The time in seconds between sweeps of a task which scavenges old expired sessions.
The default is 10 minutess.
Increasing the frequency is not recommended as doing so increases the load on the database with very little gain.
jetty.jdbcSession.datasource::
The name of a `javax.sql.DataSource` that gives access to the database that holds the session information.
The name of a `javax.sql.DataSource` that gives access to the database that holds the session information.
You should configure *either* this or the jdbc driver information described next.
jetty.jdbcSession.datasource and jetty.jdbcSession.connectionURL::
This is the name of the jdbc driver class, and a jdbc connection url suitable for that driver.
This is the name of the jdbc driver class, and a jdbc connection url suitable for that driver.
You should configure *either* this or the jdbc datasource name described above.
These properties are applied to the `JDBCSessionIdManager` described below.
===== Configuring the JDBCSessionIdManager
The jdbc-session module will have installed file called `$\{jetty.home}/etc/jetty-jdbc-sessions.xml`.
This file configures an instance of the `JDBCSessionIdManager` that will be shared across all webapps deployed on that server.
The jdbc-session module will have installed file called `$\{jetty.home}/etc/jetty-jdbc-sessions.xml`.
This file configures an instance of the `JDBCSessionIdManager` that will be shared across all webapps deployed on that server.
It looks like this:
[source, xml, subs="{sub-order}"]
@ -88,7 +88,7 @@ As well as uncommenting and setting up appropriate values for the properties dis
As Jetty configuration files are direct mappings of XML to Java, it is straight forward to do this in code:
[source, java, subs="{sub-order}"]
----
----
Server server = new Server();
...
JDBCSessionIdManager idMgr = new JDBCSessionIdManager(server);
@ -96,7 +96,7 @@ idMgr.setWorkerName("node1");
idMgr.setDriverInfo("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/sessions?user=janb");
idMgr.setScavengeInterval(600);
server.setSessionIdManager(idMgr);
----
====== Configuring the Database Schema
@ -108,7 +108,7 @@ The defaults used are:
[options="header"]
|===========================
|table name |JettySessionIds
|columns |id
|columns |id
|===========================
.Default Values for Session Table
@ -121,10 +121,10 @@ accessTime, lastAccessTime, createTime, cookieTime, lastSavedTime,
expiryTime, maxInterval, map
|=======================================================================
To change these values, use the link:{JDURL}/org/eclipse/jetty/server/session/SessionIdTableSchema.html[org.eclipse.jetty.server.session.SessionIdTableSchema] and link:{JDURL}/org/eclipse/jetty/server/session/SessionTableSchema.html[org.eclipse.jetty.server.session.SessionTableSchema] classes.
To change these values, use the link:{JDURL}/org/eclipse/jetty/server/session/SessionIdTableSchema.html[org.eclipse.jetty.server.session.SessionIdTableSchema] and link:{JDURL}/org/eclipse/jetty/server/session/SessionTableSchema.html[org.eclipse.jetty.server.session.SessionTableSchema] classes.
These classes have getter/setter methods for the table name and all columns.
Here's an example of changing the name of `JettySessionsId` table and its single column.
Here's an example of changing the name of `JettySessionsId` table and its single column.
This example will use java code, but as explained above, you may also do this via a Jetty xml configuration file:
[source, java, subs="{sub-order}"]
@ -137,7 +137,7 @@ idTableSchema.setIdColumn("theid");
idManager.setSessionIdTableSchema(idTableSchema);
----
In a similar fashion, you can change the names of the table and columns for the `JettySessions` table.
In a similar fashion, you can change the names of the table and columns for the `JettySessions` table.
*Note* that both the `SessionIdTableSchema` and the `SessionTableSchema` instances are set on the `JDBCSessionIdManager` class.
[source, java, subs="{sub-order}"]
@ -156,13 +156,13 @@ sessionTableSchema.setLastAccessTimeColumn("latime");
sessionTableSchema.setLastNodeColumn("lnode");
sessionTableSchema.setLastSavedTimeColumn("lstime");
sessionTableSchema.setMapColumn("mo");
sessionTableSchema.setMaxIntervalColumn("mi");
sessionTableSchema.setMaxIntervalColumn("mi");
idManager.setSessionTableSchema(sessionTableSchema);
----
===== Configuring the JDBCSessionManager
As mentioned elsewhere, there should be one `JDBCSessionManager` per context (e.g. webapp).
As mentioned elsewhere, there should be one `JDBCSessionManager` per context (e.g. webapp).
It will need to reference the single `JDBCSessionIdManager` configured previously for the Server.
The way you configure a `JDBCSessionManager` depends on whether you're configuring from a context xml file, a `jetty-web.xml` file or code.
@ -192,7 +192,7 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc
[source, xml, subs="{sub-order}"]
----
<Get name="server">
<Get id="idMgr" name="sessionIdManager"/>
</Get>
@ -216,7 +216,7 @@ If you're embedding this in code:
//assuming you have already set up the JDBCSessionIdManager as shown earlier
//and have a reference to the Server instance:
WebAppContext wac = new WebAppContext();
... //configure your webapp context
JDBCSessionManager jdbcMgr = new JDBCSessionManager();

View File

@ -17,17 +17,17 @@
[[session-clustering-mongodb]]
=== Session Clustering with MongoDB
Jetty can support session clustering by persisting sessions into http://www.mogodb.org[MongoDB].
Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the cluster as the request exits the server.
Jetty can support session clustering by persisting sessions into http://www.mogodb.org[MongoDB].
Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the cluster as the request exits the server.
Sessions must obey the Serialization contract, and servlets must call the `Session.setAttribute()` method to ensure that changes are persisted.
The session persistence mechanism works in conjunction with a load balancer that supports stickiness.
Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism.
The session persistence mechanism works in conjunction with a load balancer that supports stickiness.
Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism.
For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing.
In this type of solution, the traffic on the network needs to be carefully watched and tends to be the bottleneck.
You are probably investigating this solution in order to scale to large amount of users and sessions, so careful attention should be paid to your usage scenario.
Applications with a heavy write profile to their sessions will consume more network bandwidth than profiles that are predominately read oriented.
In this type of solution, the traffic on the network needs to be carefully watched and tends to be the bottleneck.
You are probably investigating this solution in order to scale to large amount of users and sessions, so careful attention should be paid to your usage scenario.
Applications with a heavy write profile to their sessions will consume more network bandwidth than profiles that are predominately read oriented.
We recommend using this session manager with largely read based session scenarios.
==== Configuration
@ -41,12 +41,12 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server
==== 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.
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.
If you need to up or downgrade the version of these jars, then you can delete the jars that were automatically installed and replace them.
Once you've done that, you will need to prevent Jetty's startup checks from detecting the missing jars.
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.
If you need to up or downgrade the version of these jars, then you can delete the jars that were automatically installed and replace them.
Once you've done that, you will need to prevent Jetty's startup checks from detecting the missing jars.
To do that, you can use `--skip-file-validation=nosql` argument to start.jar on the command line, or place that line inside `${jetty.base}/start.ini` to ensure it is used for every start.
You will also find the following properties, either in your base's `start.d/nosql.ini` file or appended to your `start.ini`, depending on how you enabled the module:
@ -61,8 +61,8 @@ jetty.nosqlSession.workerName=node1
jetty.nosqlSession.scavenge=1800
----
The `jetty.nosqlSession.workerName` is the unique name for this Jetty Server instance.
It will be used by the sticky load balancer to uniquely identify the node.
The `jetty.nosqlSession.workerName` is the unique name for this Jetty Server instance.
It will be used by the sticky load balancer to uniquely identify the node.
You should change this value on *each* node to which you install MongoDB session management.
The `jetty.nosqlSession.scavenge` property defines the time in seconds between runs of the scavenger: the scavenger is a task which runs periodically to clean out sessions that have expired but become stranded in the database for whatever reason.
@ -71,8 +71,8 @@ These properties are substituted into the configuration of the `MongoDBSessionId
===== Configuring the MongoSessionIdManager
The nosql module will have installed file called `$\{jetty.home}/etc/jetty-nosql.xml`.
This file configures an instance of the `MongoSessionIdManager` that will be shared across all webapps deployed on that server.
The nosql module will have installed file called `$\{jetty.home}/etc/jetty-nosql.xml`.
This file configures an instance of the `MongoSessionIdManager` that will be shared across all webapps deployed on that server.
It looks like this:
[source, xml, subs="{sub-order}"]
@ -80,8 +80,8 @@ It looks like this:
include::{SRCDIR}/jetty-nosql/src/main/config/etc/jetty-nosql.xml[]
----
The `MongoSessionIdManager` needs access to a MongoDB cluster, and the `jetty-nosql.xml` file assumes the defaults of localhost and default MongoDB port.
If you need to configure something else, you will need to edit this file.
The `MongoSessionIdManager` needs access to a MongoDB cluster, and the `jetty-nosql.xml` file assumes the defaults of localhost and default MongoDB port.
If you need to configure something else, you will need to edit this file.
Here's an example of a more complex setup to use a remote MongoDB instance:
[source, xml, subs="{sub-order}"]
@ -122,31 +122,31 @@ Here's an example of a more complex setup to use a remote MongoDB instance:
<Set name="scavengePeriod"><Property name="jetty.nosqlSession.scavenge" default="1800"/></Set>
</New>
</Set>
----
As Jetty configuration files are direct mappings of XML to Java, it is straight forward to do this in code:
[source, java, subs="{sub-order}"]
----
Server server = new Server();
...
MongoSessionIdManager idMgr = newMongoSessionIdManager(server);
idMgr.setWorkerName("node1");
idMgr.setScavengePeriod(1800);
server.setSessionIdManager(idMgr);
----
The MongoSessionIdManager has slightly different options than some of our more traditional session options.
The `MongoDBSessionIdManager` has the same scavenge timers which govern the setting of a valid session to invalid after a certain period of inactivity.
New to this session id manager is the extra purge setting which governs removal from the MongoDB cluster.
This can be configured through the 'purge' option. Purge is by default set to true and by default runs daily for each node on the cluster.
Also able to be configured is the age in which an invalid session will be retained which is set to 1 day by default.
This means that invalid sessions will be removed after lingering in the MongoDB instance for a day.
There is also an option for purging valid sessions that have not been used recently.
The MongoSessionIdManager has slightly different options than some of our more traditional session options.
The `MongoDBSessionIdManager` has the same scavenge timers which govern the setting of a valid session to invalid after a certain period of inactivity.
New to this session id manager is the extra purge setting which governs removal from the MongoDB cluster.
This can be configured through the 'purge' option. Purge is by default set to true and by default runs daily for each node on the cluster.
Also able to be configured is the age in which an invalid session will be retained which is set to 1 day by default.
This means that invalid sessions will be removed after lingering in the MongoDB instance for a day.
There is also an option for purging valid sessions that have not been used recently.
The default time for this is 1 week. You can disable these behaviors by setting purge to false.
scavengeDelay::
@ -154,8 +154,8 @@ scavengeDelay::
scavengePeriod::
How much time after a scavenge has completed should you wait before doing it again?
scavengeBlockSize::
Number of session ids to which to limit each scavenge query.
If you have a very large number of sessions in memory then setting this to a non 0 value may help speed up scavenging by breaking the scavenge into multiple, queries.
Number of session ids to which to limit each scavenge query.
If you have a very large number of sessions in memory then setting this to a non 0 value may help speed up scavenging by breaking the scavenge into multiple, queries.
The default is 0, which means that all session ids are considered in a single query.
purge (Boolean)::
Do you want to purge (delete) sessions that are invalid from the session store completely?
@ -164,11 +164,11 @@ purgeDelay::
purgeInvalidAge::
How old should an invalid session be before it is eligible to be purged?
purgeValidAge::
How old should a valid session be before it is eligible to be marked invalid and purged?
How old should a valid session be before it is eligible to be marked invalid and purged?
Should this occur at all?
purgeLimit::
Integer value that represents how many items to return from a purge query.
The default is 0, which is unlimited.
Integer value that represents how many items to return from a purge query.
The default is 0, which is unlimited.
If you have a lot of old expired orphaned sessions then setting this value may speed up the purge process.
preserveOnStop::
Whether or not to retain all sessions when the session manager stops.
@ -176,16 +176,16 @@ preserveOnStop::
===== Configuring a MongoSessionManager
As mentioned elsewhere, there should be one `MongoSessionManager` per context (e.g. webapp).
As mentioned elsewhere, there should be one `MongoSessionManager` per context (e.g. webapp).
It will need to reference the single `MongoSessionIdManager` configured previously for the Server.
The way you configure a link:{JDURL}/org/eclipse/jetty/nosql/MongoSessionManager.html[org.eclipse.jetty.nosql.mongodb.MongoSessionManager] depends on whether you're configuring from a link:#deployable-descriptor-file[context xml] file or a link:#jetty-web-xml-config[jetty-web.xml] file or code.
The way you configure a link:{JDURL}/org/eclipse/jetty/nosql/MongoSessionManager.html[org.eclipse.jetty.nosql.mongodb.MongoSessionManager] depends on whether you're configuring from a link:#deployable-descriptor-file[context xml] file or a link:#jetty-web-xml-config[jetty-web.xml] file or code.
The basic difference is how you get a reference to the Jetty `org.eclipse.jetty.server.Server` instance.
From a context xml file, you reference the Server instance as a Ref:
[source, xml, subs="{sub-order}"]
----
----
<Ref name="Server" id="Server">
<Call id="mongoIdMgr" name="getSessionIdManager"/>
</Ref>
@ -229,7 +229,7 @@ If you're embedding this in code:
----
//assuming you have already set up the MongoSessionIdManager as shown earlier
//and have a reference to the Server instance:
WebAppContext wac = new WebAppContext();
... //configure your webapp context
MongoSessionManager mongoMgr = new MongoSessionManager();

View File

@ -16,12 +16,15 @@
[[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.
[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
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.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
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.
Additionally a `${jetty.base}/sessions` directory was created.
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:
@ -49,12 +52,12 @@ Opening the `start.d/session-store-file.ini` will show a list of all the configu
# ---------------------------------------
--module=session-store-file
jetty.session.storeDir=${jetty.base}/sessions
#jetty.session.deleteUnrestorableFiles=false
jetty.session.file.storeDir=${jetty.base}/sessions
#jetty.session.file.deleteUnrestorableFiles=false
----
jetty.session.storeDir::
This defines the location for storage of Session files.
jetty.session.deleteUnrestorableFiles::
jetty.session.file.deleteUnrestorableFiles::
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.

View File

@ -15,26 +15,71 @@
// ========================================================================
[[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.
[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
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
+ 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: session-store-gcloud
+ 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
Module: session-store-gcloud
+ 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
Proceed (y/N)? y
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
@ -79,11 +124,11 @@ WARN : Module session-store-gcloud requires jcl-api from one of [jcl, jcl-slf4j]
WARN : Unsatisfied module dependencies: session-store-gcloud,session-store-gcloud
Usage: java -jar $JETTY_HOME/start.jar [options] [properties] [configs]
java -jar $JETTY_HOME/start.jar --help # for more information
java -jar $JETTY_HOME/start.jar --help # for more information
----
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).
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.
@ -94,13 +139,13 @@ $ java -jar ../start.jar --add-to-start=jcl
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
+ 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
+ Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html
Module: jcl
+ Log4j is released under the Apache 2.0 license.
+ http://www.apache.org/licenses/LICENSE-2.0.html
Proceed (y/N)? y
INFO : jcl initialised in ${jetty.base}/start.d/jcl.ini
@ -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.
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]
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}"]
----
@ -128,13 +173,23 @@ Opening the `start.d/session-store-gcloud.ini` will show a list of all the confi
## GCloudDatastore Session config
#jetty.gcloudSession.maxRetries=5
#jetty.gcloudSession.backoffMs=1000
#jetty.session.gcloud.maxRetries=5
#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.
jetty.gcloudSession.backoffMs::
jetty.session.gcloud.backoffMs::
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 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.
[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
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.
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).
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.
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]
@ -66,18 +69,20 @@ Opening the `start.d/session-store-infinispan-remote.ini` will show a list of al
# ---------------------------------------
--module=session-store-infinispan-remote
#jetty.session.remoteInfinispanCache.name=sessions
#jetty.session.infinispanIdleTimeout.seconds=0
#jetty.session.infinispan.remoteCacheName=sessions
#jetty.session.infinispan.idleTimeout.seconds=0
#jetty.session.gracePeriod.seconds=3600
----
jetty.session.remoteInfinispanCache.name::
jetty.session.infinispanIdleTimeout.seconds::
jetty.session.infinispan.remoteCacheName::
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::
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.
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.
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).
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.
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 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.
[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
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.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.
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.
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:
@ -52,49 +55,40 @@ Opening the `start.d/session-store-jdbc.ini` will show a list of all the configu
## Connection type:Datasource
db-connection-type=datasource
#jetty.session.datasourceName=/jdbc/sessions
#jetty.session.jdbc.datasourceName=/jdbc/sessions
## Connection type:driver
#db-connection-type=driver
#jetty.session.driverClass=
#jetty.session.driverUrl=
#jetty.session.jdbc.driverClass=
#jetty.session.jdbc.driverUrl=
## Session table schema
#jetty.sessionTableSchema.accessTimeColumn=accessTime
#jetty.sessionTableSchema.contextPathColumn=contextPath
#jetty.sessionTableSchema.cookieTimeColumn=cookieTime
#jetty.sessionTableSchema.createTimeColumn=createTime
#jetty.sessionTableSchema.expiryTimeColumn=expiryTime
#jetty.sessionTableSchema.lastAccessTimeColumn=lastAccessTime
#jetty.sessionTableSchema.lastSavedTimeColumn=lastSavedTime
#jetty.sessionTableSchema.idColumn=sessionId
#jetty.sessionTableSchema.lastNodeColumn=lastNode
#jetty.sessionTableSchema.virtualHostColumn=virtualHost
#jetty.sessionTableSchema.maxIntervalColumn=maxInterval
#jetty.sessionTableSchema.mapColumn=map
#jetty.sessionTableSchema.table=JettySessions
#jetty.session.jdbc.schema.accessTimeColumn=accessTime
#jetty.session.jdbc.schema.contextPathColumn=contextPath
#jetty.session.jdbc.schema.cookieTimeColumn=cookieTime
#jetty.session.jdbc.schema.createTimeColumn=createTime
#jetty.session.jdbc.schema.expiryTimeColumn=expiryTime
#jetty.session.jdbc.schema.lastAccessTimeColumn=lastAccessTime
#jetty.session.jdbc.schema.lastSavedTimeColumn=lastSavedTime
#jetty.session.jdbc.schema.idColumn=sessionId
#jetty.session.jdbc.schema.lastNodeColumn=lastNode
#jetty.session.jdbc.schema.virtualHostColumn=virtualHost
#jetty.session.jdbc.schema.maxIntervalColumn=maxInterval
#jetty.session.jdbc.schema.mapColumn=map
#jetty.session.jdbc.schema.table=JettySessions
----
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.
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::
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::
The `jetty.sessionTableSchema` values represent the names for the columns in the JDBC database and can be changed to suit your environment.

View File

@ -16,12 +16,15 @@
[[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.
[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
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.
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).
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.
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]
@ -65,14 +68,20 @@ Opening the `start.d/session-store-mongo.ini` will show a list of all the config
# ---------------------------------------
--module=session-store-mongo
#jetty.session.dbName=HttpSessions
#jetty.session.collectionName=jettySessions
#jetty.session.mongo.dbName=HttpSessions
#jetty.session.mongo.collectionName=jettySessions
#jetty.session.mongo.host=localhost
#jetty.session.mongo.port=27017
#jetty.session.gracePeriod.seconds=3600
----
jetty.session.dbName::
jetty.session.mongo.dbName::
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.
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::
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.
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:
image::images/SessionsHierarchy.png[]
==== 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.
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::start-jar.adoc[]
include::startup-base-vs-home.adoc[]
include::startup-xml-config.adoc[]
include::startup-classpath.adoc[]
include::startup-modules.adoc[]
include::startup-xml-config.adoc[]
include::startup-unix-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.
For information on logging, please see the section on <<configuring-jetty-logging, Configuring Jetty Logging.>>
--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}`.
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::
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].
+
Also lists enabled state based on information present on the command line, and all active startup INI files.
--module=<name>,(<name>)*::
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.
+
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.`
--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>)*::
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.
+
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]
--
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.
Please see link:#start-vs-startd[Start.ini vs. Start.d] for more information.
--
--write-module-graph=<filename>::

View File

@ -17,7 +17,7 @@
[[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/`.
@ -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.
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::
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.
The `[ini-template]` section declares this section of sample configuration.
Required Files and Directories::
@ -62,15 +62,15 @@ Download File;;
[[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]
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.
____
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.
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.
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]]
==== Configuring Modules
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.
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 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.
When a module is activated, a number of properties are set by default.
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
* Tune the link:garbage-collection.html#examples[Garbage Collection]
* Tune the link:#tuning-examples[Garbage Collection]
* Allocate sufficient memory
* Use the -server option
* 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].
* 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.
===== 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]
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.
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:
[source, java, subs="{sub-order}"]
----
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setExcludeCipherSuites(
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
"^.*_(MD5|SHA|SHA1)$");
----
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 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 the Jetty SslContextFactory
@ -401,52 +648,17 @@ setExcludeProtocols / setIncludeProtocols::
____
[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.
Be aware that each Include / Exclude list has a Set method (replace the list) or Add method (append the list).
____
____
[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.
____
==== 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
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.
If you used the `--add-to-start` command, this configuration is in the `start.ini` file.
If you used the `--add-to-startd` command instead, this configuration is in the `start.d/setuid.ini` file instead.
If your server instance has a `${jetty.base/start.d}` directory, 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:
+

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.
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.
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.
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
To use quickstart the module has to be available to the Jetty instance.
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:
===== Prerequisites
====== Jetty Distribution
In a standard Jetty distribution the quickstart module can be configured with the following command:
[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`.
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:
====== Embedded
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}"]
----
<?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">
<Set name="war"><Property name="jetty.webapps" default="."/>/benchmark.war</Set>
<Set name="contextPath">/benchmark</Set>
<Set name="autoPreconfigure">true</Set>
</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
//
// 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:
//
// [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.
// 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

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]:
[source,bash]
----
java -jar start.jar --add-to-startd=jaas
----
[source, screen, subs="{sub-order}"]
....
java -jar start.jar --add-to-start=jaas
....
____
[NOTE]

View File

@ -28,7 +28,7 @@ For example:
[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.
@ -42,7 +42,7 @@ The following is an example mimicking the default jetty startup configuration.
[source, xml, subs="{sub-order}"]
----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
@ -98,5 +98,5 @@ The following is an example mimicking the default jetty startup configuration.
</bean>
</beans>
----

View File

@ -723,6 +723,7 @@ mvn jetty:stop
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.
[[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`).

View File

@ -32,9 +32,9 @@ To start Jetty on the default port of 8080, run the following command:
2015-06-04 10:50:45.030:INFO:oejs.Server:main: Started @558ms
----
You can point a browser at this server at link:http://localhost:8080[].
However, as there are no webapps deployed in the $JETTY_HOME directory, you will see a 404 error page served by Jetty.
*Note* the HomeBase warning - it is _not_ recommended to run Jetty from the $JETTY_HOME directory.
You can point a browser at this server at link:http://localhost:8080[].
However, as there are no webapps deployed in the $JETTY_HOME directory, you will see a 404 error page served by Jetty.
*Note* the HomeBase warning - it is _not_ recommended to run Jetty from the $JETTY_HOME directory.
Instead, see how to link:#creating-jetty-base[create a Jetty Base] below.
[[demo-webapps-base]]
@ -89,15 +89,15 @@ You can see the configuration of the demo-base by using the following commands:
...
----
The `--list-modules` command will return a complete list of available and enabled modules for the server.
It will also display the location of the modules, how and in what order they are implemented, dependent modules, and associated jar files.
The `--list-modules` command will return a complete list of available and enabled modules for the server.
It will also display the location of the modules, how and in what order they are implemented, dependent modules, and associated jar files.
The `--list-config` command displays a trove of information about the server including the Java and Jetty environments, the configuration order, any JVM arguments or System Properties set, general server properties, a full listing of the Jetty server class path, and active Jetty XML files.
[[creating-jetty-base]]
==== Creating a new Jetty Base
The `demo-base` directory described above is an example of the link:#startup-base-and-home[jetty.base] mechanism added in Jetty 9.1.
A Jetty base directory allows the configuration and web applications of a server instance to be stored separately from the Jetty distribution, so that upgrades can be done with minimal disruption.
The `demo-base` directory described above is an example of the link:#startup-base-and-home[jetty.base] mechanism added in Jetty 9.1.
A Jetty base directory allows the configuration and web applications of a server instance to be stored separately from the Jetty distribution, so that upgrades can be done with minimal disruption.
Jetty's default configuration is based on two properties:
jetty.home::
@ -127,7 +127,9 @@ WARNING: Nothing to start, exiting ...
Usage: java -jar start.jar [options] [properties] [configs]
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: http initialised in ${jetty.base}/start.d/http.ini
@ -163,7 +165,7 @@ You can configure Jetty to run on a different port by setting the `jetty.http.po
...
----
Alternatively, property values can be added to the effective command line built from either the `start.ini` file or `start.d/http.ini` files.
Alternatively, property values can be added to the effective command line built from either the `start.ini` file or `start.d/http.ini` files.
By default, the Jetty distribution defines the `jetty.http.port` property in the `start.d/http.ini` file, which may be edited to set another value.
____
@ -186,7 +188,7 @@ To add HTTPS and HTTP2 connectors to a Jetty configuration, the modules can be a
[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
@ -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/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.
* 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]]
===== Changing the Jetty HTTPS Port
@ -220,13 +217,12 @@ 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
----
Alternatively, property values can be added to the effective command line built from the `start.ini` file and `start.d/*.ini` files.
If you used the `--add-to-startd` command to enable HTTPS , then you can edit this property in the `start.d/https.ini` file.
If you used `--add-to-start` command, then you can edit this property in the `start.ini` file.
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.
Please see the section on link:#start-vs-startd[Start.ini vs. Start.d] for more information.
==== More start.jar options
The job of the `start.jar` is to interpret the command line, `start.ini` and `start.d` directory (and associated .ini files) to build a Java classpath and list of properties and configuration files to pass to the main class of the Jetty XML configuration mechanism.
The job of the `start.jar` is to interpret the command line, `start.ini` and `start.d` directory (and associated .ini files) to build a Java classpath and list of properties and configuration files to pass to the main class of the Jetty XML configuration mechanism.
The `start.jar` mechanism has many options which are documented in the xref:startup[] administration section and you can see them in summary by using the command:
[source, screen, subs="{sub-order}"]

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
|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
|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
|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

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}"]
----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
..
</Configure>
----
____

View File

@ -53,7 +53,7 @@ The following XML configuration file creates some Java objects and sets some att
<Set name="name">demo2</Set>
</Get>
</Ref>
</Configure>
</Configure>
----
The XML above is equivalent to the following Java code:
@ -72,7 +72,7 @@ bar.init(false);
foo.setNested(bar);
bar.setWibble(20);
bar.getParent().setName("demo2");
bar.getParent().setName("demo2");
----
==== Overview
@ -80,41 +80,27 @@ bar.getParent().setName("demo2");
===== Understanding DTD and Parsing
The document type descriptor
(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. The first two lines of an XML must reference the DTD
to be used to validate the XML like:
(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.
The first two lines of an XML must reference the DTD to be used to validate the XML like:
[source, xml, subs="{sub-order}"]
----
<?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">
...
----
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. 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.
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.
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.
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.
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.
===== Jetty XML Configuration Scope
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. The outer
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
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.
The outer 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}"]
----
@ -134,50 +120,36 @@ to explain the scope
<Call name="methodOnObjectReturnedByMethodOnFooWithNoArgs"/>
</Call>
</Configure>
----
===== Coercing Arguments to a Type
When trying to match XML elements to java elements, Jetty
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. 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
When trying to match XML elements to java elements, Jetty `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.
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`.
===== Referring to a Class
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). 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).
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).
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
You can use the id attribute to store a reference to the current object
when first creating or referring to this object. You can then use the
link:#jetty-xml-ref[Ref element] to reference the object later. The id
must be unique for each object you create.
You can use the id attribute to store a reference to the current object when first creating or referring to this object.
You can then use the link:#jetty-xml-ref[Ref element] to reference the object later.
The ID must be unique for each object you create.
===== Attribute vs Element Style
For XML elements that contain only other XML Elements, there is a choice
of using attributes or elements style. The following is an example of
attribute style:
For XML elements that contain only other XML Elements, there is a choice of using attributes or elements style.
The following is an example of attribute style:
....
<Call id="result" class="org.example.SomeClass" name="someMethod" arg="value0,value1"/>
....
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. Thus the more verbose element style is available and the
following is semantically equivalent to the attribute style above:
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.
Thus, the more verbose element style is available and the following is semantically equivalent to the attribute style above:
....
<Call>
@ -189,11 +161,8 @@ following is semantically equivalent to the attribute style above:
</Call>
....
Note that multivalued elements like Arg, must be repeated and may not be
comma separated like they are when provided as attributes. It is
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:
Note that multivalued elements like `Arg` must be repeated and may not be comma-separated like they are when provided as attributes.
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:
....
<Call id="result" name="someMethod">
@ -205,16 +174,14 @@ style:
</Call>
....
Attributes may not be expressed as elements when their parent element is
one that contains data. Thus Arg, Item, Set, Put and Get elements may
not have their attributes expressed as elements.
Attributes may not be expressed as elements when their parent element is one that contains data.
Thus `Arg`, `Item`, `Set`, `Put` and `Get` elements may not have their attributes expressed as elements.
[[jetty-xml-configure]]
==== <Configure>
This is the root element that specifies the class of object that is to
be configured. It is usually either the Server, in `jetty.xml`, or a
WebAppContext in `jetty-web.xml`.
This is the root element that specifies the class of object that is to be configured.
It is usually either the Server, in `jetty.xml`, or a `WebAppContext` in `jetty-web.xml`.
[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.
|class |no |The fully qualified classname of the object to be
configured. Could be org.eclipse.jetty.server.Server,
org.eclipse.jetty.webapp.WebAppContext, a handler, etc.
configured. Could be `org.eclipse.jetty.server.Server`,
`org.eclipse.jetty.webapp.WebAppContext`, a handler, etc.
|=======================================================================
===== Can Contain
@ -246,7 +213,7 @@ link:#jetty-xml-property[Property element]
----
<Configure class="org.eclipse.jetty.server.Server">
<Set name="port">8080</Set>
</Configure>
</Configure>
----
This is equivalent to:
@ -254,46 +221,43 @@ This is equivalent to:
[source, java, subs="{sub-order}"]
----
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
files
====== Using id to break up configuration of one object across multiple files
(etc/jetty.xml)
In `etc/jetty.xml`:
[source, xml, subs="{sub-order}"]
----
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- basic configuration here -->
</Configure>
</Configure>
----
(etc/jetty-logging.xml)
In `etc/jetty-logging.xml`:
[source, xml, subs="{sub-order}"]
----
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- assumes that you have the basic server configuration set up; this file only contains additional configuration for logging -->
</Configure>
</Configure>
----
Then run the combined configuration using:
....
java -jar start.jar etc/jetty.xml jetty-logging.xml
java -jar start.jar etc/jetty.xml jetty-logging.xml
....
[[jetty-xml-set]]
==== <Set>
A Set element maps to a call to a setter method or field on the current
object. It can contain text and/or elements such as Call, New,
SystemProperty, etc., as values. The name and optional type attributes
are used to select the setter method. If you do not specify a value
type, white space is trimmed out of the value. If it contains multiple
elements as values, they are added as strings before being converted to
any specified type.
A Set element maps to a call to a setter method or field on the current object.
It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc., as values.
The name and optional type attributes are used to select the setter method.
If you do not specify a value type, white space is trimmed out of the value.
If it contains multiple elements as values, they are added as strings before being converted to any specified type.
[cols=",,",options="header",]
|=======================================================================
@ -325,7 +289,7 @@ link:#jetty-xml-property[Property element]
----
<Configure id="server" class="org.eclipse.jetty.server.Server">
<Set name="port">8080</Set>
</Configure>
</Configure>
----
====== Set via a System Property
@ -334,7 +298,7 @@ link:#jetty-xml-property[Property element]
----
<Configure id="server" class="org.eclipse.jetty.server.Server">
<Set name="port"><SystemProperty name="jetty.http.port" /></Set>
</Configure>
</Configure>
----
====== Creating a NewObject and Setting It on the Server
@ -348,7 +312,7 @@ link:#jetty-xml-property[Property element]
<Set name="maxThreads">1000</Set>
</New>
</Set>
</Configure>
</Configure>
----
This is equivalent to:
@ -361,7 +325,7 @@ org.eclipse.jetty.util.thread.QueuedThreadPool threadPool = new org.eclipse.jett
threadPool.setMinThreads(10);
threadPool.setMaxThreads(1000);
server.setThreadPool(threadPool);
server.setThreadPool(threadPool);
----
====== Invoking a Static Setter
@ -370,15 +334,14 @@ server.setThreadPool(threadPool);
----
<Configure id="server" class="org.eclipse.jetty.server.Server">
<Set class="org.eclipse.jetty.util.log.Log" name="logToParent">loggerName</Set>
</Configure">
</Configure>
----
[[jetty-xml-get]]
==== <Get>
A Get element maps to a call to a getter method or field on the current
object. It can contain nested elements such as Set, Put, Call, etc.;
these act on the object returned by the Get call.
A Get element maps to a call to a getter method or field on the current object.
It can contain nested elements such as `Set`, `Put`, `Call`, etc.; these act on the object returned by the `Get` call.
[cols=",,",options="header",]
|=======================================================================
@ -406,14 +369,14 @@ link:#jetty-xml-property[Property element]
====== Basic Example
This simple example doesn't do much on its own. You would normally use
this in conjunction with a <Ref id="Logger" />.
This simple example doesn't do much on its own.
You would normally use this in conjunction with a `<Ref id="Logger" />`.
[source, xml, subs="{sub-order}"]
----
<Configure id="server" class="org.eclipse.jetty.server.Server">
<Get id="Logger" class="org.eclipse.jetty.util.log.Log" name="log"/>
</Configure>
</Configure>
----
====== Invoking a Static Getter and Call Methods on the Returned Object
@ -426,18 +389,16 @@ this in conjunction with a <Ref id="Logger" />.
<Arg>Server version is: <Get class="org.eclipse.jetty.server.Server" name="version"/></Arg>
</Call>
</Get>
</Configure>
</Configure>
----
[[jetty-xml-put]]
==== <Put>
A Put element maps to a call to a put method on the current object,
which must implement the Map interface. It can contain text and/or
elements such as Call, New, SystemProperty, etc. as values. If you do
not specify a no value type, white space is trimmed out of the value. If
it contains multiple elements as values, they are added as strings
before being converted to any specified type.
A Put element maps to a call to a put method on the current object, which must implement the Map interface.
It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc. as values.
If you do not specify a no value type, white space is trimmed out of the value.
If it contains multiple elements as values, they are added as strings before being converted to any specified type.
[cols=",,",options="header",]
|=======================================================================
@ -450,7 +411,7 @@ Arg for how to define null and empty string values.
===== 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-array[Array element], link:#jetty-xml-map[Map
element], link:#jetty-xml-system-property[System Property element],
@ -462,17 +423,15 @@ link:#jetty-xml-property[Property element]
----
<Get name="someKindOfMap">
<Put name="keyName">objectValue</Put>
</Get>
</Get>
----
[[jetty-xml-call]]
==== <Call>
A Call element maps to an arbitrary call to a method on the current
object. It can contain a sequence of Arg elements followed by a sequence
of configuration elements, such as Set, Put, Call. The <Arg>s are passed
as arguments to the method; the sequence of configuration elements act
on the object returned by the original call.
A `Call` element maps to an arbitrary call to a method on the current object.
It can contain a sequence of Arg elements followed by a sequence of configuration elements, such as Set, Put, Call.
The <Arg>s are passed as arguments to the method; the sequence of configuration elements act on the object returned by the original call.
[cols=",,",options="header",]
|=======================================================================
@ -507,7 +466,7 @@ element], link:#jetty-xml-property[Property element]
<Call name="doFoo">
<Arg>bar</Arg>
<Set name="test">1, 2, 3</Set>
</Call>
</Call>
----
This is equivalent to:
@ -515,7 +474,7 @@ This is equivalent to:
[source, java, subs="{sub-order}"]
----
Object o2 = o1.doFoo("bar");
o2.setTest("1, 2, 3");
o2.setTest("1, 2, 3");
----
====== Invoking a static method
@ -524,14 +483,14 @@ o2.setTest("1, 2, 3");
----
<Call class="com.acme.Foo" name="setString">
<Arg>somestring</Arg>
</Call>
</Call>
----
which is equivalent to:
Which is equivalent to:
[source, java, subs="{sub-order}"]
----
com.acme.Foo.setString("somestring");
com.acme.Foo.setString("somestring");
----
====== Invoking the Actual MethodInstead of Relying on Getter/Setter Magic
@ -545,15 +504,15 @@ com.acme.Foo.setString("somestring");
<Ref refid="port"/>
</Arg>
</Call>
</Configure>
</Configure>
----
which is equivalent to:
Which is equivalent to:
[source, java, subs="{sub-order}"]
----
org.mortbay.jetty.Server server = new org.mortbay.jetty.Server();
com.acme.Environment.setPort( server.getPort() );
com.acme.Environment.setPort( server.getPort() );
----
[[jetty-xml-arg]]
@ -562,13 +521,11 @@ com.acme.Environment.setPort( server.getPort() );
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[].
It can contain text and/or elements, such as Call, New, SystemProperty,
etc., as values. The optional type attribute can force the type of the
value. If you don't specify a type, white space is trimmed out of the
value. If it contains multiple elements as values, they are added as
strings before being converted to any specified type. Simple String
arguments can also be specified as a string separated arg attribute on
the parent element.
It can contain text and/or elements, such as `Call`, `New`, `SystemProperty`, etc., as values.
The optional type attribute can force the type of the value.
If you don't specify a type, white space is trimmed out of the value.
If it contains multiple elements as values, they are added as strings before being converted to any specified type.
Simple `String` arguments can also be specified as a string separated arg attribute on the parent element.
[cols=",,",options="header",]
|=======================================================================
@ -597,7 +554,7 @@ link:#jetty-xml-property[Property element]
<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></Arg> <!-- null value -->
<Arg type="String"></Arg> <!-- empty string "" ->
<Arg type="String"></Arg> <!-- empty string "" -->
----
====== Coercing Type
@ -606,13 +563,12 @@ This explicitly coerces the type to a boolean:
[source, xml, subs="{sub-order}"]
----
<Arg type="boolean">False</Arg>
<Arg type="boolean">False</Arg>
----
====== As a Parameter
Here are a couple of examples of link:#jetty-xml-arg[Arg element] being
used as a parameter to methods and to constructors:
Here are a couple of examples of link:#jetty-xml-arg[Arg element] being used as a parameter to methods and to constructors:
[source, xml, subs="{sub-order}"]
----
@ -622,14 +578,14 @@ used as a parameter to methods and to constructors:
<Arg>bar</Arg>
</New>
</Arg>
</Call>
</Call>
----
This is equivalent to:
[source, java, subs="{sub-order}"]
----
com.acme.Environment.setFoo(new com.acme.Foo("bar"));
com.acme.Environment.setFoo(new com.acme.Foo("bar"));
----
[source, xml, subs="{sub-order}"]
@ -640,26 +596,24 @@ com.acme.Environment.setFoo(new com.acme.Foo("bar"));
<Arg>2</Arg>
</Call>
</Arg>
</New>
</New>
----
This is equivalent to:
[source, java, subs="{sub-order}"]
----
new com.acme.Baz(com.acme.MyStaticObjectFactory.createObject(2));
new com.acme.Baz(com.acme.MyStaticObjectFactory.createObject(2));
----
[[jetty-xml-new]]
==== <New>
Instantiates an object. Equivalent to new in Java, and allows the
creation of a new object. 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). link:#jetty-xml-arg[Arg
element]'s are used to select a constructor for the object to be
created. The sequence of configuration elements then acts on the
newly-created object.
Instantiates an object.
Equivalent to `new` in Java, and allows the creation of a new object.
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).
link:#jetty-xml-arg[`Arg` element]'s are used to select a constructor for the object to be created.
The sequence of configuration elements then acts on the newly-created object.
[cols=",,",options="header",]
|=======================================================================
@ -691,28 +645,28 @@ element], link:#jetty-xml-property[Property element]
----
<New class="com.acme.Foo">
<Arg>bar</Arg>
</New>
</New>
----
which is equivalent to:
Which is equivalent to:
[source, java, subs="{sub-order}"]
----
com.acme.Foo foo = new com.acme.Foo("bar");
com.acme.Foo foo = new com.acme.Foo("bar");
----
====== Instantiate with the Default Constructor
[source, xml, subs="{sub-order}"]
----
<New class="com.acme.Foo" />
<New class="com.acme.Foo" />
----
which is equivalent to:
Which is equivalent to:
[source, java, subs="{sub-order}"]
----
com.acme.Foo foo = new com.acme.Foo();
com.acme.Foo foo = new com.acme.Foo();
----
====== Instantiate with Multiple Arguments, Then Configuring Further
@ -723,10 +677,10 @@ com.acme.Foo foo = new com.acme.Foo();
<Arg>bar</Arg>
<Arg>baz</Arg>
<Set name="test">1, 2, 3</Set>
</New>
</New>
----
which is equivalent to:
Which is equivalent to:
[source, java, subs="{sub-order}"]
----
@ -737,17 +691,14 @@ foo.setTest("1, 2, 3");
[[jetty-xml-ref]]
==== <Ref>
A Ref element allows a previously created object to be referenced by a
unique id. It can contain a sequence of elements, such as Set or Put
which then act on the referenced object. You can also use a Ref element
as a value for other elements such as Set and Arg.
A `Ref` element allows a previously created object to be referenced by a unique id.
It can contain a sequence of elements, such as `Set` or `Put` which then act on the referenced object.
You can also use a `Ref` element as a value for other elements such as `Set` and `Arg`.
The Ref element provides convenience and eases readability. You can
usually achieve the effect of the Ref by nesting elements (method
calls), but this can get complicated very easily. 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 also makes it possible to
split up configuration across multiple files.
The `Ref` element provides convenience and eases readability.
You can usually achieve the effect of the `Ref` by nesting elements (method calls), but this can get complicated very easily.
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 also makes it possible to split up configuration across multiple files.
[cols=",,",options="header",]
|=======================================================================
@ -768,13 +719,12 @@ link:#jetty-xml-property[Property element]
====== Basic example
Use the referenced object as an argument to a method call or
constructor:
Use the referenced object as an argument to a method call or constructor:
[source, xml, subs="{sub-order}"]
----
<Get id="foo" name="xFoo" />
<Set name="test"><Ref refid="foo"/></Set>
<Set name="test"><Ref refid="foo"/></Set>
----
This is equivalent to:
@ -782,7 +732,7 @@ This is equivalent to:
[source, java, subs="{sub-order}"]
----
foo = getXFoo();
setSomeMethod(foo);
setSomeMethod(foo);
----
====== Manipulating the Object Returned by Ref
@ -792,7 +742,7 @@ setSomeMethod(foo);
<Get id="foo" name="xFoo" />
<Ref refid="foo">
<Set name="test">1, 2, 3</Set>
</Ref>
</Ref>
----
This is equivalent to:
@ -800,13 +750,13 @@ This is equivalent to:
[source, java, subs="{sub-order}"]
----
foo = getXFoo();
foo.setTest("1, 2, 3");
foo.setTest("1, 2, 3");
----
====== Ref vs. Nested Elements
Here is an example of the difference in syntax between using the Ref
element, and nesting method calls. They are exactly equivalent:
Here is an example of the difference in syntax between using the `Ref` element, and nesting method calls.
They are exactly equivalent:
[source, xml, subs="{sub-order}"]
----
@ -822,11 +772,10 @@ element, and nesting method calls. They are exactly equivalent:
<Get class="org.eclipse.jetty.util.log.Log" name="log">
<Set name="debugEnabled">true</Set>
</Get>
</Configure>
</Configure>
----
Here is a more practical example, taken from the handler configuration
section in ` etc/jetty.xml`:
Here is a more practical example, taken from the handler configuration section in `etc/jetty.xml`:
[source, xml, subs="{sub-order}"]
----
@ -862,13 +811,13 @@ section in ` etc/jetty.xml`:
<!-- configure the RequestLogHandler object ("RequestLog") that we created earlier -->
<Ref refid="RequestLog">
....
</Ref>
</Ref>
----
[[jetty-xml-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",]
|==================================================================
@ -895,13 +844,13 @@ This is equivalent to:
[source, java, subs="{sub-order}"]
----
String[] a = new String[] { "value0", new String("value1") };
String[] a = new String[] { "value0", new String("value1") };
----
[[jetty-xml-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",]
|=======================================================================
@ -921,8 +870,7 @@ link:#jetty-xml-property[Property element]
[[jetty-xml-map]]
==== <Map>
A Map element allows the creation of a new HashMap and to populate it
with (key, value) pairs.
A `Map` element allows the creation of a new HashMap and to populate it with `(key, value)` pairs.
[cols=",,",options="header",]
|================================================================
@ -943,7 +891,7 @@ link:#jetty-xml-entry[Entry element]
<Item>keyName</Item>
<Item><New class="java.lang.String"><Arg>value1</Arg></New></Item>
</Entry>
</Map>
</Map>
----
This is equivalent to:
@ -951,14 +899,13 @@ This is equivalent to:
[source, java, subs="{sub-order}"]
----
Map m = new HashMap();
m.put("keyName", new String("value1"));
m.put("keyName", new String("value1"));
----
[[jetty-xml-entry]]
==== <Entry>
An Entry element contains a key-value link:#jetty-xml-item[Item element]
pair for a Map.
An `Entry` element contains a key-value link:#jetty-xml-item[Item element] pair for a `Map`.
===== Can Contain
@ -967,8 +914,8 @@ link:#jetty-xml-item[Item element]
[[jetty-xml-system-property]]
==== <SystemProperty>
A SystemProperty element gets the value of a JVM system property. It can
be used within elements that accept values, such as Set, Put, Arg.
A `SystemProperty` element gets the value of a JVM system property.
It can be used within elements that accept values, such as `Set`, `Put`, `Arg`.
[cols=",,",options="header",]
|=======================================================================
@ -983,31 +930,30 @@ later.
===== Can Contain
Only attributes as Elements (Id, Name, Default).
Only attributes as Elements (`Id`, `Name`, `Default`).
===== Example
[source, xml, subs="{sub-order}"]
----
<SystemProperty name="jetty.http.port" default="8080"/>
<SystemProperty name="jetty.http.port" default="8080"/>
----
That is equivalent to:
[source, java, subs="{sub-order}"]
----
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
not set, then 8080 is used.
Both try to retrieve the value of `jetty.http.port`.
If `jetty.http.port` is not set, then 8080 is used.
[[jetty-xml-property]]
==== <Property>
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
on the retrieved object.
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 on the retrieved object.
[cols=",,",options="header",]
|=======================================================================
@ -1020,17 +966,13 @@ on the retrieved object.
later.
|=======================================================================
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. 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.
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.
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
The attributes may be expressed as contained Elements (Id, Name,
Default).
The attributes may be expressed as contained Elements (`Id`, `Name`, `Default`).
===== Example
@ -1040,5 +982,5 @@ Default).
<Call id="jdbcIdMgr" name="getAttribute">
<Arg>jdbcIdMgr</Arg>
</Call>
</Property>
</Property>
----

View File

@ -18,7 +18,7 @@
=== Jetty XML Usage
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.
[[using-jettyxml]]
@ -28,7 +28,7 @@ To use `jetty.xml`, specify it as a configuration file when running Jetty.
[source, java, subs="{sub-order}"]
----
java -jar start.jar etc/jetty.xml
java -jar start.jar etc/jetty.xml
----
____
@ -48,24 +48,24 @@ If you use the same ID across multiple configuration files, those configurations
[[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:
[source, xml, subs="{sub-order}"]
----
<Set name="port"><SystemProperty name="jetty.http.port" default="8080"/></Set>
<Set name="port"><SystemProperty name="jetty.http.port" default="8080"/></Set>
----
Then you modify the port while running Jetty by using this command:
[source, java, subs="{sub-order}"]
----
java -Djetty.http.port=8888 -jar start.jar etc/jetty.xml
java -Djetty.http.port=8888 -jar start.jar etc/jetty.xml
----
An example of defining both system properties and properties files from the command line:
[source, java, subs="{sub-order}"]
----
java -Djetty.http.port=8888 -jar start.jar myjetty.properties etc/jetty.xml etc/other.xml
java -Djetty.http.port=8888 -jar start.jar myjetty.properties etc/jetty.xml etc/other.xml
----

View File

@ -22,33 +22,31 @@ 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.
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.
You define it per-webapp, using the xref:jetty-xml-syntax[].
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.
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
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}"]
----
<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,
relative to your $(jetty.home) directory or to the current directory -->
<Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/my/path/to/override-web.xml</Set>
...
</Configure>
----
The equivalent in code is:
[source, java, subs="{sub-order}"]
----
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
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]]
==== Using the Jetty Maven Plugin
@ -71,7 +67,6 @@ Use the `<overrideDescriptor>` tag as follows:
[source, xml, subs="{sub-order}"]
----
<project>
...
<plugins>
@ -89,8 +84,6 @@ Use the `<overrideDescriptor>` tag as follows:
</plugins>
...
</project>
----
[[override-web-xml-additional-resources]]

View File

@ -38,7 +38,7 @@ You can specify a custom `webdefault.xml` for an individual web application in t
[source, xml, subs="{sub-order}"]
----
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
...
<!-- Set up the absolute path to the custom webdefault.xml -->
@ -46,14 +46,14 @@ You can specify a custom `webdefault.xml` for an individual web application in t
...
</Configure>
----
The equivalent in code is:
[source, java, subs="{sub-order}"]
----
import org.eclipse.jetty.webapp.WebAppContext;
...
@ -64,7 +64,7 @@ import org.eclipse.jetty.webapp.WebAppContext;
wac.setDefaultsDescriptor("/my/path/to/webdefault.xml");
...
----
Alternatively, you can use a xref:jetty-classloading[] to find the resource representing your custom `webdefault.xml`.
@ -86,7 +86,7 @@ Similarly, when using the link:#jetty-maven-plugin[Jetty Maven Plugin] you provi
[source, xml, subs="{sub-order}"]
----
<project>
...
<plugins>
@ -105,7 +105,7 @@ Similarly, when using the link:#jetty-maven-plugin[Jetty Maven Plugin] you provi
...
</project>
----
[[webdefault-xml-additional-resources]]

View File

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

View File

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

View File

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

View File

@ -11,8 +11,49 @@
<Arg>
<New id="sessionDataStoreFactory" class="org.eclipse.jetty.gcloud.session.GCloudSessionDataStoreFactory">
<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="backoffMs"><Property name="jetty.gcloudSession.backoffMs" default="1000"/></Set>
<Set name="maxRetries"><Property name="jetty.session.gcloud.maxRetries" default="5"/></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>
</Arg>
</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]
Enables GCloudDatastore session management.
[Tags]
session
gcloud
[provides]
session-store
[depends]
gcloud-datastore
annotations
webapp
sessions
jcl-api
jcl-impl
[files]
basehome:etc/sessions/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
basehome:modules/gcloud/index.yaml|etc/index.yaml
[lib]
lib/jetty-gcloud-session-manager-${jetty.version}.jar
lib/gcloud/*.jar
[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]
## GCloudDatastore Session config
#jetty.gcloudSession.maxRetries=5
#jetty.gcloudSession.backoffMs=1000
#jetty.session.gcloud.maxRetries=5
#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,38 +59,327 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
{
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
public static final String ID = "id";
public static final String CONTEXTPATH = "contextPath";
public static final String VHOST = "vhost";
public static final String ACCESSED = "accessed";
public static final String LASTACCESSED = "lastAccessed";
public static final String CREATETIME = "createTime";
public static final String COOKIESETTIME = "cookieSetTime";
public static final String LASTNODE = "lastNode";
public static final String EXPIRY = "expiry";
public static final String MAXINACTIVE = "maxInactive";
public static final String ATTRIBUTES = "attributes";
public static final String KIND = "GCloudSession";
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;
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;
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;
private boolean _dsProvided = false;
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 CONTEXTPATH = "contextPath";
public static final String VHOST = "vhost";
public static final String ACCESSED = "accessed";
public static final String LASTACCESSED = "lastAccessed";
public static final String CREATETIME = "createTime";
public static final String COOKIESETTIME = "cookieSetTime";
public static final String LASTNODE = "lastNode";
public static final String EXPIRY = "expiry";
public static final String MAXINACTIVE = "maxInactive";
public static final String ATTRIBUTES = "attributes";
public static final String KIND = "GCloudSession";
protected String _kind = KIND;
protected String _id = ID;
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 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)
{
_backoff = ms;
}
public void setNamespace (String namespace)
{
_namespace = namespace;
}
public String getNamespace ()
{
return _namespace;
}
public int getBackoffMs ()
{
@ -116,9 +405,22 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
protected void doStart() throws Exception
{
if (!_dsProvided)
_datastore = DatastoreOptions.defaultInstance().service();
{
if (!StringUtil.isBlank(getNamespace()))
_datastore = DatastoreOptions.builder().namespace(getNamespace()).build().service();
else
_datastore = DatastoreOptions.defaultInstance().service();
}
_keyFactory = _datastore.newKeyFactory().kind(KIND);
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");
super.doStart();
}
@ -198,43 +500,34 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
try
{
//get up to maxResult number of sessions that have expired
Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder()
.kind(KIND)
.projection(ID, LASTNODE, EXPIRY)
.filter(CompositeFilter.and(PropertyFilter.gt(EXPIRY, 0), PropertyFilter.le(EXPIRY, now)))
.limit(_maxResults)
.build();
QueryResults<ProjectionEntity> presults = _datastore.run(query);
while (presults.hasNext())
Set<ExpiryInfo> info = null;
if (_indexesPresent)
info = queryExpiryByIndex();
else
info = queryExpiryByEntity();
for (ExpiryInfo item:info)
{
ProjectionEntity pe = presults.next();
String id = pe.getString(ID);
String lastNode = pe.getString(LASTNODE);
long expiry = pe.getLong(EXPIRY);
if (StringUtil.isBlank(lastNode))
expired.add(id); //nobody managing it
if (StringUtil.isBlank(item.getLastNode()))
expired.add(item.getId()); //nobody managing it
else
{
if (_context.getWorkerName().equals(lastNode))
expired.add(id); //we're managing it, we can expire it
if (_context.getWorkerName().equals(item.getLastNode()))
expired.add(item.getId()); //we're managing it, we can expire it
else
{
if (_lastExpiryCheckTime <= 0)
{
//our first check, just look for sessions that we managed by another node that
//expired at least 3 graceperiods ago
if (expiry < (now - (1000L * (3 * _gracePeriodSec))))
expired.add(id);
if (item.getExpiry() < (now - (1000L * (3 * _gracePeriodSec))))
expired.add(item.getId());
}
else
{
//another node was last managing it, only expire it if it expired a graceperiod ago
if (expiry < (now - (1000L * _gracePeriodSec)))
expired.add(id);
if (item.getExpiry() < (now - (1000L * _gracePeriodSec)))
expired.add(item.getId());
}
}
}
@ -254,8 +547,8 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
try
{
Query<Key> q = Query.keyQueryBuilder()
.kind(KIND)
.filter(PropertyFilter.eq(ID, s))
.kind(_model.getKind())
.filter(PropertyFilter.eq(_model.getId(), s))
.build();
QueryResults<Key> res = _datastore.run(q);
if (!res.hasNext())
@ -278,36 +571,152 @@ 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;
}
/**
* @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String)
*/
@Override
public boolean exists(String id) throws Exception
{
Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder()
.kind(KIND)
.projection(EXPIRY)
.filter(PropertyFilter.eq(ID, id))
.build();
QueryResults<ProjectionEntity> presults = _datastore.run(query);
if (presults.hasNext())
if (_indexesPresent)
{
ProjectionEntity pe = presults.next();
long expiry = pe.getLong(EXPIRY);
if (expiry <= 0)
return true; //never expires
Query<ProjectionEntity> query = Query.projectionEntityQueryBuilder()
.kind(_model.getKind())
.projection(_model.getExpiry())
.filter(PropertyFilter.eq(_model.getId(), id))
.build();
QueryResults<ProjectionEntity> presults;
if (LOG.isDebugEnabled())
{
long start = System.currentTimeMillis();
presults = _datastore.run(query);
LOG.debug("Exists query by index in {}ms", System.currentTimeMillis()-start);
}
else
return (expiry > System.currentTimeMillis()); //not expired yet
presults = _datastore.run(query);
if (presults.hasNext())
{
ProjectionEntity pe = presults.next();
return !isExpired(pe.getLong(_model.getExpiry()));
}
else
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();
}
/**
@ -371,21 +780,48 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
* @param context the session context
* @return the key
*/
private Key makeKey (String id, SessionContext context)
protected Key makeKey (String id, SessionContext context)
{
String key = context.getCanonicalContextPath()+"_"+context.getVhost()+"_"+id;
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
* @param session the session data
* @param key the key
* @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)
return null;
@ -400,17 +836,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
//turn a session into an entity
entity = Entity.builder(key)
.set(ID, session.getId())
.set(CONTEXTPATH, session.getContextPath())
.set(VHOST, session.getVhost())
.set(ACCESSED, session.getAccessed())
.set(LASTACCESSED, session.getLastAccessed())
.set(CREATETIME, session.getCreated())
.set(COOKIESETTIME, session.getCookieSet())
.set(LASTNODE,session.getLastNode())
.set(EXPIRY, session.getExpiry())
.set(MAXINACTIVE, session.getMaxInactiveMs())
.set(ATTRIBUTES, BlobValue.builder(Blob.copyFrom(baos.toByteArray())).excludeFromIndexes(true).build()).build();
.set(_model.getId(), session.getId())
.set(_model.getContextPath(), session.getContextPath())
.set(_model.getVhost(), session.getVhost())
.set(_model.getAccessed(), session.getAccessed())
.set(_model.getLastAccessed(), session.getLastAccessed())
.set(_model.getCreateTime(), session.getCreated())
.set(_model.getCookieSetTime(), session.getCookieSet())
.set(_model.getLastNode(),session.getLastNode())
.set(_model.getExpiry(), session.getExpiry())
.set(_model.getMaxInactive(), session.getMaxInactiveMs())
.set(_model.getAttributes(), BlobValue.builder(Blob.copyFrom(baos.toByteArray())).excludeFromIndexes(true).build()).build();
return entity;
@ -422,7 +858,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
* @return the session data
* @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)
return null;
@ -436,17 +872,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
try
{
//turn an Entity into a Session
String id = entity.getString(ID);
String contextPath = entity.getString(CONTEXTPATH);
String vhost = entity.getString(VHOST);
long accessed = entity.getLong(ACCESSED);
long lastAccessed = entity.getLong(LASTACCESSED);
long createTime = entity.getLong(CREATETIME);
long cookieSet = entity.getLong(COOKIESETTIME);
String lastNode = entity.getString(LASTNODE);
long expiry = entity.getLong(EXPIRY);
long maxInactive = entity.getLong(MAXINACTIVE);
Blob blob = (Blob) entity.getBlob(ATTRIBUTES);
String id = entity.getString(_model.getId());
String contextPath = entity.getString(_model.getContextPath());
String vhost = entity.getString(_model.getVhost());
long accessed = entity.getLong(_model.getAccessed());
long lastAccessed = entity.getLong(_model.getLastAccessed());
long createTime = entity.getLong(_model.getCreateTime());
long cookieSet = entity.getLong(_model.getCookieSetTime());
String lastNode = entity.getString(_model.getLastNode());
long expiry = entity.getLong(_model.getExpiry());
long maxInactive = entity.getLong(_model.getMaxInactive());
Blob blob = (Blob) entity.getBlob(_model.getAttributes());
SessionData session = newSessionData (id, createTime, accessed, lastAccessed, maxInactive);
session.setLastNode(lastNode);

View File

@ -30,10 +30,21 @@ import org.eclipse.jetty.server.session.SessionHandler;
*/
public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFactory
{
private String _namespace;
private int _maxRetries;
private int _backoffMs;
private GCloudSessionDataStore.EntityDataModel _model;
public GCloudSessionDataStore.EntityDataModel getEntityDataModel()
{
return _model;
}
public void setEntityDataModel(GCloudSessionDataStore.EntityDataModel model)
{
_model = model;
}
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)
*/
@ -66,6 +93,7 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto
ds.setBackoffMs(getBackoffMs());
ds.setMaxRetries(getMaxRetries());
ds.setGracePeriodSec(getGracePeriodSec());
ds.setNamespace(_namespace);
return ds;
}

View File

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

View File

@ -1,6 +1,9 @@
[description]
Deploys the Hawtio console as a webapplication.
[Tags]
3rdparty
[depend]
stats
deploy
@ -13,6 +16,7 @@ etc/hawtio.xml
etc/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
basehome:modules/hawtio/hawtio.xml|etc/hawtio.xml
[license]
Hawtio is a redhat JBoss project released under the Apache License, v2.0

View File

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

View File

@ -1,6 +1,9 @@
[description]
Deploys the Jminix JMX Console within the server
[Tags]
3rdparty
[depend]
stats
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://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
basehome:modules/jminix/jminix.xml|etc/jminix.xml
[lib]
lib/jminix/**.jar

View File

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

View File

@ -18,6 +18,11 @@
<artifactId>jetty-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<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;
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
{
private final String _host;
private final int _port;
final HostPort _hostPort;
public HostPortHttpField(String 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);
if (authority==null || authority.length()==0)
throw new IllegalArgumentException("No Authority");
try
{
if (authority.charAt(0)=='[')
{
// 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;
_hostPort=new HostPort(authority);
}
catch(Exception e)
{
@ -92,7 +55,7 @@ public class HostPortHttpField extends HttpField
*/
public String getHost()
{
return _host;
return _hostPort.getHost();
}
/* ------------------------------------------------------------ */
@ -101,6 +64,16 @@ public class HostPortHttpField extends HttpField
*/
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;
import java.util.ArrayList;
import java.util.Objects;
import org.eclipse.jetty.util.StringUtil;
@ -85,113 +84,9 @@ public class HttpField
{
if (_value == null)
return null;
ArrayList<String> list = new ArrayList<>();
int state = 0;
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()]);
QuotedCSV list = new QuotedCSV(false,_value);
return list.getValues().toArray(new String[list.size()]);
}
/**

View File

@ -282,6 +282,100 @@ public class HttpFields implements Iterable<HttpField>
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
* as a {@link QuotedCSV}
@ -292,11 +386,17 @@ public class HttpFields implements Iterable<HttpField>
*/
public List<String> getCSV(HttpHeader header,boolean keepQuotes)
{
QuotedCSV values = new QuotedCSV(keepQuotes);
QuotedCSV values = null;
for (HttpField f : this)
{
if (f.getHeader()==header)
{
if (values==null)
values = new QuotedCSV(keepQuotes);
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)
{
QuotedCSV values = new QuotedCSV(keepQuotes);
QuotedCSV values = null;
for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name))
{
if (values==null)
values = new QuotedCSV(keepQuotes);
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)
{
QuotedQualityCSV values = new QuotedQualityCSV();
QuotedQualityCSV values = null;
for (HttpField f : this)
{
if (f.getHeader()==header)
{
if (values==null)
values = new QuotedQualityCSV();
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)
{
QuotedQualityCSV values = new QuotedQualityCSV();
QuotedQualityCSV values = null;
for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name))
{
if (values==null)
values = new QuotedQualityCSV();
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;
import java.io.EOFException;
import java.io.IOException;
import java.nio.BufferOverflowException;
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.ArrayTrie;
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.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
@ -933,6 +935,7 @@ public class HttpParser
break;
default: break;
}
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.List;
import org.eclipse.jetty.util.QuotedStringTokenizer;
/* ------------------------------------------------------------ */
/**
* 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)
{
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()
{
@ -252,7 +266,7 @@ public class QuotedCSV implements Iterable<String>
{
return _values.iterator();
}
public static String unquote(String s)
{
// handle trivial cases

View File

@ -42,10 +42,9 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
private final List<Double> _quality = new ArrayList<>();
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.
*/
@ -54,32 +53,35 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
this((s) -> s.length());
}
/* ------------------------------------------------------------ */
/**
* 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) -> {
for (int i=0;i<serverPreferredValueOrder.length;++i)
if (serverPreferredValueOrder[i].equals(s))
return serverPreferredValueOrder.length-i;
for (int i=0;i<preferredOrder.length;++i)
if (preferredOrder[i].equals(s))
return preferredOrder.length-i;
if ("*".equals(s))
return serverPreferredValueOrder.length;
return preferredOrder.length;
return MIN_VALUE;
});
}
/* ------------------------------------------------------------ */
/**
* 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)
{
@ -148,7 +150,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
Double q = _quality.get(i);
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 + 1, v);
@ -161,7 +163,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
}
last=q;
lastOrderIndex=secondaryOrderingFunction.apply(v);
lastOrderIndex=_secondaryOrdering.apply(v);
}
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;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
@ -340,7 +341,89 @@ public class HttpFieldsTest
}
@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();
@ -351,7 +434,8 @@ public class HttpFieldsTest
fields.add("name", "one;q=0.4");
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("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("two",HttpFields.valueParameters(list.get(2),null));

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