Merge branch 'jetty-9.4.x' into issue-207
This commit is contained in:
commit
82942cb3a4
|
@ -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
|
||||
|
|
6900
VERSION.txt
6900
VERSION.txt
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);};
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.eclipse.jetty.toolchain.test.TestTracker;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
@Deprecated
|
||||
public class GZIPContentDecoderTest
|
||||
{
|
||||
@Rule
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,4 +43,9 @@ package org.eclipse.jetty.continuation;
|
|||
* </p>
|
||||
*/
|
||||
public class ContinuationThrowable extends Error
|
||||
{}
|
||||
{
|
||||
public ContinuationThrowable()
|
||||
{
|
||||
super(null, null, false, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|=======================================================================
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
....
|
||||
|
|
|
@ -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[]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
....
|
|
@ -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`::
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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].
|
||||
____
|
||||
____
|
||||
|
|
|
@ -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].
|
||||
____
|
||||
____
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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[]
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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}`.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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[]
|
||||
|
|
|
@ -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>::
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
+
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
|
|
@ -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`).
|
||||
|
|
|
@ -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}"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
----
|
||||
|
||||
____
|
||||
|
|
|
@ -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>
|
||||
----
|
||||
|
|
|
@ -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
|
||||
----
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
|
@ -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/
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue