Jetty 10.0.x 4506 metadata complete (#4587)

* Issue #4506 Do not introspect annotations on metadata-complete fragments

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2020-03-09 15:34:04 +01:00 committed by GitHub
parent 7554a3a903
commit dfd3875dbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 1386 additions and 476 deletions

View File

@ -39,6 +39,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;
@ -58,7 +59,6 @@ import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.MetaDataComplete;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebDescriptor;
@ -335,11 +335,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override
public void configure(WebAppContext context) throws Exception
{
//handle introspectable annotations (postconstruct,predestroy, multipart etc etc)
context.getObjectFactory().addDecorator(new AnnotationDecorator(context));
if (!context.getMetaData().isMetaDataComplete())
{
//If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
//If web.xml not metadata-complete, if this is a servlet 3 webapp or above
//or configDiscovered is true, we need to search for annotations
if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
{
_discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context));
@ -408,7 +410,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
/**
* Perform scanning of classes for annotations
* Perform scanning of classes for discoverable
* annotations such as WebServlet/WebFilter/WebListener
*
* @param context the context for the scan
* @throws Exception if unable to scan
@ -431,6 +434,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
isUseMultiThreading(context),
getMaxScanWait(context));
//scan selected jars on the container classpath first
parseContainerPath(context, parser);
//email from Rajiv Mordani jsrs 315 7 April 2010
// If there is a <others/> then the ordering should be
@ -438,6 +442,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
// In case there is no others then it is
// WEB-INF/classes + order of the elements.
parseWebInfClasses(context, parser);
//scan non-excluded, non medatadata-complete jars in web-inf lib
parseWebInfLib(context, parser);
long start = System.nanoTime();
@ -691,14 +696,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
//If no ordering, nothing is excluded
if (context.getMetaData().getOrdering() == null)
if (!context.getMetaData().isOrdered())
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} no ordering", sci);
return false;
}
List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
List<Resource> orderedJars = context.getMetaData().getWebInfResources(true);
//there is an ordering, but there are no jars resulting from the ordering, everything excluded
if (orderedJars.isEmpty())
@ -710,17 +715,17 @@ public class AnnotationConfiguration extends AbstractConfiguration
//Check if it is excluded by an ordering
URI loadingJarURI = sciResource.getURI();
boolean found = false;
Iterator<Resource> itor = orderedJars.iterator();
while (!found && itor.hasNext())
boolean included = false;
for (Resource r : orderedJars)
{
Resource r = itor.next();
found = r.getURI().equals(loadingJarURI);
included = r.getURI().equals(loadingJarURI);
if (included)
break;
}
if (LOG.isDebugEnabled())
LOG.debug("{}Excluded {} found={}", found ? "!" : "", sci, found);
return !found;
LOG.debug("{}Excluded {} found={}", included ? "!" : "", sci, included);
return !included;
}
/**
@ -785,7 +790,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
*/
public boolean isFromWebInfClasses(WebAppContext context, Resource sci)
{
for (Resource dir : context.getMetaData().getWebInfClassesDirs())
for (Resource dir : context.getMetaData().getWebInfClassesResources())
{
if (dir.equals(sci))
{
@ -831,7 +836,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
catch (Error e)
{
// Probably a SCI discovered on the system classpath that is hidden by the context classloader
LOG.info("Error: " + e.getMessage() + " for " + context);
LOG.info("Error: {} for {}", e.getMessage(), context);
LOG.debug(e);
continue;
}
@ -867,7 +872,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (initializerOrdering != null && !initializerOrdering.isDefaultOrder())
{
if (LOG.isDebugEnabled())
LOG.debug("Ordering ServletContainerInitializers with " + initializerOrdering);
LOG.debug("Ordering ServletContainerInitializers with {}", initializerOrdering);
//There is an ordering that is not just "*".
//Arrange ServletContainerInitializers according to the ordering of classnames given, irrespective of coming from container or webapp classpaths
@ -894,7 +899,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
else
{
for (Resource dir : context.getMetaData().getWebInfClassesDirs())
for (Resource dir : context.getMetaData().getWebInfClassesResources())
{
if (dir.equals(entry.getValue()))//from WEB-INF/classes so can't be ordered/excluded
{
@ -923,7 +928,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
LOG.debug("Ordering ServletContainerInitializers with ordering {}", context.getMetaData().getOrdering());
//add SCIs according to the ordering of its containing jar
for (Resource webInfJar : context.getMetaData().getOrderedWebInfJars())
for (Resource webInfJar : context.getMetaData().getWebInfResources(true))
{
for (Map.Entry<ServletContainerInitializer, Resource> entry : sciResourceMap.entrySet())
{
@ -977,7 +982,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
return null;
String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_ORDER);
if (tmp == null || "".equals(tmp.trim()))
if (StringUtil.isBlank(tmp))
return null;
return new ServletContainerInitializerOrdering(tmp);
@ -1002,9 +1007,10 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (LOG.isDebugEnabled())
_containerPathStats = new CounterStatistic();
//scan the container classpath jars that were selected by
//filtering in MetaInfConfiguration
for (Resource r : context.getMetaData().getContainerResources())
{
//queue it up for scanning if using multithreaded mode
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers, r);
@ -1019,7 +1025,10 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
/**
* Scan jars in WEB-INF/lib
* Scan jars in WEB-INF/lib.
*
* Only jars selected by MetaInfConfiguration, and that are not excluded
* by an ordering will be considered.
*
* @param context the context for the scan
* @param parser the annotation parser to use
@ -1027,20 +1036,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
*/
public void parseWebInfLib(final WebAppContext context, final AnnotationParser parser) throws Exception
{
List<FragmentDescriptor> frags = context.getMetaData().getFragments();
//email from Rajiv Mordani jsrs 315 7 April 2010
//jars that do not have a web-fragment.xml are still considered fragments
//they have to participate in the ordering
ArrayList<URI> webInfUris = new ArrayList<URI>();
List<Resource> jars = null;
if (context.getMetaData().getOrdering() != null)
jars = context.getMetaData().getOrderedWebInfJars();
else
//No ordering just use the jars in any order
jars = context.getMetaData().getWebInfJars();
//if there is an ordering, the ordered jars should be used.
//If there is no ordering, jars will be unordered.
List<Resource> jars = context.getMetaData().getWebInfResources(context.getMetaData().isOrdered());
if (LOG.isDebugEnabled())
{
@ -1053,13 +1055,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
//for each jar, we decide which set of annotations we need to parse for
final Set<Handler> handlers = new HashSet<Handler>();
FragmentDescriptor f = getFragmentFromJar(r, frags);
FragmentDescriptor f = context.getMetaData().getFragmentDescriptorForJar(r);
//if its from a fragment jar that is metadata complete, we should skip scanning for @webservlet etc
// but yet we still need to do the scanning for the classes on behalf of the servletcontainerinitializers
//if a jar has no web-fragment.xml we scan it (because it is not excluded by the ordering)
//or if it has a fragment we scan it if it is not metadata complete
if (f == null || !isMetaDataComplete(f) || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
if (f == null || !WebDescriptor.isMetaDataComplete(f) || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
{
//register the classinheritance handler if there is one
if (_classInheritanceHandler != null)
@ -1069,7 +1071,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
handlers.addAll(_containerInitializerAnnotationHandlers);
//only register the discoverable annotation handlers if this fragment is not metadata complete, or has no fragment descriptor
if (f == null || !isMetaDataComplete(f))
if (f == null || !WebDescriptor.isMetaDataComplete(f))
handlers.addAll(_discoverableAnnotationHandlers);
if (_parserTasks != null)
@ -1087,7 +1089,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
/**
* Scan classes in WEB-INF/classes
* Scan classes in WEB-INF/classes.
*
* @param context the context for the scan
* @param parser the annotation parser to use
@ -1105,7 +1107,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (LOG.isDebugEnabled())
_webInfClassesStats = new CounterStatistic();
for (Resource dir : context.getMetaData().getWebInfClassesDirs())
for (Resource dir : context.getMetaData().getWebInfClassesResources())
{
if (_parserTasks != null)
{
@ -1120,39 +1122,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
}
/**
* Get the web-fragment.xml from a jar
*
* @param jar the jar to look in for a fragment
* @param frags the fragments previously found
* @return true if the fragment if found, or null of not found
* @throws Exception if unable to determine the the fragment contains
*/
public FragmentDescriptor getFragmentFromJar(Resource jar, List<FragmentDescriptor> frags)
throws Exception
{
//check if the jar has a web-fragment.xml
FragmentDescriptor d = null;
for (FragmentDescriptor frag : frags)
{
Resource fragResource = frag.getResource(); //eg jar:file:///a/b/c/foo.jar!/META-INF/web-fragment.xml
if (Resource.isContainedIn(fragResource, jar))
{
d = frag;
break;
}
}
return d;
}
public boolean isMetaDataComplete(WebDescriptor d)
{
return (d != null && d.getMetaDataComplete() == MetaDataComplete.True);
}
public static class ClassInheritanceMap extends ConcurrentHashMap<String, Set<String>>
{
@Override
public String toString()
{

View File

@ -18,6 +18,9 @@
package org.eclipse.jetty.annotations;
import java.util.Objects;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.Decorator;
import org.eclipse.jetty.webapp.WebAppContext;
@ -26,23 +29,26 @@ import org.eclipse.jetty.webapp.WebAppContext;
*/
public class AnnotationDecorator implements Decorator
{
protected AnnotationIntrospector _introspector = new AnnotationIntrospector();
protected AnnotationIntrospector _introspector;
protected WebAppContext _context;
public AnnotationDecorator(WebAppContext context)
{
registerHandlers(context);
_context = Objects.requireNonNull(context);
_introspector = new AnnotationIntrospector(_context);
registerHandlers();
}
public void registerHandlers(WebAppContext context)
private void registerHandlers()
{
_introspector.registerHandler(new ResourceAnnotationHandler(context));
_introspector.registerHandler(new ResourcesAnnotationHandler(context));
_introspector.registerHandler(new RunAsAnnotationHandler(context));
_introspector.registerHandler(new PostConstructAnnotationHandler(context));
_introspector.registerHandler(new PreDestroyAnnotationHandler(context));
_introspector.registerHandler(new DeclareRolesAnnotationHandler(context));
_introspector.registerHandler(new MultiPartConfigAnnotationHandler(context));
_introspector.registerHandler(new ServletSecurityAnnotationHandler(context));
_introspector.registerHandler(new ResourceAnnotationHandler(_context));
_introspector.registerHandler(new ResourcesAnnotationHandler(_context));
_introspector.registerHandler(new RunAsAnnotationHandler(_context));
_introspector.registerHandler(new PostConstructAnnotationHandler(_context));
_introspector.registerHandler(new PreDestroyAnnotationHandler(_context));
_introspector.registerHandler(new DeclareRolesAnnotationHandler(_context));
_introspector.registerHandler(new MultiPartConfigAnnotationHandler(_context));
_introspector.registerHandler(new ServletSecurityAnnotationHandler(_context));
}
/**
@ -50,22 +56,28 @@ public class AnnotationDecorator implements Decorator
* <ul>
* <li> Resource </li>
* <li> Resources </li>
* <li> RunAs </li>
* <li> PostConstruct </li>
* <li> PreDestroy </li>
* <li> ServletSecurity? </li>
* <li> DeclareRoles </li>
* <li> MultiPart </li>
* <li> ServletSecurity</li>
* </ul>
*
* @param o the object ot introspect
* @param o the object to introspect
* @param metaInfo information about the object to introspect
*/
protected void introspect(Object o)
protected void introspect(Object o, Object metaInfo)
{
_introspector.introspect(o.getClass());
if (o == null)
return;
_introspector.introspect(o, metaInfo);
}
@Override
public Object decorate(Object o)
{
introspect(o);
introspect(o, DecoratedObjectFactory.getAssociatedInfo());
return o;
}

View File

@ -18,11 +18,21 @@
package org.eclipse.jetty.annotations;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.eclipse.jetty.servlet.BaseHolder;
import org.eclipse.jetty.servlet.Source.Origin;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebDescriptor;
/**
* AnnotationIntrospector
* Introspects a class to find various types of
@ -30,8 +40,10 @@ import java.util.Set;
*/
public class AnnotationIntrospector
{
private static final Logger LOG = Log.getLogger(AnnotationIntrospector.class);
private final Set<Class<?>> _introspectedClasses = new HashSet<>();
private final List<IntrospectableAnnotationHandler> _handlers = new ArrayList<IntrospectableAnnotationHandler>();
private final WebAppContext _context;
/**
* IntrospectableAnnotationHandler
@ -51,12 +63,14 @@ public class AnnotationIntrospector
*/
public abstract static class AbstractIntrospectableAnnotationHandler implements IntrospectableAnnotationHandler
{
private boolean _introspectAncestors;
protected boolean _introspectAncestors;
protected WebAppContext _context;
public abstract void doHandle(Class<?> clazz);
public AbstractIntrospectableAnnotationHandler(boolean introspectAncestors)
public AbstractIntrospectableAnnotationHandler(boolean introspectAncestors, WebAppContext context)
{
_context = Objects.requireNonNull(context);
_introspectAncestors = introspectAncestors;
}
@ -75,6 +89,16 @@ public class AnnotationIntrospector
c = c.getSuperclass();
}
}
public WebAppContext getContext()
{
return _context;
}
}
public AnnotationIntrospector(WebAppContext context)
{
_context = Objects.requireNonNull(context);
}
public void registerHandler(IntrospectableAnnotationHandler handler)
@ -82,13 +106,96 @@ public class AnnotationIntrospector
_handlers.add(handler);
}
public void introspect(Class<?> clazz)
/**
* Test if an object should be introspected for some specific types of annotations
* like PostConstruct/PreDestroy/MultiPart etc etc.
*
* According to servlet 4.0, these types of annotations should only be evaluated iff any
* of the following are true:
* <ol>
* <li>the object was created by the javax.servlet.ServletContext.createServlet/Filter/Listener method</li>
* <li>the object comes either from a discovered annotation (WebServlet/Filter/Listener) or a declaration
* in a descriptor AND web.xml is NOT metadata-complete AND any web-fragment.xml associated with the location of
* the class is NOT metadata-complete</li>
* </ol>
*
* We also support evaluations of these types of annotations for objects that were created directly
* by the jetty api.
*
* @param o the object to check for its ability to be introspected for annotations
* @param metaInfo meta information about the object to be introspected
* @return true if it can be introspected according to servlet 4.0 rules
*/
public boolean isIntrospectable(Object o, Object metaInfo)
{
if (_handlers == null)
return;
if (clazz == null)
if (o == null)
return false; //nothing to introspect
if (metaInfo == null)
return true; //no information about the object to introspect, assume introspectable
@SuppressWarnings("rawtypes")
BaseHolder holder = null;
try
{
holder = (BaseHolder)metaInfo;
}
catch (ClassCastException e)
{
LOG.warn(e);
return true; //not the type of information we were expecting, assume introspectable
}
Origin origin = (holder.getSource() == null ? null : holder.getSource().getOrigin());
if (origin == null)
return true; //assume introspectable
switch (origin)
{
case EMBEDDED:
case JAVAX_API:
{
return true; //objects created from the jetty or servlet api are always introspectable
}
case ANNOTATION:
{
return true; //we will have discovered annotations only if metadata-complete==false
}
default:
{
//must be from a descriptor. Only introspect if the descriptor with which it was associated
//is not metadata-complete
if (_context.getMetaData().isMetaDataComplete())
return false;
String descriptorLocation = holder.getSource().getResource();
if (descriptorLocation == null)
return true; //no descriptor, can't be metadata-complete
try
{
return !WebDescriptor.isMetaDataComplete(_context.getMetaData().getFragmentDescriptor(Resource.newResource(descriptorLocation)));
}
catch (IOException e)
{
LOG.warn("Unable to get Resource for descriptor {}", descriptorLocation, e);
return false; //something wrong with the descriptor
}
}
}
}
/**
* @param o
* @param metaInfo
*/
public void introspect(Object o, Object metaInfo)
{
if (!isIntrospectable(o, metaInfo))
return;
Class<?> clazz = o.getClass();
synchronized (_introspectedClasses)
{
//Synchronize on the set of already introspected classes.

View File

@ -35,12 +35,9 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat
{
private static final Logger LOG = Log.getLogger(DeclareRolesAnnotationHandler.class);
protected WebAppContext _context;
public DeclareRolesAnnotationHandler(WebAppContext context)
{
super(false);
_context = context;
super(false, context);
}
@Override

View File

@ -33,13 +33,10 @@ import org.eclipse.jetty.webapp.WebAppContext;
*/
public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
protected WebAppContext _context;
public MultiPartConfigAnnotationHandler(WebAppContext context)
{
//TODO verify that MultipartConfig is not inheritable
super(false);
_context = context;
super(false, context);
}
@Override

View File

@ -31,12 +31,9 @@ import org.eclipse.jetty.webapp.WebAppContext;
public class PostConstructAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
protected WebAppContext _context;
public PostConstructAnnotationHandler(WebAppContext wac)
{
super(true);
_context = wac;
super(true, wac);
}
@Override

View File

@ -31,12 +31,9 @@ import org.eclipse.jetty.webapp.WebAppContext;
public class PreDestroyAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
WebAppContext _context;
public PreDestroyAnnotationHandler(WebAppContext wac)
{
super(true);
_context = wac;
super(true, wac);
}
@Override

View File

@ -48,12 +48,9 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH
Float.class
});
protected WebAppContext _context;
public ResourceAnnotationHandler(WebAppContext wac)
{
super(true);
_context = wac;
super(true, wac);
}
/**

View File

@ -31,12 +31,9 @@ public class ResourcesAnnotationHandler extends AbstractIntrospectableAnnotation
{
private static final Logger LOG = Log.getLogger(ResourcesAnnotationHandler.class);
protected WebAppContext _wac;
public ResourcesAnnotationHandler(WebAppContext wac)
{
super(true);
_wac = wac;
super(true, wac);
}
@Override
@ -64,8 +61,8 @@ public class ResourcesAnnotationHandler extends AbstractIntrospectableAnnotation
{
//TODO don't ignore the shareable, auth etc etc
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName))
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName))
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName))
if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName))
LOG.warn("Skipping Resources(Resource) annotation on " + clazz.getName() + " for name " + name + ": No resource bound at " + (mappedName == null ? name : mappedName));
}
catch (NamingException e)

View File

@ -33,14 +33,11 @@ public class RunAsAnnotationHandler extends AbstractIntrospectableAnnotationHand
{
private static final Logger LOG = Log.getLogger(RunAsAnnotationHandler.class);
protected WebAppContext _context;
public RunAsAnnotationHandler(WebAppContext wac)
{
//Introspect only the given class for a RunAs annotation, as it is a class level annotation,
//and according to Common Annotation Spec p2-6 a class-level annotation is not inheritable.
super(false);
_context = wac;
super(false, wac);
}
@Override

View File

@ -57,12 +57,9 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno
{
private static final Logger LOG = Log.getLogger(ServletSecurityAnnotationHandler.class);
private WebAppContext _context;
public ServletSecurityAnnotationHandler(WebAppContext wac)
{
super(false);
_context = wac;
super(false, wac);
}
@Override

View File

@ -16,9 +16,15 @@
// ========================================================================
//
package org.eclipse.jetty.webapp;
package org.eclipse.jetty.annotations;
public enum MetaDataComplete
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServlet;
public class ServletE extends HttpServlet
{
@PreDestroy
public void preDestroy()
{
NotSet, True, False
}
}

View File

@ -33,6 +33,7 @@ import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.RelativeOrdering;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebDescriptor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -125,7 +126,7 @@ public class TestAnnotationConfiguration
context25.setClassLoader(Thread.currentThread().getContextClassLoader());
context25.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context25.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, 0);
context25.getMetaData().setWebXml(Resource.newResource(web25));
context25.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web25)));
context25.getServletContext().setEffectiveMajorVersion(2);
context25.getServletContext().setEffectiveMinorVersion(5);
config25.configure(context25);
@ -138,7 +139,7 @@ public class TestAnnotationConfiguration
context25b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context25b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, 0);
context25b.setConfigurationDiscovered(true);
context25b.getMetaData().setWebXml(Resource.newResource(web25));
context25b.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web25)));
context25b.getServletContext().setEffectiveMajorVersion(2);
context25b.getServletContext().setEffectiveMinorVersion(5);
config25b.configure(context25b);
@ -150,7 +151,7 @@ public class TestAnnotationConfiguration
context31.setClassLoader(Thread.currentThread().getContextClassLoader());
context31.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context31.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, 0);
context31.getMetaData().setWebXml(Resource.newResource(web31true));
context31.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web31true)));
context31.getServletContext().setEffectiveMajorVersion(3);
context31.getServletContext().setEffectiveMinorVersion(1);
config31.configure(context31);
@ -162,7 +163,7 @@ public class TestAnnotationConfiguration
context31b.setClassLoader(Thread.currentThread().getContextClassLoader());
context31b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context31b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, 0);
context31b.getMetaData().setWebXml(Resource.newResource(web31false));
context31b.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web31false)));
context31b.getServletContext().setEffectiveMajorVersion(3);
context31b.getServletContext().setEffectiveMinorVersion(1);
config31b.configure(context31b);
@ -183,9 +184,9 @@ public class TestAnnotationConfiguration
//test 3.1 webapp loads both server and app scis
context.setClassLoader(webAppLoader);
context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL()));
context.getMetaData().setWebXml(Resource.newResource(web31true));
context.getMetaData().setWebInfClassesDirs(classes);
context.getMetaData().addWebInfResource(Resource.newResource(testSciJar.toURI().toURL()));
context.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web31true)));
context.getMetaData().setWebInfClassesResources(classes);
context.getServletContext().setEffectiveMajorVersion(3);
context.getServletContext().setEffectiveMinorVersion(1);
scis = config.getNonExcludedInitializers(context);
@ -215,9 +216,9 @@ public class TestAnnotationConfiguration
// test a 3.1 webapp with metadata-complete=false loads both server
// and webapp scis
context.setClassLoader(webAppLoader);
context.getMetaData().setWebXml(Resource.newResource(web31false));
context.getMetaData().setWebInfClassesDirs(classes);
context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL()));
context.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web31false)));
context.getMetaData().setWebInfClassesResources(classes);
context.getMetaData().addWebInfResource(Resource.newResource(testSciJar.toURI().toURL()));
context.getServletContext().setEffectiveMajorVersion(3);
context.getServletContext().setEffectiveMinorVersion(1);
scis = config.getNonExcludedInitializers(context);
@ -260,12 +261,12 @@ public class TestAnnotationConfiguration
WebAppContext context = new WebAppContext();
List<ServletContainerInitializer> scis;
context.setClassLoader(orderedLoader);
context.getMetaData().setWebXml(Resource.newResource(web31true));
context.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web31true)));
RelativeOrdering ordering = new RelativeOrdering(context.getMetaData());
context.getMetaData().setOrdering(ordering);
context.getMetaData().addWebInfJar(Resource.newResource(orderedFragmentJar.toURI().toURL()));
context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL()));
context.getMetaData().setWebInfClassesDirs(classes);
context.getMetaData().addWebInfResource(Resource.newResource(orderedFragmentJar.toURI().toURL()));
context.getMetaData().addWebInfResource(Resource.newResource(testSciJar.toURI().toURL()));
context.getMetaData().setWebInfClassesResources(classes);
context.getMetaData().orderFragments();
context.getServletContext().setEffectiveMajorVersion(3);
context.getServletContext().setEffectiveMinorVersion(1);
@ -295,9 +296,9 @@ public class TestAnnotationConfiguration
WebAppContext context = new WebAppContext();
List<ServletContainerInitializer> scis;
context.setClassLoader(webAppLoader);
context.getMetaData().setWebXml(Resource.newResource(web25));
context.getMetaData().setWebInfClassesDirs(classes);
context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL()));
context.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web25)));
context.getMetaData().setWebInfClassesResources(classes);
context.getMetaData().addWebInfResource(Resource.newResource(testSciJar.toURI().toURL()));
context.getServletContext().setEffectiveMajorVersion(2);
context.getServletContext().setEffectiveMinorVersion(5);
scis = config.getNonExcludedInitializers(context);
@ -332,9 +333,9 @@ public class TestAnnotationConfiguration
List<ServletContainerInitializer> scis;
context.setConfigurationDiscovered(true);
context.setClassLoader(webAppLoader);
context.getMetaData().setWebXml(Resource.newResource(web25));
context.getMetaData().setWebInfClassesDirs(classes);
context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL()));
context.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web25)));
context.getMetaData().setWebInfClassesResources(classes);
context.getMetaData().addWebInfResource(Resource.newResource(testSciJar.toURI().toURL()));
context.getServletContext().setEffectiveMajorVersion(2);
context.getServletContext().setEffectiveMinorVersion(5);
scis = config.getNonExcludedInitializers(context);
@ -349,24 +350,4 @@ public class TestAnnotationConfiguration
Thread.currentThread().setContextClassLoader(old);
}
}
@Test
public void testGetFragmentFromJar() throws Exception
{
String dir = MavenTestingUtils.getTargetTestingDir("getFragmentFromJar").getAbsolutePath();
File file = new File(dir);
file = new File(file.getCanonicalPath());
URL url = file.toURI().toURL();
Resource jar1 = Resource.newResource(url + "file.jar");
AnnotationConfiguration config = new AnnotationConfiguration();
WebAppContext wac = new WebAppContext();
List<FragmentDescriptor> frags = new ArrayList<FragmentDescriptor>();
frags.add(new FragmentDescriptor(Resource.newResource("jar:" + url + "file.jar!/fooa.props")));
frags.add(new FragmentDescriptor(Resource.newResource("jar:" + url + "file2.jar!/foob.props")));
assertNotNull(config.getFragmentFromJar(jar1, frags));
}
}

View File

@ -0,0 +1,127 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.annotations;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.Source;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.resource.EmptyResource;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebDescriptor;
import org.eclipse.jetty.xml.XmlParser;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestAnnotationDecorator
{
public class TestWebDescriptor extends WebDescriptor
{
public TestWebDescriptor(MetaData.Complete metadata)
{
super(EmptyResource.INSTANCE);
_metaDataComplete = metadata;
}
@Override
public void parse(XmlParser parser) throws Exception
{
}
@Override
public void processVersion()
{
}
@Override
public void processOrdering()
{
}
@Override
public void processDistributable()
{
}
@Override
public int getMajorVersion()
{
return 4;
}
@Override
public int getMinorVersion()
{
return 0;
}
}
@Test
public void testAnnotationDecorator() throws Exception
{
assertThrows(NullPointerException.class, () ->
{
new AnnotationDecorator(null);
});
WebAppContext context = new WebAppContext();
AnnotationDecorator decorator = new AnnotationDecorator(context);
ServletE servlet = new ServletE();
//test without BaseHolder metadata
decorator.decorate(servlet);
LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
assertNotNull(callbacks);
assertFalse(callbacks.getPreDestroyCallbacks().isEmpty());
//reset
context.removeAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
//test with BaseHolder metadata, should not introspect with metdata-complete==true
context.getMetaData().setWebDescriptor(new TestWebDescriptor(MetaData.Complete.True));
assertTrue(context.getMetaData().isMetaDataComplete());
ServletHolder holder = new ServletHolder(new Source(Source.Origin.DESCRIPTOR, ""));
holder.setHeldClass(ServletE.class);
context.getServletHandler().addServlet(holder);
DecoratedObjectFactory.associateInfo(holder);
decorator = new AnnotationDecorator(context);
decorator.decorate(servlet);
DecoratedObjectFactory.disassociateInfo();
callbacks = (LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
assertNull(callbacks);
//reset
context.removeAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
//test with BaseHolder metadata, should introspect with metadata-complete==false
context.getMetaData().setWebDescriptor(new TestWebDescriptor(MetaData.Complete.False));
DecoratedObjectFactory.associateInfo(holder);
decorator = new AnnotationDecorator(context);
decorator.decorate(servlet);
DecoratedObjectFactory.disassociateInfo();
callbacks = (LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
assertNotNull(callbacks);
assertFalse(callbacks.getPreDestroyCallbacks().isEmpty());
}
}

View File

@ -0,0 +1,98 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.annotations;
import java.io.File;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.Source;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebDescriptor;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestAnnotationIntrospector
{
@Test
public void testIsIntrospectable() throws Exception
{
try (StacklessLogging ignore = new StacklessLogging(AnnotationIntrospector.class))
{
WebAppContext wac = new WebAppContext();
AnnotationIntrospector introspector = new AnnotationIntrospector(wac);
//can't introspect nothing
assertFalse(introspector.isIntrospectable(null, null));
//can introspect if no metadata to say otherwise
assertTrue(introspector.isIntrospectable(new Object(), null));
//can introspect if metdata isn't a BaseHolder
assertTrue(introspector.isIntrospectable(new Object(), new Object()));
//an EMBEDDED sourced servlet can be introspected
ServletHolder holder = new ServletHolder();
holder.setHeldClass(ServletE.class);
assertTrue(introspector.isIntrospectable(new ServletE(), holder));
//a JAVAX API sourced servlet can be introspected
holder = new ServletHolder(Source.JAVAX_API);
holder.setHeldClass(ServletE.class);
assertTrue(introspector.isIntrospectable(new ServletE(), holder));
//an ANNOTATION sourced servlet can be introspected
holder = new ServletHolder(new Source(Source.Origin.ANNOTATION, ServletE.class.getName()));
holder.setHeldClass(ServletE.class);
assertTrue(introspector.isIntrospectable(new ServletE(), holder));
//a DESCRIPTOR sourced servlet can be introspected if web.xml metdata-complete==false
File file = MavenTestingUtils.getTestResourceFile("web31false.xml");
Resource resource = Resource.newResource(file);
wac.getMetaData().setWebDescriptor(new WebDescriptor(resource));
holder = new ServletHolder(new Source(Source.Origin.DESCRIPTOR, resource.toString()));
assertTrue(introspector.isIntrospectable(new ServletE(), holder));
//a DESCRIPTOR sourced servlet can be introspected if web-fragment.xml medata-complete==false && web.xml metadata-complete==false
file = MavenTestingUtils.getTestResourceFile("web-fragment4false.xml");
resource = Resource.newResource(file);
wac.getMetaData().addFragmentDescriptor(Resource.newResource(file.getParentFile()), new FragmentDescriptor(resource));
holder = new ServletHolder(new Source(Source.Origin.DESCRIPTOR, resource.toString()));
assertTrue(introspector.isIntrospectable(new ServletE(), holder));
//a DESCRIPTOR sourced servlet cannot be introspected if web-fragment.xml medata-complete==true (&& web.xml metadata-complete==false)
file = MavenTestingUtils.getTestResourceFile("web-fragment4true.xml");
resource = Resource.newResource(file);
wac.getMetaData().addFragmentDescriptor(Resource.newResource(file.getParentFile()), new FragmentDescriptor(resource));
holder = new ServletHolder(new Source(Source.Origin.DESCRIPTOR, resource.toString()));
assertFalse(introspector.isIntrospectable(new ServletE(), holder));
//a DESCRIPTOR sourced servlet cannot be introspected if web.xml medata-complete==true
file = MavenTestingUtils.getTestResourceFile("web31true.xml");
resource = Resource.newResource(file);
wac.getMetaData().setWebDescriptor(new WebDescriptor(resource));
holder = new ServletHolder(new Source(Source.Origin.DESCRIPTOR, resource.toString()));
assertFalse(introspector.isIntrospectable(new ServletE(), holder));
}
}
}

View File

@ -89,7 +89,7 @@ public class TestSecurityAnnotationConversions
//Assume we found 1 servlet with a @HttpConstraint with value=EmptyRoleSemantic.DENY security annotation
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
AnnotationIntrospector introspector = new AnnotationIntrospector();
AnnotationIntrospector introspector = new AnnotationIntrospector(wac);
introspector.registerHandler(annotationHandler);
//set up the expected outcomes:
@ -108,7 +108,7 @@ public class TestSecurityAnnotationConversions
expectedMappings[1].setConstraint(expectedConstraint);
expectedMappings[1].setPathSpec("*.foo");
introspector.introspect(DenyServlet.class);
introspector.introspect(new DenyServlet(), null);
compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@ -122,15 +122,15 @@ public class TestSecurityAnnotationConversions
});
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
AnnotationIntrospector introspector = new AnnotationIntrospector();
AnnotationIntrospector introspector = new AnnotationIntrospector(wac);
introspector.registerHandler(annotationHandler);
//set up the expected outcomes - no constraints at all as per Servlet Spec 3.1 pg 129
//1 ConstraintMapping per ServletMapping pathSpec
ConstraintMapping[] expectedMappings = new ConstraintMapping[]{};
introspector.introspect(PermitServlet.class);
PermitServlet permit = new PermitServlet();
introspector.introspect(permit, null);
compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@ -146,7 +146,7 @@ public class TestSecurityAnnotationConversions
});
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
AnnotationIntrospector introspector = new AnnotationIntrospector();
AnnotationIntrospector introspector = new AnnotationIntrospector(wac);
introspector.registerHandler(annotationHandler);
//set up the expected outcomes:compareResults
@ -164,8 +164,7 @@ public class TestSecurityAnnotationConversions
expectedMappings[1] = new ConstraintMapping();
expectedMappings[1].setConstraint(expectedConstraint);
expectedMappings[1].setPathSpec("*.foo");
introspector.introspect(RolesServlet.class);
introspector.introspect(new RolesServlet(), null);
compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@ -211,10 +210,10 @@ public class TestSecurityAnnotationConversions
expectedMappings[3].setPathSpec("*.foo");
expectedMappings[3].setMethod("GET");
AnnotationIntrospector introspector = new AnnotationIntrospector();
AnnotationIntrospector introspector = new AnnotationIntrospector(wac);
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
introspector.registerHandler(annotationHandler);
introspector.introspect(Method1Servlet.class);
introspector.introspect(new Method1Servlet(), null);
compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@ -227,7 +226,7 @@ public class TestSecurityAnnotationConversions
"/foo/*", "*.foo"
});
AnnotationIntrospector introspector = new AnnotationIntrospector();
AnnotationIntrospector introspector = new AnnotationIntrospector(wac);
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
introspector.registerHandler(annotationHandler);
@ -263,7 +262,7 @@ public class TestSecurityAnnotationConversions
expectedMappings[3].setPathSpec("*.foo");
expectedMappings[3].setMethod("GET");
introspector.introspect(Method2Servlet.class);
introspector.introspect(new Method2Servlet(), null);
compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}

View File

@ -73,11 +73,14 @@ public class TestResourceAnnotations
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false);
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false);
AnnotationIntrospector parser = new AnnotationIntrospector();
AnnotationIntrospector parser = new AnnotationIntrospector(wac);
ResourceAnnotationHandler handler = new ResourceAnnotationHandler(wac);
parser.registerHandler(handler);
parser.introspect(ResourceA.class);
parser.introspect(ResourceB.class);
ResourceA resourceA = new ResourceA();
ResourceB resourceB = new ResourceB();
parser.introspect(resourceA, null);
parser.introspect(resourceB, null);
//processing classA should give us these jndi name bindings:
// java:comp/env/myf
@ -155,11 +158,13 @@ public class TestResourceAnnotations
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false);
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false);
AnnotationIntrospector introspector = new AnnotationIntrospector();
AnnotationIntrospector introspector = new AnnotationIntrospector(wac);
ResourcesAnnotationHandler handler = new ResourcesAnnotationHandler(wac);
introspector.registerHandler(handler);
introspector.introspect(ResourceA.class);
introspector.introspect(ResourceB.class);
ResourceA resourceA = new ResourceA();
ResourceB resourceB = new ResourceB();
introspector.introspect(resourceA, null);
introspector.introspect(resourceB, null);
assertEquals(objA, env.lookup("peach"));
assertEquals(objB, env.lookup("pear"));

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-fragment_4_0.xsd"
version="4.0">
<name>ardvaark</name>
</web-fragment>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-fragment_4_0.xsd"
metadata-complete="true"
version="4.0">
<name>badger</name>
</web-fragment>

View File

@ -126,9 +126,9 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
continue;
Resource bundleRes = oparser.indexBundle(bundle);
if (!context.getMetaData().getWebInfJars().contains(bundleRes))
if (!context.getMetaData().getWebInfResources(false).contains(bundleRes))
{
context.getMetaData().addWebInfJar(bundleRes);
context.getMetaData().addWebInfResource(bundleRes);
}
if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null)

View File

@ -748,8 +748,9 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
injections.add(injection);
//Record which was the first descriptor to declare an injection for this name
if (context.getMetaData().getOriginDescriptor(node.getTag() + "." + jndiName + ".injection") == null)
context.getMetaData().setOrigin(node.getTag() + "." + jndiName + ".injection", descriptor);
String name = node.getTag() + "." + jndiName + ".injection";
if (context.getMetaData().getOriginDescriptor(name) == null)
context.getMetaData().setOrigin(name, descriptor);
}
catch (ClassNotFoundException e)
{

View File

@ -74,20 +74,20 @@ public class PlusDescriptorProcessorTest
URL webXml = Thread.currentThread().getContextClassLoader().getResource("web.xml");
webDescriptor = new WebDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(webXml));
webDescriptor.parse();
webDescriptor.parse(WebDescriptor.getParser(false));
URL frag1Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-1.xml");
fragDescriptor1 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag1Xml));
fragDescriptor1.parse();
fragDescriptor1.parse(WebDescriptor.getParser(false));
URL frag2Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-2.xml");
fragDescriptor2 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag2Xml));
fragDescriptor2.parse();
fragDescriptor2.parse(WebDescriptor.getParser(false));
URL frag3Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-3.xml");
fragDescriptor3 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag3Xml));
fragDescriptor3.parse();
fragDescriptor3.parse(WebDescriptor.getParser(false));
URL frag4Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-4.xml");
fragDescriptor4 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag4Xml));
fragDescriptor4.parse();
fragDescriptor4.parse(WebDescriptor.getParser(false));
}
@AfterEach

View File

@ -36,6 +36,7 @@ import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.StandardDescriptorProcessor;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebDescriptor;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
@ -211,9 +212,9 @@ public class QuickStartConfiguration extends AbstractConfiguration
context.setConfigurations(context.getConfigurations().stream()
.filter(c -> !__replacedConfigurations.contains(c.replaces()) && !__replacedConfigurations.contains(c.getClass()))
.collect(Collectors.toList()).toArray(new Configuration[]{}));
context.getMetaData().setWebXml((Resource)context.getAttribute(QUICKSTART_WEB_XML));
context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebXml().getMajorVersion());
context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebXml().getMinorVersion());
context.getMetaData().setWebDescriptor(new WebDescriptor((Resource)context.getAttribute(QUICKSTART_WEB_XML)));
context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebDescriptor().getMajorVersion());
context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebDescriptor().getMinorVersion());
}
/**

View File

@ -19,10 +19,12 @@
package org.eclipse.jetty.servlet;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.UnavailableException;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@ -177,6 +179,40 @@ public abstract class BaseHolder<T> extends AbstractLifeCycle implements Dumpabl
return _instance;
}
protected synchronized T createInstance() throws Exception
{
ServletContext ctx = getServletContext();
if (ctx == null)
return getHeldClass().getDeclaredConstructor().newInstance();
if (ServletContextHandler.Context.class.isAssignableFrom(ctx.getClass()))
return ((ServletContextHandler.Context)ctx).createInstance(this);
return null;
}
public ServletContext getServletContext()
{
ServletContext scontext = null;
//try the ServletHandler first
if (getServletHandler() != null)
scontext = getServletHandler().getServletContext();
if (scontext != null)
return scontext;
//try the ContextHandler next
Context ctx = ContextHandler.getCurrentContext();
if (ctx != null)
{
ContextHandler contextHandler = ctx.getContextHandler();
if (contextHandler != null)
return contextHandler.getServletContext();
}
return null;
}
/**
* @return True if this holder was created for a specific instance.
*/

View File

@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
@ -113,10 +114,7 @@ public class FilterHolder extends Holder<Filter>
{
try
{
ServletContext context = getServletHandler().getServletContext();
_filter = (context != null)
? context.createFilter(getHeldClass())
: getHeldClass().getDeclaredConstructor().newInstance();
_filter = createInstance();
}
catch (ServletException ex)
{
@ -135,6 +133,19 @@ public class FilterHolder extends Holder<Filter>
}
}
@Override
protected synchronized Filter createInstance() throws Exception
{
Filter filter = super.createInstance();
if (filter == null)
{
ServletContext context = getServletContext();
if (context != null)
filter = context.createFilter(getHeldClass());
}
return filter;
}
@Override
public void doStop()
throws Exception

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.servlet;
import java.util.EventListener;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@ -88,10 +89,7 @@ public class ListenerHolder extends BaseHolder<EventListener>
//create an instance of the listener and decorate it
try
{
ServletContext context = contextHandler.getServletContext();
_listener = (context != null)
? context.createListener(getHeldClass())
: getHeldClass().getDeclaredConstructor().newInstance();
_listener = createInstance();
}
catch (ServletException ex)
{
@ -107,6 +105,20 @@ public class ListenerHolder extends BaseHolder<EventListener>
}
}
@Override
protected synchronized EventListener createInstance() throws Exception
{
EventListener listener = super.createInstance();
if (listener == null)
{
ServletContext ctx = getServletContext();
if (ctx != null)
listener = ctx.createListener(getHeldClass());
}
return listener;
}
@Override
public void doStop() throws Exception
{

View File

@ -1261,6 +1261,21 @@ public class ServletContextHandler extends ContextHandler
return _objFactory.decorate(super.createInstance(clazz));
}
public <T> T createInstance(BaseHolder<T> holder) throws ServletException
{
try
{
//set a thread local
DecoratedObjectFactory.associateInfo(holder);
return createInstance(holder.getHeldClass());
}
finally
{
//unset the thread local
DecoratedObjectFactory.disassociateInfo();
}
}
public <T extends Filter> void destroyFilter(T f)
{
_objFactory.destroy(f);

View File

@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.TimeUnit;
import javax.servlet.GenericServlet;
import javax.servlet.MultipartConfigElement;
import javax.servlet.Servlet;
@ -1110,30 +1111,22 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
* @throws NoSuchMethodException if creating new instance resulted in error
* @throws InvocationTargetException If creating new instance throws an exception
*/
protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException,
NoSuchMethodException, InvocationTargetException
protected Servlet newInstance() throws Exception
{
try
{
ServletContext ctx = getServletHandler().getServletContext();
if (ctx != null)
return ctx.createServlet(getHeldClass());
return getHeldClass().getDeclaredConstructor().newInstance();
return createInstance();
}
}
catch (ServletException ex)
@Override
protected synchronized Servlet createInstance() throws Exception
{
Throwable cause = ex.getRootCause();
if (cause instanceof InstantiationException)
throw (InstantiationException)cause;
if (cause instanceof IllegalAccessException)
throw (IllegalAccessException)cause;
if (cause instanceof NoSuchMethodException)
throw (NoSuchMethodException)cause;
if (cause instanceof InvocationTargetException)
throw (InvocationTargetException)cause;
throw ex;
Servlet servlet = super.createInstance();
if (servlet == null)
{
ServletContext ctx = getServletContext();
if (ctx != null)
servlet = ctx.createServlet(getHeldClass());
}
return servlet;
}
@Override

View File

@ -33,7 +33,6 @@ public class Source
EMBEDDED, JAVAX_API, DESCRIPTOR, ANNOTATION
}
;
public Origin _origin;
public String _resource;

View File

@ -27,10 +27,12 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
/**
@ -38,6 +40,22 @@ import static org.junit.jupiter.api.Assertions.fail;
*/
public class FilterHolderTest
{
public static class DummyFilter implements Filter
{
public DummyFilter()
{
}
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
}
}
@Test
public void testInitialize()
@ -95,4 +113,28 @@ public class FilterHolderTest
fh.initialize();
assertEquals(2, counter.get());
}
@Test
public void testCreateInstance() throws Exception
{
try (StacklessLogging ignore = new StacklessLogging(ServletHandler.class, ServletContextHandler.class))
{
//test without a ServletContextHandler or current ContextHandler
FilterHolder holder = new FilterHolder();
holder.setName("foo");
holder.setHeldClass(DummyFilter.class);
Filter filter = holder.createInstance();
assertNotNull(filter);
//test with a ServletContextHandler
Server server = new Server();
ServletContextHandler context = new ServletContextHandler();
server.setHandler(context);
ServletHandler handler = context.getServletHandler();
handler.addFilter(holder);
holder.setServletHandler(handler);
context.start();
assertNotNull(holder.getFilter());
}
}
}

View File

@ -0,0 +1,57 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.servlet;
import java.util.EventListener;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class ListenerHolderTest
{
public static class DummyListener implements EventListener
{
}
@Test
public void testCreateInstance() throws Exception
{
try (StacklessLogging ignore = new StacklessLogging(ServletHandler.class, ServletContextHandler.class))
{
//test without a ServletContextHandler or current ContextHandler
ListenerHolder holder = new ListenerHolder();
holder.setHeldClass(DummyListener.class);
EventListener listener = holder.createInstance();
assertNotNull(listener);
//test with a ServletContextHandler
Server server = new Server();
ServletContextHandler context = new ServletContextHandler();
server.setHandler(context);
ServletHandler handler = context.getServletHandler();
handler.addListener(holder);
holder.setServletHandler(handler);
context.start();
assertNotNull(holder.getListener());
}
}
}

View File

@ -20,10 +20,13 @@ package org.eclipse.jetty.servlet;
import java.util.Collections;
import java.util.Set;
import javax.servlet.Servlet;
import javax.servlet.ServletRegistration;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.log.StacklessLogging;
@ -33,6 +36,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -114,6 +118,30 @@ public class ServletHolderTest
assertEquals("org.apache.jsp.a.b.c.blah_jsp", h.getClassNameForJsp("a/b/c/blah.jsp"));
}
@Test
public void testCreateInstance() throws Exception
{
try (StacklessLogging ignore = new StacklessLogging(ServletHandler.class, ContextHandler.class, ServletContextHandler.class))
{
//test without a ServletContextHandler or current ContextHandler
ServletHolder holder = new ServletHolder();
holder.setName("foo");
holder.setHeldClass(FakeServlet.class);
Servlet servlet = holder.createInstance();
assertNotNull(servlet);
//test with a ServletContextHandler
Server server = new Server();
ServletContextHandler context = new ServletContextHandler();
server.setHandler(context);
ServletHandler handler = context.getServletHandler();
handler.addServlet(holder);
holder.setServletHandler(handler);
context.start();
assertNotNull(holder.getServlet());
}
}
@Test
public void testNoClassName() throws Exception
{

View File

@ -46,8 +46,25 @@ public class DecoratedObjectFactory implements Iterable<Decorator>
*/
public static final String ATTR = DecoratedObjectFactory.class.getName();
private static final ThreadLocal<Object> decoratorInfo = new ThreadLocal<>();
private List<Decorator> decorators = new ArrayList<>();
public static void associateInfo(Object info)
{
decoratorInfo.set(info);
}
public static void disassociateInfo()
{
decoratorInfo.set(null);
}
public static Object getAssociatedInfo()
{
return decoratorInfo.get();
}
public void addDecorator(Decorator decorator)
{
LOG.debug("Adding Decorator: {}", decorator);
@ -70,7 +87,7 @@ public class DecoratedObjectFactory implements Iterable<Decorator>
{
if (LOG.isDebugEnabled())
{
LOG.debug("Creating Instance: " + clazz);
LOG.debug("Creating Instance: {}", clazz);
}
T o = clazz.getDeclaredConstructor().newInstance();
return decorate(o);

View File

@ -460,11 +460,18 @@ public class PathResource extends Resource
}
@Override
public boolean isContainedIn(Resource r) throws MalformedURLException
public boolean isContainedIn(Resource r)
{
try
{
PathResource pr = PathResource.class.cast(r);
return (path.startsWith(pr.getPath()));
}
catch (ClassCastException e)
{
// not applicable for FileSystem / path
return false;
}
}
@Override
public boolean isDirectory()

View File

@ -393,7 +393,7 @@ public class FileSystemResourceTest
try (Resource base = newResource(resourceClass, dir.toFile()))
{
Resource res = base.addPath("foo");
assertThat("is contained in", res.isContainedIn(base), is(false));
assertThat("is contained in", res.isContainedIn(base), is(true));
}
}

View File

@ -48,7 +48,7 @@ public class AbsoluteOrdering implements Ordering
//1. put everything into the list of named others, and take the named ones out of there,
//assuming we will want to use the <other> clause
Map<String, FragmentDescriptor> others = new HashMap<String, FragmentDescriptor>(_metaData.getNamedFragments());
Map<String, FragmentDescriptor> others = new HashMap<String, FragmentDescriptor>(_metaData.getNamedFragmentDescriptors());
//2. for each name, take out of the list of others, add to tail of list
int index = -1;
@ -59,7 +59,7 @@ public class AbsoluteOrdering implements Ordering
FragmentDescriptor f = others.remove(item);
if (f != null)
{
Resource jar = _metaData.getJarForFragment(item);
Resource jar = _metaData.getJarForFragmentName(item);
orderedList.add(jar); //take from others and put into final list in order, ignoring duplicate names
//remove resource from list for resource matching name of descriptor
tmp.remove(jar);

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.webapp;
import java.util.Objects;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlParser;
@ -26,30 +28,21 @@ public abstract class Descriptor
protected Resource _xml;
protected XmlParser.Node _root;
protected String _dtd;
protected boolean _validating;
public Descriptor(Resource xml)
{
_xml = xml;
_xml = Objects.requireNonNull(xml);
}
public abstract XmlParser ensureParser()
throws ClassNotFoundException;
public void setValidating(boolean validating)
{
_validating = validating;
}
public void parse()
public void parse(XmlParser parser)
throws Exception
{
if (_root == null)
{
Objects.requireNonNull(parser);
try
{
XmlParser parser = ensureParser();
_root = parser.parse(_xml.getInputStream());
_dtd = parser.getDTD();
}
@ -60,6 +53,11 @@ public abstract class Descriptor
}
}
public boolean isParsed()
{
return _root != null;
}
public Resource getResource()
{
return _xml;

View File

@ -52,6 +52,11 @@ public abstract class DiscoveredAnnotation
_resource = resource;
}
public String getClassName()
{
return _className;
}
public Resource getResource()
{
return _resource;
@ -84,4 +89,10 @@ public abstract class DiscoveredAnnotation
LOG.warn(e);
}
}
@Override
public String toString()
{
return getClass().getName() + "[" + getClassName() + "," + getResource() + "]";
}
}

View File

@ -66,11 +66,11 @@ public class FragmentConfiguration extends AbstractConfiguration
{
if (key.isDirectory()) //tolerate the case where the library is a directory, not a jar. useful for OSGi for example
{
metaData.addFragment(key, frags.get(key));
metaData.addFragmentDescriptor(key, new FragmentDescriptor(frags.get(key)));
}
else //the standard case: a jar most likely inside WEB-INF/lib
{
metaData.addFragment(key, frags.get(key));
metaData.addFragmentDescriptor(key, new FragmentDescriptor(frags.get(key)));
}
}
}

View File

@ -60,10 +60,10 @@ public class FragmentDescriptor extends WebDescriptor
}
@Override
public void parse()
public void parse(XmlParser parser)
throws Exception
{
super.parse();
super.parse(parser);
processName();
}

View File

@ -19,17 +19,22 @@
package org.eclipse.jetty.webapp;
import java.lang.annotation.Annotation;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.servlet.ServletContext;
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.EmptyResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlParser;
/**
* MetaData
@ -44,36 +49,67 @@ public class MetaData
public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs";
public static final Resource NON_FRAG_RESOURCE = EmptyResource.INSTANCE;
protected Map<String, OriginInfo> _origins = new HashMap<String, OriginInfo>();
protected Map<String, OriginInfo> _origins = new HashMap<>();
protected WebDescriptor _webDefaultsRoot;
protected WebDescriptor _webXmlRoot;
protected final List<WebDescriptor> _webOverrideRoots = new ArrayList<WebDescriptor>();
protected final List<WebDescriptor> _webOverrideRoots = new ArrayList<>();
protected boolean _metaDataComplete;
protected final List<DescriptorProcessor> _descriptorProcessors = new ArrayList<DescriptorProcessor>();
protected final List<FragmentDescriptor> _webFragmentRoots = new ArrayList<FragmentDescriptor>();
protected final Map<String, FragmentDescriptor> _webFragmentNameMap = new HashMap<String, FragmentDescriptor>();
protected final Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>();
protected final Map<Resource, List<DiscoveredAnnotation>> _annotations = new HashMap<Resource, List<DiscoveredAnnotation>>();
protected final List<Resource> _webInfClasses = new ArrayList<Resource>();
protected final List<Resource> _webInfJars = new ArrayList<Resource>();
protected final List<Resource> _orderedContainerResources = new ArrayList<Resource>();
protected final List<Resource> _orderedWebInfResources = new ArrayList<Resource>();
protected final List<DescriptorProcessor> _descriptorProcessors = new ArrayList<>();
protected final List<FragmentDescriptor> _webFragmentRoots = new ArrayList<>();
protected final Map<String, FragmentDescriptor> _webFragmentNameMap = new HashMap<>();
protected final Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<>();
protected final Map<Resource, List<DiscoveredAnnotation>> _annotations = new HashMap<>();
protected final List<Resource> _webInfClasses = new ArrayList<>();
protected final List<Resource> _webInfJars = new ArrayList<>();
protected final List<Resource> _orderedContainerResources = new ArrayList<>();
protected final List<Resource> _orderedWebInfResources = new ArrayList<>();
protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml
protected boolean _allowDuplicateFragmentNames = false;
protected boolean _validateXml = false;
public enum Complete
{
NotSet, True, False
}
/**
* Metadata regarding where a deployable element was declared:
* by annotation or by descriptor.
*
*/
public static class OriginInfo
{
/**
* Identifier for the deployable element
*/
private final String name;
/**
* Origin of the deployable element
*/
private final Origin origin;
/**
* Reference to the descriptor, if declared in one
*/
private final Descriptor descriptor;
/**
* Reference to the annotation, if declared by one
*/
private final Annotation annotation;
/**
* The class containing the annotation, if declared by one
*/
private final Class<?> annotated;
public OriginInfo(String n, Annotation a, Class<?> ac)
{
if (Objects.isNull(n))
throw new IllegalArgumentException("No name");
name = n;
origin = Origin.Annotation;
origin = Origin.of(a);
descriptor = null;
annotation = a;
annotated = ac;
@ -81,24 +117,21 @@ public class MetaData
public OriginInfo(String n, Descriptor d)
{
if (Objects.isNull(n))
throw new IllegalArgumentException("No name");
if (Objects.isNull(d))
throw new IllegalArgumentException("No descriptor");
name = n;
origin = Origin.of(d);
descriptor = d;
annotation = null;
annotated = null;
if (d == null)
throw new IllegalArgumentException("No descriptor");
if (d instanceof FragmentDescriptor)
origin = Origin.WebFragment;
else if (d instanceof OverrideDescriptor)
origin = Origin.WebOverride;
else if (d instanceof DefaultsDescriptor)
origin = Origin.WebDefaults;
else
origin = Origin.WebXml;
}
public OriginInfo(String n)
{
if (Objects.isNull(n))
throw new IllegalArgumentException("No name");
name = n;
origin = Origin.API;
annotation = null;
@ -159,12 +192,17 @@ public class MetaData
_allowDuplicateFragmentNames = false;
}
public void setDefaults(Resource webDefaults)
/**
* Set the web-default.xml.
*
* @param descriptor the web-default.xml
* @throws Exception
*/
public void setDefaultsDescriptor(DefaultsDescriptor descriptor)
throws Exception
{
_webDefaultsRoot = new DefaultsDescriptor(webDefaults);
_webDefaultsRoot.setValidating(isValidateXml());
_webDefaultsRoot.parse();
_webDefaultsRoot = descriptor;
_webDefaultsRoot.parse(WebDescriptor.getParser(isValidateXml()));
if (_webDefaultsRoot.isOrdered())
{
Ordering ordering = getOrdering();
@ -185,13 +223,16 @@ public class MetaData
}
}
public void setWebXml(Resource webXml)
/**
* @param descriptor the web.xml descriptor
* @throws Exception
*/
public void setWebDescriptor(WebDescriptor descriptor)
throws Exception
{
_webXmlRoot = new WebDescriptor(webXml);
_webXmlRoot.setValidating(isValidateXml());
_webXmlRoot.parse();
_metaDataComplete = _webXmlRoot.getMetaDataComplete() == MetaDataComplete.True;
_webXmlRoot = descriptor;
_webXmlRoot.parse(WebDescriptor.getParser(isValidateXml()));
_metaDataComplete = WebDescriptor.isMetaDataComplete(_webXmlRoot);
if (_webXmlRoot.isOrdered())
{
@ -213,14 +254,18 @@ public class MetaData
}
}
public void addOverride(Resource override)
/**
* Add a override-web.xml descriptor.
*
* @param descriptor the override-web.xml
* @throws Exception
*/
public void addOverrideDescriptor(OverrideDescriptor descriptor)
throws Exception
{
OverrideDescriptor webOverrideRoot = new OverrideDescriptor(override);
webOverrideRoot.setValidating(false);
webOverrideRoot.parse();
descriptor.parse(WebDescriptor.getParser(isValidateXml()));
switch (webOverrideRoot.getMetaDataComplete())
switch (descriptor.getMetaDataComplete())
{
case True:
_metaDataComplete = true;
@ -232,14 +277,14 @@ public class MetaData
break;
}
if (webOverrideRoot.isOrdered())
if (descriptor.isOrdered())
{
Ordering ordering = getOrdering();
if (ordering == null)
ordering = new AbsoluteOrdering(this);
List<String> order = webOverrideRoot.getOrdering();
List<String> order = descriptor.getOrdering();
for (String s : order)
{
if (s.equalsIgnoreCase("others"))
@ -251,29 +296,29 @@ public class MetaData
//set or reset the ordering to cause the webinf jar ordering to be recomputed
setOrdering(ordering);
}
_webOverrideRoots.add(webOverrideRoot);
_webOverrideRoots.add(descriptor);
}
/**
* Add a web-fragment.xml
* Add a web-fragment.xml, and the jar it is contained in.
*
* @param jarResource the jar the fragment is contained in
* @param xmlResource the resource representing the xml file
* @param jarResource the jar of the fragment
* @param descriptor web-fragment.xml
* @throws Exception if unable to add fragment
*/
public void addFragment(Resource jarResource, Resource xmlResource)
public void addFragmentDescriptor(Resource jarResource, FragmentDescriptor descriptor)
throws Exception
{
if (_metaDataComplete)
return; //do not process anything else if web.xml/web-override.xml set metadata-complete
Objects.requireNonNull(jarResource);
Objects.requireNonNull(descriptor);
//Metadata-complete is not set, or there is no web.xml
FragmentDescriptor descriptor = new FragmentDescriptor(xmlResource);
_webFragmentResourceMap.put(jarResource, descriptor);
_webFragmentRoots.add(descriptor);
descriptor.setValidating(isValidateXml());
descriptor.parse();
descriptor.parse(WebDescriptor.getParser(isValidateXml()));
if (descriptor.getName() != null)
{
@ -298,8 +343,8 @@ public class MetaData
}
/**
* Annotations not associated with a WEB-INF/lib fragment jar.
* These are from WEB-INF/classes or the ??container path??
* Annotations such as WebServlet, WebFilter, WebListener that
* can be discovered by scanning unloaded classes.
*
* @param annotations the list of discovered annotations to add
*/
@ -315,7 +360,8 @@ public class MetaData
/**
* Add an annotation that has been discovered on a class, method or field within a resource
* eg a jar or dir.
* eg a jar or dir. The annotation may also have no associated resource, or that resource
* may be a system or container resource.
*
* This method is synchronized as it is anticipated that it may be called by many threads
* during the annotation scanning phase.
@ -327,21 +373,69 @@ public class MetaData
if (annotation == null)
return;
//if no resource associated with an annotation or the resource is not one of the WEB-INF/lib jars,
//map it to empty resource
//if no resource associated with an annotation map it to empty resource - these
//annotations will always be processed first
Resource enclosingResource = EmptyResource.INSTANCE;
Resource resource = annotation.getResource();
if (resource == null || !_webInfJars.contains(resource))
resource = EmptyResource.INSTANCE;
if (resource != null)
{
//check if any of the web-inf classes dirs is a parent
enclosingResource = getEnclosingResource(_webInfClasses, resource);
List<DiscoveredAnnotation> list = _annotations.get(resource);
//check if any of the web-inf jars is a parent
if (enclosingResource == null)
enclosingResource = getEnclosingResource(_webInfJars, resource);
//check if any of the container resources is a parent
if (enclosingResource == null)
enclosingResource = getEnclosingResource(_orderedContainerResources, resource);
//Couldn't find a parent resource in any of the known resources, map it to the empty resource
if (enclosingResource == null)
enclosingResource = EmptyResource.INSTANCE;
}
List<DiscoveredAnnotation> list = _annotations.get(enclosingResource);
if (list == null)
{
list = new ArrayList<DiscoveredAnnotation>();
_annotations.put(resource, list);
list = new ArrayList<>();
_annotations.put(enclosingResource, list);
}
list.add(annotation);
}
/**
* Check if the resource is contained within one of the list of resources.
* In other words, check if the given resource is a sub-resource of one
* of the list of resources.
*
* @param resources the list of resources to check against
* @param resource the resource for which to find the parent resource
* @return the resource from the list that contains the given resource.
*/
private Resource getEnclosingResource(List<Resource> resources, Resource resource)
{
Resource enclosingResource = null;
try
{
for (Resource r : resources)
{
if (Resource.isContainedIn(resource, r))
{
enclosingResource = r;
break;
}
}
return enclosingResource;
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
public void addDescriptorProcessor(DescriptorProcessor p)
{
_descriptorProcessors.add(p);
@ -375,9 +469,9 @@ public class MetaData
// Set the ordered lib attribute
List<Resource> orderedWebInfJars = null;
if (getOrdering() != null)
if (isOrdered())
{
orderedWebInfJars = getOrderedWebInfJars();
orderedWebInfJars = getWebInfResources(true);
List<String> orderedLibs = new ArrayList<String>();
for (Resource webInfJar : orderedWebInfJars)
{
@ -387,7 +481,7 @@ public class MetaData
int j = fullname.lastIndexOf("/", i);
orderedLibs.add(fullname.substring(j + 1, i + 4));
}
context.setAttribute(ServletContext.ORDERED_LIBS, orderedLibs);
context.setAttribute(ServletContext.ORDERED_LIBS, Collections.unmodifiableList(orderedLibs));
}
// set the webxml version
@ -397,40 +491,29 @@ public class MetaData
context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion());
}
//process web-defaults.xml, web.xml and override-web.xmls
for (DescriptorProcessor p : _descriptorProcessors)
{
p.process(context, getWebDefault());
p.process(context, getWebXml());
for (WebDescriptor wd : getOverrideWebs())
p.process(context, getDefaultsDescriptor());
p.process(context, getWebDescriptor());
for (WebDescriptor wd : getOverrideDescriptors())
{
LOG.debug("process {} {} {}", context, p, wd);
p.process(context, wd);
}
}
//get an apply the annotations that are not associated with a fragment (and hence for
//which no ordering applies
List<DiscoveredAnnotation> nonFragAnnotations = _annotations.get(NON_FRAG_RESOURCE);
if (nonFragAnnotations != null)
{
for (DiscoveredAnnotation a : nonFragAnnotations)
{
LOG.debug("apply {}", a);
a.apply();
}
}
//apply the annotations that are associated with a fragment, according to the
//established ordering
List<Resource> resources = null;
if (getOrdering() != null)
resources = orderedWebInfJars;
else
resources = getWebInfJars();
List<Resource> resources = new ArrayList<>();
resources.add(EmptyResource.INSTANCE); //always apply annotations with no resource first
resources.addAll(_orderedContainerResources); //next all annotations from container path
resources.addAll(_webInfClasses);//next everything from web-inf classes
resources.addAll(getWebInfResources(isOrdered())); //finally annotations (in order) from webinf path
for (Resource r : resources)
{
//Process the web-fragment.xml before applying annotations from a fragment.
//Note that some fragments, or resources that aren't fragments won't have
//a descriptor.
FragmentDescriptor fd = _webFragmentResourceMap.get(r);
if (fd != null)
{
@ -441,10 +524,13 @@ public class MetaData
}
}
List<DiscoveredAnnotation> fragAnnotations = _annotations.get(r);
if (fragAnnotations != null)
//Then apply the annotations - note that if metadata is complete
//either overall or for a fragment, those annotations won't have
//been discovered.
List<DiscoveredAnnotation> annotations = _annotations.get(r);
if (annotations != null)
{
for (DiscoveredAnnotation a : fragAnnotations)
for (DiscoveredAnnotation a : annotations)
{
LOG.debug("apply {}", a);
a.apply();
@ -453,6 +539,13 @@ public class MetaData
}
}
/**
* A webapp is distributable if web.xml is metadata-complete and
* distributable=true, or if metadata-complete is false, but all
* web-fragments.xml are distributable=true.
*
* @return true if the webapp is distributable, false otherwise
*/
public boolean isDistributable()
{
boolean distributable = (
@ -464,9 +557,9 @@ public class MetaData
distributable &= d.isDistributable();
}
if (getOrdering() != null)
if (isOrdered())
{
List<Resource> orderedResources = getOrderedWebInfJars();
List<Resource> orderedResources = getWebInfResources(true);
for (Resource r : orderedResources)
{
FragmentDescriptor d = _webFragmentResourceMap.get(r);
@ -477,44 +570,24 @@ public class MetaData
return distributable;
}
public WebDescriptor getWebXml()
public WebDescriptor getWebDescriptor()
{
return _webXmlRoot;
}
public List<WebDescriptor> getOverrideWebs()
public List<WebDescriptor> getOverrideDescriptors()
{
return _webOverrideRoots;
}
public WebDescriptor getWebDefault()
public WebDescriptor getDefaultsDescriptor()
{
return _webDefaultsRoot;
}
public List<FragmentDescriptor> getFragments()
public boolean isOrdered()
{
return _webFragmentRoots;
}
public List<Resource> getOrderedWebInfJars()
{
return _orderedWebInfResources;
}
public List<FragmentDescriptor> getOrderedFragments()
{
List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>();
if (getOrdering() == null)
return list;
for (Resource r : getOrderedWebInfJars())
{
FragmentDescriptor fd = _webFragmentResourceMap.get(r);
if (fd != null)
list.add(fd);
}
return list;
return getOrdering() != null;
}
public Ordering getOrdering()
@ -528,32 +601,60 @@ public class MetaData
orderFragments();
}
public FragmentDescriptor getFragment(Resource jar)
{
return _webFragmentResourceMap.get(jar);
}
public FragmentDescriptor getFragment(String name)
/**
* @param name the name specified in a web-fragment.xml
* @return the web-fragment.xml that defines that name or null
*/
public FragmentDescriptor getFragmentDescriptor(String name)
{
return _webFragmentNameMap.get(name);
}
public Resource getJarForFragment(String name)
/**
* @param descriptorResource the web-fragment.xml location as a Resource
* @return the FrgmentDescriptor for the web-fragment.xml, or null if none exists
*/
public FragmentDescriptor getFragmentDescriptor(Resource descriptorResource)
{
FragmentDescriptor f = getFragment(name);
return _webFragmentRoots.stream().filter(d -> d.getResource().equals(descriptorResource)).findFirst().orElse(null);
}
/**
* @param name the name specified in a web-fragment.xml
* @return the jar that contains the web-fragment.xml with the given name or null
*/
public Resource getJarForFragmentName(String name)
{
Resource jar = null;
FragmentDescriptor f = getFragmentDescriptor(name);
if (f == null)
return null;
Resource jar = null;
for (Resource r : _webFragmentResourceMap.keySet())
for (Map.Entry<Resource,FragmentDescriptor> entry : _webFragmentResourceMap.entrySet())
{
if (_webFragmentResourceMap.get(r).equals(f))
jar = r;
if (entry.getValue().equals(f))
jar = entry.getKey();
}
return jar;
}
public Map<String, FragmentDescriptor> getNamedFragments()
/**
* Get the web-fragment.xml related to a jar
*
* @param jar the jar to check for a mapping to web-fragment.xml
* @return the FragmentDescriptor or null if no web-fragment.xml is associated with the jar
*/
public FragmentDescriptor getFragmentDescriptorForJar(Resource jar)
{
return _webFragmentResourceMap.get(jar);
}
/**
* @return a map of name to FragmentDescriptor, for those FragmentDescriptors that
* define a name element.
*/
public Map<String, FragmentDescriptor> getNamedFragmentDescriptors()
{
return Collections.unmodifiableMap(_webFragmentNameMap);
}
@ -586,6 +687,9 @@ public class MetaData
public void setOrigin(String name, Descriptor d)
{
if (name == null)
return;
OriginInfo x = new OriginInfo(name, d);
_origins.put(name, x);
}
@ -613,19 +717,22 @@ public class MetaData
return _metaDataComplete;
}
public void addWebInfJar(Resource newResource)
public void addWebInfResource(Resource newResource)
{
_webInfJars.add(newResource);
}
public List<Resource> getWebInfJars()
public List<Resource> getWebInfResources(boolean withOrdering)
{
if (!withOrdering)
return Collections.unmodifiableList(_webInfJars);
else
return Collections.unmodifiableList(_orderedWebInfResources);
}
public List<Resource> getContainerResources()
{
return _orderedContainerResources;
return Collections.unmodifiableList(_orderedContainerResources);
}
public void addContainerResource(Resource jar)
@ -633,14 +740,14 @@ public class MetaData
_orderedContainerResources.add(jar);
}
public void setWebInfClassesDirs(List<Resource> dirs)
public void setWebInfClassesResources(List<Resource> dirs)
{
_webInfClasses.addAll(dirs);
}
public List<Resource> getWebInfClassesDirs()
public List<Resource> getWebInfClassesResources()
{
return _webInfClasses;
return Collections.unmodifiableList(_webInfClasses);
}
public boolean isAllowDuplicateFragmentNames()
@ -650,11 +757,11 @@ public class MetaData
public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)
{
this._allowDuplicateFragmentNames = allowDuplicateFragmentNames;
_allowDuplicateFragmentNames = allowDuplicateFragmentNames;
}
/**
* @return the validateXml
* @return true if the parser validates, false otherwise
*/
public boolean isValidateXml()
{
@ -662,7 +769,7 @@ public class MetaData
}
/**
* @param validateXml the validateXml to set
* @param validateXml if true xml syntax is validated by the parser, false otherwise
*/
public void setValidateXml(boolean validateXml)
{

View File

@ -144,7 +144,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
@Override
public void matched(URI uri) throws Exception
{
_context.getMetaData().addWebInfJar(Resource.newResource(uri));
_context.getMetaData().addWebInfResource(Resource.newResource(uri));
}
}
@ -169,7 +169,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
findAndFilterWebAppPaths(context);
//No pattern to appy to classes, just add to metadata
context.getMetaData().setWebInfClassesDirs(findClassDirs(context));
context.getMetaData().setWebInfClassesResources(findClassDirs(context));
scanJars(context);
}
@ -358,7 +358,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
List<String> scanTypes = new ArrayList<>(__allScanTypes);
if (context.getMetaData().isMetaDataComplete() || (context.getServletContext().getEffectiveMajorVersion() < 3) && !context.isConfigurationDiscovered())
scanTypes.remove(METAINF_FRAGMENTS);
scanJars(context, context.getMetaData().getWebInfJars(), false, scanTypes);
scanJars(context, context.getMetaData().getWebInfResources(false), false, scanTypes);
}
/**

View File

@ -20,5 +20,23 @@ package org.eclipse.jetty.webapp;
public enum Origin
{
NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation, API
NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation, API;
public static Origin of(Object o)
{
if (o == null)
return null;
if (o instanceof java.lang.annotation.Annotation)
return Annotation;
if (o instanceof FragmentDescriptor)
return WebFragment;
else if (o instanceof OverrideDescriptor)
return WebOverride;
else if (o instanceof DefaultsDescriptor)
return WebDefaults;
else if (o instanceof WebDescriptor)
return WebXml;
else
return API;
}
}

View File

@ -52,7 +52,7 @@ public class RelativeOrdering implements Ordering
// Pass 1: split the jars into 'before others', 'others' or 'after others'
for (Resource jar : jars)
{
FragmentDescriptor fragment = _metaData.getFragment(jar);
FragmentDescriptor fragment = _metaData.getFragmentDescriptorForJar(jar);
if (fragment == null)
others.add(jar);
@ -79,7 +79,7 @@ public class RelativeOrdering implements Ordering
Set<Resource> referenced = new HashSet<>();
for (Resource jar : jars)
{
FragmentDescriptor fragment = _metaData.getFragment(jar);
FragmentDescriptor fragment = _metaData.getFragmentDescriptorForJar(jar);
if (fragment != null)
{
@ -87,7 +87,7 @@ public class RelativeOrdering implements Ordering
// and remember that the dependency has been referenced.
for (String name : fragment.getAfters())
{
Resource after = _metaData.getJarForFragment(name);
Resource after = _metaData.getJarForFragmentName(name);
sort.addDependency(jar, after);
referenced.add(after);
}
@ -96,7 +96,7 @@ public class RelativeOrdering implements Ordering
// and remember that the dependency has been referenced.
for (String name : fragment.getBefores())
{
Resource before = _metaData.getJarForFragment(name);
Resource before = _metaData.getJarForFragmentName(name);
sort.addDependency(before, jar);
referenced.add(before);
}

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.webapp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -97,7 +96,6 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
registerVisitor("filter", this.getClass().getMethod("visitFilter", __signature));
registerVisitor("filter-mapping", this.getClass().getMethod("visitFilterMapping", __signature));
registerVisitor("listener", this.getClass().getMethod("visitListener", __signature));
registerVisitor("distributable", this.getClass().getMethod("visitDistributable", __signature));
registerVisitor("deny-uncovered-http-methods", this.getClass().getMethod("visitDenyUncoveredHttpMethods", __signature));
registerVisitor("default-context-path", this.getClass().getMethod("visitDefaultContextPath", __signature));
registerVisitor("request-character-encoding", this.getClass().getMethod("visitRequestCharacterEncoding", __signature));
@ -1894,7 +1892,6 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
public void visitListener(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
{
String className = node.getString("listener-class", false, true);
EventListener listener = null;
try
{
if (className != null && className.length() > 0)
@ -1922,14 +1919,6 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
}
}
public void visitDistributable(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
{
// the element has no content, so its simple presence
// indicates that the webapp is distributable...
//Servlet Spec 3.0 p.74 distributable only if all fragments are distributable
((WebDescriptor)descriptor).setDistributable(true);
}
/**
* Servlet spec 3.1. When present in web.xml, this means that http methods that are
* not covered by security constraints should have access denied.

View File

@ -39,32 +39,50 @@ public class WebDescriptor extends Descriptor
{
private static final Logger LOG = Log.getLogger(WebDescriptor.class);
protected static XmlParser _nonValidatingStaticParser;
protected MetaDataComplete _metaDataComplete;
public static XmlParser __nonValidatingStaticParser = newParser(false);
protected MetaData.Complete _metaDataComplete;
protected int _majorVersion = 4; //default to container version
protected int _minorVersion = 0;
protected ArrayList<String> _classNames = new ArrayList<String>();
protected ArrayList<String> _classNames = new ArrayList<>();
protected boolean _distributable;
protected boolean _isOrdered = false;
protected List<String> _ordering = new ArrayList<String>();
protected List<String> _ordering = new ArrayList<>();
@Override
public XmlParser ensureParser() throws ClassNotFoundException
/**
* Check if the descriptor is metadata-complete.
*
* @param d the descriptor (web.xml, web-fragment.xml,
* web-default.xml, web-override.xml) to check
*
* @return true iff metadata-complete=true is declared in the
* descriptor
*/
public static boolean isMetaDataComplete(WebDescriptor d)
{
synchronized (WebDescriptor.class)
{
if (_nonValidatingStaticParser == null)
_nonValidatingStaticParser = newParser(false);
return (d != null && d.getMetaDataComplete() == MetaData.Complete.True);
}
if (!isValidating())
return _nonValidatingStaticParser;
/**
* Get a parser for parsing web descriptor content.
*
* @param validating true if the parser should validate syntax, false otherwise
* @return an XmlParser for web descriptors
*/
public static XmlParser getParser(boolean validating)
{
if (!validating)
return __nonValidatingStaticParser;
else
return newParser(true);
}
public static XmlParser newParser(boolean validating) throws ClassNotFoundException
/**
* Create a new parser for parsing web descriptors.
*
* @param validating if true, the parser will validate syntax
* @return an XmlParser
*/
public static XmlParser newParser(boolean validating)
{
XmlParser xmlParser = new XmlParser(validating)
{
@ -218,15 +236,16 @@ public class WebDescriptor extends Descriptor
}
@Override
public void parse()
public void parse(XmlParser parser)
throws Exception
{
super.parse();
super.parse(parser);
processVersion();
processOrdering();
processDistributable();
}
public MetaDataComplete getMetaDataComplete()
public MetaData.Complete getMetaDataComplete()
{
return _metaDataComplete;
}
@ -266,14 +285,14 @@ public class WebDescriptor extends Descriptor
}
if (_majorVersion <= 2 && _minorVersion < 5)
_metaDataComplete = MetaDataComplete.True; // does not apply before 2.5
_metaDataComplete = MetaData.Complete.True; // does not apply before 2.5
else
{
String s = (String)_root.getAttribute("metadata-complete");
if (s == null)
_metaDataComplete = MetaDataComplete.NotSet;
_metaDataComplete = MetaData.Complete.NotSet;
else
_metaDataComplete = Boolean.valueOf(s).booleanValue() ? MetaDataComplete.True : MetaDataComplete.False;
_metaDataComplete = Boolean.valueOf(s).booleanValue() ? MetaData.Complete.True : MetaData.Complete.False;
}
if (LOG.isDebugEnabled())
@ -309,6 +328,14 @@ public class WebDescriptor extends Descriptor
}
}
public void processDistributable()
{
XmlParser.Node distributable = _root.get("distributable");
if (distributable == null)
return; //no <distributable> element
_distributable = true;
}
public void addClassName(String className)
{
if (!_classNames.contains(className))
@ -320,27 +347,11 @@ public class WebDescriptor extends Descriptor
return _classNames;
}
public void setDistributable(boolean distributable)
{
_distributable = distributable;
}
public boolean isDistributable()
{
return _distributable;
}
@Override
public void setValidating(boolean validating)
{
_validating = validating;
}
public boolean isValidating()
{
return _validating;
}
public boolean isOrdered()
{
return _isOrdered;

View File

@ -57,16 +57,16 @@ public class WebXmlConfiguration extends AbstractConfiguration
if (dftResource == null)
dftResource = context.newResource(defaultsDescriptor);
}
context.getMetaData().setDefaults(dftResource);
context.getMetaData().setDefaultsDescriptor(new DefaultsDescriptor(dftResource));
}
//parse, but don't process web.xml
Resource webxml = findWebXml(context);
if (webxml != null)
{
context.getMetaData().setWebXml(webxml);
context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebXml().getMajorVersion());
context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebXml().getMinorVersion());
context.getMetaData().setWebDescriptor(new WebDescriptor(webxml));
context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebDescriptor().getMajorVersion());
context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebDescriptor().getMinorVersion());
}
//parse but don't process override-web.xml
@ -77,7 +77,7 @@ public class WebXmlConfiguration extends AbstractConfiguration
Resource orideResource = Resource.newSystemResource(overrideDescriptor);
if (orideResource == null)
orideResource = context.newResource(overrideDescriptor);
context.getMetaData().addOverride(orideResource);
context.getMetaData().addOverrideDescriptor(new OverrideDescriptor(orideResource));
}
}
}

View File

@ -0,0 +1,49 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.acme.webapp;
import java.util.List;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
import org.eclipse.jetty.webapp.WebAppContext;
public class TestAnnotation extends DiscoveredAnnotation
{
private List<TestAnnotation> applications;
public TestAnnotation(WebAppContext context, String className, Resource resource, List<TestAnnotation> applications)
{
super(context, className, resource);
this.applications = applications;
}
@Override
public void apply()
{
if (applications != null)
applications.add(this);
}
@Override
public String toString()
{
return getClassName();
}
}

View File

@ -88,7 +88,7 @@ public class MetaInfConfigurationTest
MetaInfConfiguration meta25 = new TestableMetaInfConfiguration(MetaInfConfiguration.__allScanTypes,
Arrays.asList(MetaInfConfiguration.METAINF_TLDS, MetaInfConfiguration.METAINF_RESOURCES));
WebAppContext context25 = new WebAppContext();
context25.getMetaData().setWebXml(Resource.newResource(web25));
context25.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web25)));
context25.getServletContext().setEffectiveMajorVersion(2);
context25.getServletContext().setEffectiveMinorVersion(5);
meta25.preConfigure(context25);
@ -98,7 +98,7 @@ public class MetaInfConfigurationTest
MetaInfConfiguration.__allScanTypes);
WebAppContext context25b = new WebAppContext();
context25b.setConfigurationDiscovered(true);
context25b.getMetaData().setWebXml(Resource.newResource(web25));
context25b.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web25)));
context25b.getServletContext().setEffectiveMajorVersion(2);
context25b.getServletContext().setEffectiveMinorVersion(5);
meta25b.preConfigure(context25b);
@ -107,7 +107,7 @@ public class MetaInfConfigurationTest
MetaInfConfiguration meta31 = new TestableMetaInfConfiguration(MetaInfConfiguration.__allScanTypes,
Arrays.asList(MetaInfConfiguration.METAINF_TLDS, MetaInfConfiguration.METAINF_RESOURCES));
WebAppContext context31 = new WebAppContext();
context31.getMetaData().setWebXml(Resource.newResource(web31));
context31.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web31)));
context31.getServletContext().setEffectiveMajorVersion(3);
context31.getServletContext().setEffectiveMinorVersion(1);
meta31.preConfigure(context31);
@ -117,7 +117,7 @@ public class MetaInfConfigurationTest
MetaInfConfiguration.__allScanTypes);
WebAppContext context31false = new WebAppContext();
context31false.setConfigurationDiscovered(true);
context31false.getMetaData().setWebXml(Resource.newResource(web31false));
context31false.getMetaData().setWebDescriptor(new WebDescriptor(Resource.newResource(web31false)));
context31false.getServletContext().setEffectiveMajorVersion(3);
context31false.getServletContext().setEffectiveMinorVersion(1);
meta31false.preConfigure(context31false);

View File

@ -478,11 +478,11 @@ public class OrderingTest
final Resource jarResource = new TestResource("A");
metadata.setOrdering(new RelativeOrdering(metadata));
metadata.addWebInfJar(jarResource);
metadata.addWebInfResource(jarResource);
metadata.orderFragments();
assertEquals(1, metadata.getOrderedWebInfJars().size());
assertEquals(1, metadata.getWebInfResources(true).size());
metadata.orderFragments();
assertEquals(1, metadata.getOrderedWebInfJars().size());
assertEquals(1, metadata.getWebInfResources(true).size());
}
@Test
@ -625,7 +625,7 @@ public class OrderingTest
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor((Resource)null);
FragmentDescriptor f4 = new FragmentDescriptor(r4);
f4._name = "D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4, f4);
@ -633,7 +633,7 @@ public class OrderingTest
TestResource jar5 = new TestResource("E");
resources.add(jar5);
TestResource r5 = new TestResource("E/web-fragment.xml");
FragmentDescriptor f5 = new FragmentDescriptor((Resource)null);
FragmentDescriptor f5 = new FragmentDescriptor(r5);
f5._name = "E";
metaData._webFragmentNameMap.put(f5._name, f5);
metaData._webFragmentResourceMap.put(jar5, f5);
@ -641,7 +641,7 @@ public class OrderingTest
TestResource jar6 = new TestResource("plain");
resources.add(jar6);
TestResource r6 = new TestResource("plain/web-fragment.xml");
FragmentDescriptor f6 = new FragmentDescriptor((Resource)null);
FragmentDescriptor f6 = new FragmentDescriptor(r6);
f6._name = FragmentDescriptor.NAMELESS + "1";
metaData._webFragmentNameMap.put(f6._name, f6);
metaData._webFragmentResourceMap.put(jar6, f6);
@ -897,7 +897,7 @@ public class OrderingTest
TestResource jar4 = new TestResource("D");
resources.add(jar4);
TestResource r4 = new TestResource("D/web-fragment.xml");
FragmentDescriptor f4 = new FragmentDescriptor((Resource)null);
FragmentDescriptor f4 = new FragmentDescriptor(r4);
f4._name = "D";
metaData._webFragmentNameMap.put(f4._name, f4);
metaData._webFragmentResourceMap.put(jar4, f4);
@ -905,7 +905,7 @@ public class OrderingTest
TestResource jar5 = new TestResource("E");
resources.add(jar5);
TestResource r5 = new TestResource("E/web-fragment.xml");
FragmentDescriptor f5 = new FragmentDescriptor((Resource)null);
FragmentDescriptor f5 = new FragmentDescriptor(r5);
f5._name = "E";
metaData._webFragmentNameMap.put(f5._name, f5);
metaData._webFragmentResourceMap.put(jar5, f5);
@ -913,7 +913,7 @@ public class OrderingTest
TestResource jar6 = new TestResource("plain");
resources.add(jar6);
TestResource r6 = new TestResource("plain/web-fragment.xml");
FragmentDescriptor f6 = new FragmentDescriptor((Resource)null);
FragmentDescriptor f6 = new FragmentDescriptor(r6);
f6._name = FragmentDescriptor.NAMELESS + "1";
metaData._webFragmentNameMap.put(f6._name, f6);
metaData._webFragmentResourceMap.put(jar6, f6);

View File

@ -0,0 +1,204 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.webapp;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.acme.webapp.TestAnnotation;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.EmptyResource;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestMetaData
{
File fragFile;
File nonFragFile;
Resource fragResource;
Resource nonFragResource;
Resource webfragxml;
Resource containerDir;
Resource webInfClassesDir;
WebAppContext wac;
TestAnnotation annotationA;
TestAnnotation annotationB;
TestAnnotation annotationC;
TestAnnotation annotationD;
TestAnnotation annotationE;
List<TestAnnotation> applications;
@BeforeEach
public void setUp() throws Exception
{
File jarDir = new File(MavenTestingUtils.getTestResourcesDir(), "fragments");
assertTrue(jarDir.exists());
fragFile = new File(jarDir, "zeta.jar");
assertTrue(fragFile.exists());
fragResource = Resource.newResource(fragFile);
nonFragFile = new File(jarDir, "sigma.jar");
nonFragResource = Resource.newResource(nonFragFile);
assertTrue(nonFragFile.exists());
webfragxml = Resource.newResource("jar:" + fragFile.toURI().toString() + "!/META-INF/web-fragment.xml");
containerDir = Resource.newResource(MavenTestingUtils.getTargetTestingDir("container"));
webInfClassesDir = Resource.newResource(MavenTestingUtils.getTargetTestingDir("webinfclasses"));
wac = new WebAppContext();
applications = new ArrayList<>();
annotationA = new TestAnnotation(wac, "com.acme.A", fragResource, applications);
annotationB = new TestAnnotation(wac, "com.acme.B", nonFragResource, applications);
annotationC = new TestAnnotation(wac, "com.acme.C", null, applications);
annotationD = new TestAnnotation(wac, "com.acme.D", containerDir, applications);
annotationE = new TestAnnotation(wac, "com.acme.E", webInfClassesDir, applications);
}
@Test
public void testAddWebInfResource() throws Exception
{
assertTrue(wac.getMetaData().getWebInfResources(false).isEmpty());
wac.getMetaData().addWebInfResource(fragResource);
wac.getMetaData().addWebInfResource(nonFragResource);
assertTrue(wac.getMetaData().getWebInfResources(false).contains(fragResource));
assertTrue(wac.getMetaData().getWebInfResources(false).contains(nonFragResource));
}
@Test
public void testGetFragmentForJar() throws Exception
{
wac.getMetaData().addWebInfResource(fragResource);
wac.getMetaData().addWebInfResource(nonFragResource);
wac.getMetaData().addFragmentDescriptor(fragResource, new FragmentDescriptor(webfragxml));
assertThrows(NullPointerException.class, () ->
{
wac.getMetaData().addFragmentDescriptor(nonFragResource, null);
});
assertNotNull(wac.getMetaData().getFragmentDescriptorForJar(fragResource));
assertNull(wac.getMetaData().getFragmentDescriptorForJar(nonFragResource));
assertNull(wac.getMetaData().getFragmentDescriptorForJar(null));
}
@Test
public void testGetFragmentDescriptorByName() throws Exception
{
wac.getMetaData().addWebInfResource(fragResource);
wac.getMetaData().addWebInfResource(nonFragResource);
FragmentDescriptor fragDescriptor = new FragmentDescriptor(webfragxml);
wac.getMetaData().addFragmentDescriptor(fragResource, fragDescriptor);
assertNotNull(wac.getMetaData().getFragmentDescriptor(fragDescriptor.getName()));
}
@Test
public void testGetFragmentDescriptorByLocation() throws Exception
{
wac.getMetaData().addWebInfResource(fragResource);
wac.getMetaData().addWebInfResource(nonFragResource);
FragmentDescriptor fragDescriptor = new FragmentDescriptor(webfragxml);
wac.getMetaData().addFragmentDescriptor(fragResource, fragDescriptor);
assertNotNull(wac.getMetaData().getFragmentDescriptor(webfragxml));
}
@Test
public void testGetJarForFragmentName() throws Exception
{
wac.getMetaData().addWebInfResource(fragResource);
wac.getMetaData().addWebInfResource(nonFragResource);
wac.getMetaData().addFragmentDescriptor(fragResource, new FragmentDescriptor(webfragxml));
FragmentDescriptor descriptor = wac.getMetaData().getFragmentDescriptorForJar(fragResource);
assertNotNull(descriptor);
assertNotNull(wac.getMetaData().getJarForFragmentName(descriptor.getName()));
assertNull(wac.getMetaData().getJarForFragmentName(null));
assertNull(wac.getMetaData().getJarForFragmentName(""));
assertNull(wac.getMetaData().getJarForFragmentName("xxx"));
}
@Test
public void testAddDiscoveredAnnotation() throws Exception
{
wac.getMetaData().addWebInfResource(fragResource);
wac.getMetaData().addWebInfResource(nonFragResource);
wac.getMetaData().addFragmentDescriptor(fragResource, new FragmentDescriptor(webfragxml));
wac.getMetaData().addContainerResource(containerDir);
wac.getMetaData().setWebInfClassesResources(Collections.singletonList(webInfClassesDir));
wac.getMetaData().addDiscoveredAnnotation(annotationA);
wac.getMetaData().addDiscoveredAnnotation(annotationB);
wac.getMetaData().addDiscoveredAnnotation(annotationC);
wac.getMetaData().addDiscoveredAnnotation(annotationD);
wac.getMetaData().addDiscoveredAnnotation(annotationE);
//test an annotation from a web-inf lib fragment
List<DiscoveredAnnotation> list = wac.getMetaData()._annotations.get(fragResource);
assertThat(list, contains(annotationA));
assertThat(list, hasSize(1));
//test an annotation from a web-inf lib fragment without a descriptor
list = wac.getMetaData()._annotations.get(nonFragResource);
assertThat(list, contains(annotationB));
assertThat(list, hasSize(1));
//test an annotation that didn't have an associated resource
list = wac.getMetaData()._annotations.get(EmptyResource.INSTANCE);
assertThat(list, contains(annotationC));
assertThat(list, hasSize(1));
//test an annotation that came from the container path
list = wac.getMetaData()._annotations.get(containerDir);
assertThat(list, contains(annotationD));
assertThat(list, hasSize(1));
//test an annoation from web-inf classes
list = wac.getMetaData()._annotations.get(webInfClassesDir);
assertThat(list, contains(annotationE));
assertThat(list, hasSize(1));
}
@Test
public void testResolve() throws Exception
{
wac.getMetaData().addWebInfResource(fragResource);
wac.getMetaData().addWebInfResource(nonFragResource);
wac.getMetaData().addFragmentDescriptor(fragResource, new FragmentDescriptor(webfragxml));
wac.getMetaData().addContainerResource(containerDir);
wac.getMetaData().setWebInfClassesResources(Collections.singletonList(webInfClassesDir));
wac.getMetaData().addDiscoveredAnnotation(annotationA);
wac.getMetaData().addDiscoveredAnnotation(annotationB);
wac.getMetaData().addDiscoveredAnnotation(annotationC);
wac.getMetaData().addDiscoveredAnnotation(annotationD);
wac.getMetaData().addDiscoveredAnnotation(annotationE);
wac.getMetaData().resolve(wac);
//test that annotations are applied from resources in order:
//no resource associated, container resources, web-inf classes resources, web-inf lib resources
assertThat(applications, contains(annotationC, annotationD, annotationE, annotationA, annotationB));
}
}

View File

@ -483,6 +483,6 @@ public class WebAppContextTest
context.setServer(new Server());
new MetaInfConfiguration().preConfigure(context);
assertEquals(Arrays.asList("acme.jar", "alpha.jar", "omega.jar"),
context.getMetaData().getWebInfJars().stream().map(r -> r.getURI().toString().replaceFirst(".+/", "")).collect(Collectors.toList()));
context.getMetaData().getWebInfResources(false).stream().map(r -> r.getURI().toString().replaceFirst(".+/", "")).collect(Collectors.toList()));
}
}

Binary file not shown.

Binary file not shown.

View File

@ -55,8 +55,7 @@ public class QuickStartTest
PreconfigureStandardTestWar.main(new String[]{});
WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-standard-preconfigured/WEB-INF/quickstart-web.xml"));
descriptor.setValidating(!Log.getLogger(QuickStartGeneratorConfiguration.class).isDebugEnabled());
descriptor.parse();
descriptor.parse(WebDescriptor.getParser(!Log.getLogger(QuickStartGeneratorConfiguration.class).isDebugEnabled()));
Node node = descriptor.getRoot();
assertThat(node, Matchers.notNullValue());
@ -109,8 +108,7 @@ public class QuickStartTest
assertTrue(Files.exists(webXmlPath), "Path should exist:" + webXmlPath);
WebDescriptor descriptor = new WebDescriptor(new PathResource(webXmlPath));
descriptor.setValidating(!Log.getLogger(QuickStartGeneratorConfiguration.class).isDebugEnabled());
descriptor.parse();
descriptor.parse(WebDescriptor.getParser(!Log.getLogger(QuickStartGeneratorConfiguration.class).isDebugEnabled()));
Node node = descriptor.getRoot();
assertThat(node, Matchers.notNullValue());
@ -160,8 +158,7 @@ public class QuickStartTest
PreconfigureJNDIWar.main(new String[]{});
WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml"));
descriptor.setValidating(!Log.getLogger(QuickStartGeneratorConfiguration.class).isDebugEnabled());
descriptor.parse();
descriptor.parse(WebDescriptor.getParser(!Log.getLogger(QuickStartGeneratorConfiguration.class).isDebugEnabled()));
Node node = descriptor.getRoot();
assertThat(node, Matchers.notNullValue());