Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x

This commit is contained in:
Lachlan Roberts 2020-10-16 15:21:25 +11:00
commit 08cf431e88
11 changed files with 240 additions and 171 deletions

View File

@ -62,6 +62,7 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat
for (String r : roles)
{
((ConstraintSecurityHandler)_context.getSecurityHandler()).addRole(r);
_context.getMetaData().setOrigin("security-role." + r, declareRoles, clazz);
}
}
}

View File

@ -108,7 +108,7 @@ public class WebFilterAnnotation extends DiscoveredAnnotation
FilterMapping mapping = new FilterMapping();
mapping.setFilterName(holder.getName());
metaData.setOrigin(name + ".filter.mapping." + Long.toHexString(mapping.hashCode()), filterAnnotation, clazz);
if (urlPatterns.length > 0)
{
ArrayList<String> paths = new ArrayList<String>();
@ -179,7 +179,7 @@ public class WebFilterAnnotation extends DiscoveredAnnotation
{
FilterMapping mapping = new FilterMapping();
mapping.setFilterName(holder.getName());
metaData.setOrigin(holder.getName() + ".filter.mapping." + Long.toHexString(mapping.hashCode()), filterAnnotation, clazz);
if (urlPatterns.length > 0)
{
ArrayList<String> paths = new ArrayList<String>();

View File

@ -154,6 +154,7 @@ public class WebServletAnnotation extends DiscoveredAnnotation
mapping = new ServletMapping(source);
mapping.setServletName(holder.getName());
mapping.setPathSpecs(LazyList.toStringArray(urlPatternList));
_context.getMetaData().setOrigin(servletName + ".servlet.mapping." + Long.toHexString(mapping.hashCode()), annotation, clazz);
}
else
{
@ -190,6 +191,7 @@ public class WebServletAnnotation extends DiscoveredAnnotation
mapping = new ServletMapping(new Source(Source.Origin.ANNOTATION, clazz.getName()));
mapping.setServletName(servletName);
mapping.setPathSpecs(LazyList.toStringArray(urlPatternList));
_context.getMetaData().setOrigin(servletName + ".servlet.mapping." + Long.toHexString(mapping.hashCode()), annotation, clazz);
}
}
@ -228,7 +230,7 @@ public class WebServletAnnotation extends DiscoveredAnnotation
LOG.debug("Removed path {} from mapping {} from defaults descriptor ", p, existingMapping);
}
}
_context.getMetaData().setOrigin(servletName + ".servlet.mapping." + p, annotation, clazz);
_context.getMetaData().setOrigin(servletName + ".servlet.mapping.url" + p, annotation, clazz);
}
allMappings.add(mapping);
_context.getServletHandler().setServletMappings(allMappings.toArray(new ServletMapping[allMappings.size()]));

View File

@ -304,11 +304,11 @@ public class HttpExchange
{
try (AutoLock l = lock.lock())
{
return String.format("%s@%x req=%s/%s@%h res=%s/%s@%h",
return String.format("%s@%x{req=%s[%s/%s] res=%s[%s/%s]}",
HttpExchange.class.getSimpleName(),
hashCode(),
requestState, requestFailure, requestFailure,
responseState, responseFailure, responseFailure);
request, requestState, requestFailure,
response, responseState, responseFailure);
}
}

View File

@ -189,7 +189,7 @@ public abstract class HttpReceiver
{
handlerListener = protocolHandler.getResponseListener();
if (LOG.isDebugEnabled())
LOG.debug("Found protocol handler {}", protocolHandler);
LOG.debug("Response {} found protocol handler {}", response, protocolHandler);
}
exchange.getConversation().updateResponseListeners(handlerListener);
@ -220,19 +220,8 @@ public abstract class HttpReceiver
*/
protected boolean responseHeader(HttpExchange exchange, HttpField field)
{
while (true)
{
ResponseState current = responseState.get();
if (current == ResponseState.BEGIN || current == ResponseState.HEADER)
{
if (updateResponseState(current, ResponseState.TRANSIENT))
break;
}
else
{
return false;
}
}
if (!updateResponseState(ResponseState.BEGIN, ResponseState.HEADER, ResponseState.TRANSIENT))
return false;
HttpResponse response = exchange.getResponse();
ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
@ -298,19 +287,8 @@ public abstract class HttpReceiver
*/
protected boolean responseHeaders(HttpExchange exchange)
{
while (true)
{
ResponseState current = responseState.get();
if (current == ResponseState.BEGIN || current == ResponseState.HEADER)
{
if (updateResponseState(current, ResponseState.TRANSIENT))
break;
}
else
{
return false;
}
}
if (!updateResponseState(ResponseState.BEGIN, ResponseState.HEADER, ResponseState.TRANSIENT))
return false;
HttpResponse response = exchange.getResponse();
if (LOG.isDebugEnabled())
@ -344,7 +322,7 @@ public abstract class HttpReceiver
{
boolean hasDemand = hasDemandOrStall();
if (LOG.isDebugEnabled())
LOG.debug("Response headers {}, hasDemand={}", response, hasDemand);
LOG.debug("Response headers hasDemand={} {}", hasDemand, response);
return hasDemand;
}
@ -365,71 +343,39 @@ public abstract class HttpReceiver
*/
protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer, Callback callback)
{
while (true)
{
ResponseState current = responseState.get();
if (current == ResponseState.HEADERS || current == ResponseState.CONTENT)
{
if (updateResponseState(current, ResponseState.TRANSIENT))
break;
}
else
{
callback.failed(new IllegalStateException("Invalid response state " + current));
return false;
}
}
boolean proceed = true;
if (LOG.isDebugEnabled())
LOG.debug("Response content {}{}{}", exchange.getResponse(), System.lineSeparator(), BufferUtil.toDetailString(buffer));
if (demand() <= 0)
{
callback.failed(new IllegalStateException("No demand for response content"));
proceed = false;
return false;
}
if (decoder == null)
return plainResponseContent(exchange, buffer, callback);
else
return decodeResponseContent(buffer, callback);
}
private boolean plainResponseContent(HttpExchange exchange, ByteBuffer buffer, Callback callback)
{
if (!updateResponseState(ResponseState.HEADERS, ResponseState.CONTENT, ResponseState.TRANSIENT))
{
callback.failed(new IllegalStateException("Invalid response state " + responseState));
return false;
}
HttpResponse response = exchange.getResponse();
if (proceed)
{
if (LOG.isDebugEnabled())
LOG.debug("Response content {}{}{}", response, System.lineSeparator(), BufferUtil.toDetailString(buffer));
if (contentListeners.isEmpty())
{
callback.succeeded();
}
else
{
if (decoder == null)
{
contentListeners.notifyContent(response, buffer, callback);
}
else
{
try
{
proceed = decoder.decode(buffer, callback);
}
catch (Throwable x)
{
callback.failed(x);
proceed = false;
}
}
}
}
if (contentListeners.isEmpty())
callback.succeeded();
else
contentListeners.notifyContent(response, buffer, callback);
if (updateResponseState(ResponseState.TRANSIENT, ResponseState.CONTENT))
{
if (proceed)
{
boolean hasDemand = hasDemandOrStall();
if (LOG.isDebugEnabled())
LOG.debug("Response content {}, hasDemand={}", response, hasDemand);
return hasDemand;
}
else
{
return false;
}
boolean hasDemand = hasDemandOrStall();
if (LOG.isDebugEnabled())
LOG.debug("Response content {}, hasDemand={}", response, hasDemand);
return hasDemand;
}
dispose();
@ -437,6 +383,11 @@ public abstract class HttpReceiver
return false;
}
private boolean decodeResponseContent(ByteBuffer buffer, Callback callback)
{
return decoder.decode(buffer, callback);
}
/**
* Method to be invoked when the response is successful.
* <p>
@ -616,15 +567,42 @@ public abstract class HttpReceiver
}
}
private boolean updateResponseState(ResponseState from1, ResponseState from2, ResponseState to)
{
while (true)
{
ResponseState current = responseState.get();
if (current == from1 || current == from2)
{
if (updateResponseState(current, to))
return true;
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("State update failed: [{},{}] -> {}: {}", from1, from2, to, current);
return false;
}
}
}
private boolean updateResponseState(ResponseState from, ResponseState to)
{
boolean updated = responseState.compareAndSet(from, to);
if (!updated)
while (true)
{
if (LOG.isDebugEnabled())
LOG.debug("State update failed: {} -> {}: {}", from, to, responseState.get());
ResponseState current = responseState.get();
if (current == from)
{
if (responseState.compareAndSet(current, to))
return true;
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("State update failed: {} -> {}: {}", from, to, current);
return false;
}
}
return updated;
}
@Override
@ -780,14 +758,62 @@ public abstract class HttpReceiver
private boolean decode(ByteBuffer encoded, Callback callback)
{
// Store the buffer to decode in case the
// decoding produces multiple decoded buffers.
this.encoded = encoded;
this.callback = callback;
return decode();
HttpResponse response = exchange.getResponse();
if (LOG.isDebugEnabled())
LOG.debug("Response content decoding {} with {}{}{}", response, decoder, System.lineSeparator(), BufferUtil.toDetailString(encoded));
boolean needInput = decode();
if (!needInput)
return false;
boolean hasDemand = hasDemandOrStall();
if (LOG.isDebugEnabled())
LOG.debug("Response content decoded, hasDemand={} {}", hasDemand, response);
return hasDemand;
}
private boolean decode()
{
while (true)
{
if (!updateResponseState(ResponseState.HEADERS, ResponseState.CONTENT, ResponseState.TRANSIENT))
{
callback.failed(new IllegalStateException("Invalid response state " + responseState));
return false;
}
DecodeResult result = decodeChunk();
if (updateResponseState(ResponseState.TRANSIENT, ResponseState.CONTENT))
{
if (result == DecodeResult.NEED_INPUT)
return true;
if (result == DecodeResult.ABORT)
return false;
boolean hasDemand = hasDemandOrStall();
if (LOG.isDebugEnabled())
LOG.debug("Response content decoded chunk, hasDemand={} {}", hasDemand, exchange.getResponse());
if (hasDemand)
continue;
else
return false;
}
dispose();
terminateResponse(exchange);
return false;
}
}
private DecodeResult decodeChunk()
{
try
{
ByteBuffer buffer;
while (true)
@ -800,27 +826,30 @@ public abstract class HttpReceiver
callback.succeeded();
encoded = null;
callback = null;
return true;
return DecodeResult.NEED_INPUT;
}
}
ByteBuffer decoded = buffer;
HttpResponse response = exchange.getResponse();
if (LOG.isDebugEnabled())
LOG.debug("Response content decoded ({}) {}{}{}", decoder, exchange, System.lineSeparator(), BufferUtil.toDetailString(decoded));
LOG.debug("Response content decoded chunk {}{}{}", response, System.lineSeparator(), BufferUtil.toDetailString(decoded));
contentListeners.notifyContent(exchange.getResponse(), decoded, Callback.from(() -> decoder.release(decoded), callback::failed));
contentListeners.notifyContent(response, decoded, Callback.from(() -> decoder.release(decoded), callback::failed));
boolean hasDemand = hasDemandOrStall();
if (LOG.isDebugEnabled())
LOG.debug("Response content decoded {}, hasDemand={}", exchange, hasDemand);
if (!hasDemand)
return false;
return DecodeResult.DECODE;
}
catch (Throwable x)
{
callback.failed(x);
return DecodeResult.ABORT;
}
}
private void resume()
{
if (LOG.isDebugEnabled())
LOG.debug("Response content resuming decoding {}", exchange);
LOG.debug("Response content resume decoding {} with {}", exchange.getResponse(), decoder);
// The content and callback may be null
// if there is no initial content demand.
@ -830,40 +859,9 @@ public abstract class HttpReceiver
return;
}
while (true)
{
ResponseState current = responseState.get();
if (current == ResponseState.HEADERS || current == ResponseState.CONTENT)
{
if (updateResponseState(current, ResponseState.TRANSIENT))
break;
}
else
{
callback.failed(new IllegalStateException("Invalid response state " + current));
return;
}
}
boolean decoded = false;
try
{
decoded = decode();
}
catch (Throwable x)
{
callback.failed(x);
}
if (updateResponseState(ResponseState.TRANSIENT, ResponseState.CONTENT))
{
if (decoded)
receive();
return;
}
dispose();
terminateResponse(exchange);
boolean needInput = decode();
if (needInput)
receive();
}
@Override
@ -873,4 +871,9 @@ public abstract class HttpReceiver
((Destroyable)decoder).destroy();
}
}
private enum DecodeResult
{
DECODE, NEED_INPUT, ABORT
}
}

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.client;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@ -32,11 +33,14 @@ import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.IO;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
@ -266,6 +270,47 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest
assertThat(heapMemory, lessThan((long)content.length));
}
@ParameterizedTest
@ArgumentsSource(ScenarioProvider.class)
public void testLargeGZIPContentAsync(Scenario scenario) throws Exception
{
String digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Random random = new Random();
byte[] content = new byte[32 * 1024 * 1024];
for (int i = 0; i < content.length; ++i)
{
content[i] = (byte)digits.charAt(random.nextInt(digits.length()));
}
start(scenario, new EmptyServerHandler()
{
@Override
protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
{
response.setContentType("text/plain;charset=" + StandardCharsets.US_ASCII.name());
response.setHeader(HttpHeader.CONTENT_ENCODING.asString(), "gzip");
GZIPOutputStream gzip = new GZIPOutputStream(response.getOutputStream());
gzip.write(content);
gzip.finish();
}
});
InputStreamResponseListener listener = new InputStreamResponseListener();
client.newRequest("localhost", connector.getLocalPort())
.scheme(scenario.getScheme())
.timeout(5, TimeUnit.SECONDS)
.send(listener);
Response response = listener.get(5, TimeUnit.SECONDS);
assertEquals(HttpStatus.OK_200, response.getStatus());
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (InputStream input = listener.getInputStream())
{
IO.copy(input, output);
}
assertArrayEquals(content, output.toByteArray());
}
private static void sleep(long ms) throws IOException
{
try

View File

@ -20,7 +20,7 @@
==== Configuring JNDI Entries
A web application may _reference_ a JNDI entry, such as a JDBC `DataSource` from the web application `web.xml` file.
The JNDI entry must be _defined_ in the Jetty context XML file, for example:
The JNDI entry must be _defined_ in a link:#og-jndi-xml[Jetty XML file], for example a context XML like so:
.mywebapp.xml
[source,xml,subs=normal]
@ -28,11 +28,11 @@ The JNDI entry must be _defined_ in the Jetty context XML file, for example:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Configure id="wac" class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/mywebapp</Set>
<Set name="war">/opt/webapps/mywebapp.war</Set>
#&nbsp;&nbsp;<New class="org.eclipse.jetty.plus.jndi.Resource">
<Arg />
<Arg><Ref refid="wac"/></Arg>
<Arg>jdbc/myds</Arg>
<Arg>
<New class="com.mysql.cj.jdbc.MysqlConnectionPoolDataSource">
@ -45,11 +45,14 @@ The JNDI entry must be _defined_ in the Jetty context XML file, for example:
</Configure>
----
For more information and examples on how to use JNDI in Jetty, refer to the link:#og-jndi[JNDI] feature section.
[IMPORTANT]
====
Class `com.mysql.cj.jdbc.MysqlConnectionPoolDataSource` is present in the MySQL JDBC driver file, `mysql-connector-java-<version>.jar`, which must be available to the web application.
Class `com.mysql.cj.jdbc.MysqlConnectionPoolDataSource` is present in the MySQL JDBC driver file, `mysql-connector-java-<version>.jar`, which must be available on the server's classpath .
If the class is instead present _within_ the web application, then the JNDI entry must be declared in a `WEB-INF/jetty-env.xml` file - see the link:#og-jndi[JNDI] feature section for more information and examples.
File `mysql-connector-java-<version>.jar` must be either present in `WEB-INF/lib`, or in the Jetty server class-path.
====
// TODO: add a link to reference the section about how
// to add a JDBC driver jar to the server classpath.

View File

@ -329,14 +329,13 @@ Server XML file::
Naming resources defined in a server XML file are link:#og-jndi-scope[scoped] at either the JVM level or the `org.eclipse.jetty.server.Server` level.
The classes for the resource _must_ be visible at the Jetty *container* level.
If instead the classes for the resource only exist inside your webapp, you must declare it in a `WEB-INF/jetty-env.xml` file.
Context XML file::
Entries in a context XML file should be link:#og-jndi-scope[scoped] at the level of the webapp to which they apply (although it is possible to use a less strict scoping level of Server or JVM, but not recommended).
As with resources declared in a server XML file, classes associated with the resource _must_ be visible on the *container's* classpath.
WEB-INF/jetty-env.xml::
Naming resources in a `WEB-INF/jetty-env.xml` file are link:#og-jndi-scope[scoped] to the webapp in which the file resides.
While you can enter JVM or Server scopes if you choose, we do not recommend doing so.
The resources defined here may use classes from inside your webapp.
This is a Jetty-specific mechanism.
Context XML file::
Entries in a context XML file should be link:#og-jndi-scope[scoped] at the level of the webapp to which they apply (although it is possible to use a less strict scoping level of Server or JVM, but not recommended).
As with resources declared in a server XML file, classes associated with the resource _must_ be visible on the *container's* classpath.
[[og-jndi-scope]]
===== Resource scoping

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.quickstart;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.webapp.Descriptor;
import org.eclipse.jetty.webapp.IterativeDescriptorProcessor;
import org.eclipse.jetty.webapp.WebAppContext;
@ -36,12 +37,11 @@ public class ExtraXmlDescriptorProcessor extends IterativeDescriptorProcessor
private static final Logger LOG = LoggerFactory.getLogger(ExtraXmlDescriptorProcessor.class);
private final StringBuilder _buffer = new StringBuilder();
private final boolean _showOrigin;
private String _originAttribute;
private String _origin;
public ExtraXmlDescriptorProcessor()
{
_showOrigin = LOG.isDebugEnabled();
try
{
registerVisitor("env-entry", getClass().getMethod("saveSnippet", __signature));
@ -60,7 +60,7 @@ public class ExtraXmlDescriptorProcessor extends IterativeDescriptorProcessor
public void start(WebAppContext context, Descriptor descriptor)
{
LOG.debug("process {}", descriptor);
_origin = (" <!-- " + descriptor + " -->\n");
_origin = (StringUtil.isBlank(_originAttribute) ? null : " <!-- " + descriptor + " -->\n");
}
@Override
@ -68,11 +68,19 @@ public class ExtraXmlDescriptorProcessor extends IterativeDescriptorProcessor
{
}
public void setOriginAttribute(String name)
{
_originAttribute = name;
}
public void saveSnippet(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
throws Exception
{
//Note: we have to output the origin as a comment field instead of
//as an attribute like the other other elements because
//we are copying these elements _verbatim_ from the descriptor
LOG.debug("save {}", node.getTag());
if (_showOrigin)
if (_origin != null)
_buffer.append(_origin);
_buffer.append(" ").append(node.toString()).append("\n");
}

View File

@ -241,7 +241,7 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
if (f != null && f.getSource() == Source.EMBEDDED)
continue;
out.openTag("filter-mapping");
out.openTag("filter-mapping", origin(md, mapping.getFilterName() + ".filter.mapping." + Long.toHexString(mapping.hashCode())));
out.tag("filter-name", mapping.getFilterName());
if (mapping.getPathSpecs() != null)
for (String s : mapping.getPathSpecs())
@ -289,7 +289,7 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
if (sh != null && sh.getSource() == Source.EMBEDDED)
continue;
out.openTag("servlet-mapping", origin(md, mapping.getServletName() + ".servlet.mappings"));
out.openTag("servlet-mapping", origin(md, mapping.getServletName() + ".servlet.mapping." + Long.toHexString(mapping.hashCode())));
out.tag("servlet-name", mapping.getServletName());
if (mapping.getPathSpecs() != null)
for (String s : mapping.getPathSpecs())
@ -327,7 +327,7 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
ConstraintAware ca = (ConstraintAware)security;
for (String r : ca.getRoles())
{
out.openTag("security-role")
out.openTag("security-role", origin(md, "security-role." + r))
.tag("role-name", r)
.closeTag();
}
@ -398,7 +398,7 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
out.openTag("welcome-file-list");
for (String welcomeFile : context.getWelcomeFiles())
{
out.tag("welcome-file", welcomeFile);
out.tag("welcome-file", origin(md, "welcome-file." + welcomeFile), welcomeFile);
}
out.closeTag();
}
@ -429,6 +429,7 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
if (cookieConfig != null)
{
out.openTag("cookie-config");
if (cookieConfig.getName() != null)
out.tag("name", origin(md, "cookie-config.name"), cookieConfig.getName());
@ -789,6 +790,7 @@ public class QuickStartGeneratorConfiguration extends AbstractConfiguration
public void preConfigure(WebAppContext context) throws Exception
{
ExtraXmlDescriptorProcessor extraXmlProcessor = new ExtraXmlDescriptorProcessor();
extraXmlProcessor.setOriginAttribute(getOriginAttribute());
context.getMetaData().addDescriptorProcessor(extraXmlProcessor);
context.setAttribute(ExtraXmlDescriptorProcessor.class.getName(), extraXmlProcessor);
super.preConfigure(context);

View File

@ -663,6 +663,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
if (TimeUnit.MINUTES.toSeconds(mins) > Integer.MAX_VALUE)
throw new IllegalStateException("Max session-timeout in minutes is " + TimeUnit.SECONDS.toMinutes(Integer.MAX_VALUE));
context.getServletContext().setSessionTimeout((int)mins);
context.getMetaData().setOrigin("session.timeout", descriptor);
}
//Servlet Spec 3.0
@ -672,7 +673,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
if (iter.hasNext())
{
Set<SessionTrackingMode> modes = null;
Origin o = context.getMetaData().getOrigin("session.tracking-mode");
Origin o = context.getMetaData().getOrigin("session.tracking-modes");
switch (o)
{
case NotSet://not previously set, starting fresh
@ -680,7 +681,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
{
modes = new HashSet<SessionTrackingMode>();
context.getMetaData().setOrigin("session.tracking-mode", descriptor);
context.getMetaData().setOrigin("session.tracking-modes", descriptor);
break;
}
case WebXml:
@ -692,7 +693,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
modes = new HashSet<SessionTrackingMode>();
else
modes = new HashSet<SessionTrackingMode>(context.getSessionHandler().getEffectiveSessionTrackingModes());
context.getMetaData().setOrigin("session.tracking-mode", descriptor);
context.getMetaData().setOrigin("session.tracking-modes", descriptor);
break;
}
default:
@ -703,7 +704,9 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
{
XmlParser.Node mNode = (XmlParser.Node)iter.next();
String trackMode = mNode.toString(false, true);
modes.add(SessionTrackingMode.valueOf(trackMode));
SessionTrackingMode mode = SessionTrackingMode.valueOf(trackMode);
modes.add(mode);
context.getMetaData().setOrigin("session.tracking-mode." + mode, descriptor);
}
context.getSessionHandler().setSessionTrackingModes(modes);
}
@ -1035,13 +1038,13 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
case NotSet:
{
context.getMetaData().setOrigin("welcome-file-list", descriptor);
addWelcomeFiles(context, node);
addWelcomeFiles(context, node, descriptor);
break;
}
case WebXml:
{
//web.xml set the welcome-file-list, all other descriptors then just merge in
addWelcomeFiles(context, node);
addWelcomeFiles(context, node, descriptor);
break;
}
case WebDefaults:
@ -1052,19 +1055,19 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
{
context.setWelcomeFiles(new String[0]);
}
addWelcomeFiles(context, node);
addWelcomeFiles(context, node, descriptor);
break;
}
case WebOverride:
{
//web-override set the list, all other descriptors just merge in
addWelcomeFiles(context, node);
addWelcomeFiles(context, node, descriptor);
break;
}
case WebFragment:
{
//A web-fragment first set the welcome-file-list. Other descriptors just add.
addWelcomeFiles(context, node);
addWelcomeFiles(context, node, descriptor);
break;
}
default:
@ -1182,14 +1185,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
}
}
public void addWelcomeFiles(WebAppContext context, XmlParser.Node node)
public void addWelcomeFiles(WebAppContext context, XmlParser.Node node, Descriptor descriptor)
{
Iterator<XmlParser.Node> iter = node.iterator("welcome-file");
while (iter.hasNext())
{
XmlParser.Node indexNode = (XmlParser.Node)iter.next();
String welcome = indexNode.toString(false, true);
context.getMetaData().setOrigin("welcome-file." + welcome, descriptor);
//Servlet Spec 3.0 p. 74 welcome files are additive
if (welcome != null && welcome.trim().length() > 0)
context.setWelcomeFiles((String[])ArrayUtil.addToArray(context.getWelcomeFiles(), welcome, String.class));
@ -1201,7 +1204,8 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
ServletMapping mapping = new ServletMapping(new Source(Source.Origin.DESCRIPTOR, descriptor.getResource().toString()));
mapping.setServletName(servletName);
mapping.setFromDefaultDescriptor(descriptor instanceof DefaultsDescriptor);
context.getMetaData().setOrigin(servletName + ".servlet.mapping." + Long.toHexString(mapping.hashCode()), descriptor);
List<String> paths = new ArrayList<String>();
Iterator<XmlParser.Node> iter = node.iterator("url-pattern");
while (iter.hasNext())
@ -1255,7 +1259,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
}
paths.add(p);
context.getMetaData().setOrigin(servletName + ".servlet.mapping." + p, descriptor);
context.getMetaData().setOrigin(servletName + ".servlet.mapping.url" + p, descriptor);
}
mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()]));
@ -1269,7 +1273,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
{
FilterMapping mapping = new FilterMapping();
mapping.setFilterName(filterName);
context.getMetaData().setOrigin(filterName + ".filter.mapping." + Long.toHexString(mapping.hashCode()), descriptor);
List<String> paths = new ArrayList<String>();
Iterator<XmlParser.Node> iter = node.iterator("url-pattern");
while (iter.hasNext())
@ -1277,7 +1281,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
String p = iter.next().toString(false, true);
p = ServletPathSpec.normalize(p);
paths.add(p);
context.getMetaData().setOrigin(filterName + ".filter.mapping." + p, descriptor);
context.getMetaData().setOrigin(filterName + ".filter.mapping.url" + p, descriptor);
}
mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()]));
@ -1286,6 +1290,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
while (iter.hasNext())
{
String n = ((XmlParser.Node)iter.next()).toString(false, true);
context.getMetaData().setOrigin(filterName + ".filter.mapping.servlet" + n, descriptor);
names.add(n);
}
mapping.setServletNames((String[])names.toArray(new String[names.size()]));
@ -1741,6 +1746,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
XmlParser.Node roleNode = node.get("role-name");
String role = roleNode.toString(false, true);
((ConstraintAware)context.getSecurityHandler()).addRole(role);
context.getMetaData().setOrigin("security-role." + role, descriptor);
}
public void visitFilter(WebAppContext context, Descriptor descriptor, XmlParser.Node node)