Merge remote-tracking branch 'origin/jetty-9.4.x'

This commit is contained in:
Greg Wilkins 2016-10-06 12:01:50 +11:00
commit 84f7fc31cb
37 changed files with 1707 additions and 1075 deletions

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.annotations;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -49,6 +48,7 @@ import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
@ -86,8 +86,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
protected List<ParserTask> _parserTasks;
protected WebAppClassNameResolver _webAppClassNameResolver;
protected ContainerClassNameResolver _containerClassNameResolver;
protected CounterStatistic _containerPathStats;
protected CounterStatistic _webInfLibStats;
@ -152,15 +150,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected Exception _exception;
protected final AnnotationParser _parser;
protected final Set<? extends Handler> _handlers;
protected final ClassNameResolver _resolver;
protected final Resource _resource;
protected TimeStatistic _stat;
public ParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver)
public ParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource)
{
_parser = parser;
_handlers = handlers;
_resolver = resolver;
_resource = resource;
}
@ -174,7 +170,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_stat != null)
_stat.start();
if (_parser != null)
_parser.parse(_handlers, _resource, _resolver);
_parser.parse(_handlers, _resource);
if (_stat != null)
_stat.end();
return null;
@ -188,83 +184,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getResource()
{
return _resource;
}
}
/**
* WebAppClassNameResolver
*
* Checks to see if a classname belongs to hidden or visible packages when scanning,
* and whether a classname that is a duplicate should override a previously
* scanned classname.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class WebAppClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public WebAppClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return true;
if (_context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class
//of same name - did it come from system or duplicate in webapp?
if (_context.isParentLoaderPriority())
return false;
return true;
}
}
/**
* ContainerClassNameResolver
*
* Checks to see if a classname belongs to a hidden or visible package
* when scanning for annotations and thus whether it should be excluded from
* consideration or not.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class ContainerClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public ContainerClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return false;
if (_context.isServerClass(name)) return true;
return false;
}
public boolean shouldOverride (String name)
{
//visiting the container classpath,
if (_context.isParentLoaderPriority())
return true;
return false;
}
}
}
@ -404,8 +324,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
_webAppClassNameResolver = new WebAppClassNameResolver(context);
_containerClassNameResolver = new ContainerClassNameResolver(context);
String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN);
_sciExcludePattern = (tmp==null?null:Pattern.compile(tmp));
}
@ -459,15 +377,15 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
scanForAnnotations(context);
// Resolve container initializers
List<ContainerInitializer> initializers =
(List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
(List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
if (initializers != null && initializers.size()>0)
{
Map<String, Set<String>> map = ( Map<String, Set<String>>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
for (ContainerInitializer i : initializers)
i.resolveClasses(context,map);
i.resolveClasses(context,map);
}
}
@ -737,23 +655,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getJarFor (ServletContainerInitializer service)
throws MalformedURLException, IOException
{
//try the thread context classloader to get the jar that loaded the class
URL jarURL = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class");
//if for some reason that failed (eg we're in osgi and the TCCL does not know about the service) try the classloader that
//loaded the class
if (jarURL == null)
jarURL = service.getClass().getClassLoader().getResource(service.getClass().getName().replace('.','/')+".class");
String loadingJarName = jarURL.toString();
int i = loadingJarName.indexOf(".jar");
if (i < 0)
return null; //not from a jar
loadingJarName = loadingJarName.substring(0,i+4);
loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName);
return Resource.newResource(loadingJarName);
return TypeUtil.getLoadedFrom(service.getClass());
}
/**
@ -774,26 +676,41 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (context == null)
throw new IllegalArgumentException("WebAppContext null");
if (LOG.isDebugEnabled()) LOG.debug("Checking {} for jar exclusion", sci);
//A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering
//of WEB-INF/lib jars
if (isFromContainerClassPath(context, sci))
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} from container classpath", sci);
return false;
}
//If no ordering, nothing is excluded
if (context.getMetaData().getOrdering() == null)
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} no ordering", sci);
return false;
}
List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
//there is an ordering, but there are no jars resulting from the ordering, everything excluded
if (orderedJars.isEmpty())
{
if (LOG.isDebugEnabled())
LOG.debug("Excluded {} empty ordering", sci);
return true;
}
if (sciResource == null)
return false; //not from a jar therefore not from WEB-INF so not excludable
{
//not from a jar therefore not from WEB-INF so not excludable
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} not from jar", sci);
return false;
}
URI loadingJarURI = sciResource.getURI();
boolean found = false;
@ -804,10 +721,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
found = r.getURI().equals(loadingJarURI);
}
if (LOG.isDebugEnabled())
LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found);
return !found;
}
/**
* Test if the ServletContainerIntializer is excluded by the
* o.e.j.containerInitializerExclusionPattern
@ -822,7 +740,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
return false;
//test if name of class matches the regex
if (LOG.isDebugEnabled()) LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName());
if (LOG.isDebugEnabled())
LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName());
return _sciExcludePattern.matcher(sci.getClass().getName()).matches();
}
@ -883,14 +802,16 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (matchesExclusionPattern(sci))
{
if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci);
if (LOG.isDebugEnabled())
LOG.debug("{} excluded by pattern", sci);
continue;
}
Resource sciResource = getJarFor(sci);
if (isFromExcludedJar(context, sci, sciResource))
{
if (LOG.isDebugEnabled()) LOG.debug("{} is from excluded jar", sci);
if (LOG.isDebugEnabled())
LOG.debug("{} is from excluded jar", sci);
continue;
}
@ -899,7 +820,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (initializerOrdering != null
&& (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0))
{
if (LOG.isDebugEnabled()) LOG.debug("{} is excluded by ordering", sci);
if (LOG.isDebugEnabled())
LOG.debug("{} is excluded by ordering", sci);
continue;
}
@ -926,12 +848,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
//no web.xml ordering defined, add SCIs in any order
if (context.getMetaData().getOrdering() == null)
{
if (LOG.isDebugEnabled()) LOG.debug("No web.xml ordering, ServletContainerInitializers in random order");
if (LOG.isDebugEnabled())
LOG.debug("No web.xml ordering, ServletContainerInitializers in random order");
nonExcludedInitializers.addAll(sciResourceMap.keySet());
}
else
{
if (LOG.isDebugEnabled()) LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering());
if (LOG.isDebugEnabled())
LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering());
for (Map.Entry<ServletContainerInitializer, Resource> entry:sciResourceMap.entrySet())
{
//add in SCIs from the container classpath
@ -1006,7 +930,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
//queue it up for scanning if using multithreaded mode
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver);
ParserTask task = new ParserTask(parser, handlers, r);
_parserTasks.add(task);
_containerPathStats.increment();
if (LOG.isDebugEnabled())
@ -1068,7 +992,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers,r, _webAppClassNameResolver);
ParserTask task = new ParserTask(parser, handlers,r);
_parserTasks.add (task);
_webInfLibStats.increment();
if (LOG.isDebugEnabled())
@ -1101,7 +1025,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver);
ParserTask task = new ParserTask(parser, handlers, dir);
_parserTasks.add(task);
_webInfClassesStats.increment();
if (LOG.isDebugEnabled())

View File

@ -547,25 +547,22 @@ public class AnnotationParser
* @param resolver the class name resolver to use
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, String className, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, String className)
throws Exception
{
if (className == null)
return;
if (!resolver.isExcluded(className))
if (!isParsed(className))
{
if (!isParsed(className) || resolver.shouldOverride(className))
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
{
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
@ -582,29 +579,27 @@ public class AnnotationParser
* @param visitSuperClasses if true, also visit super classes for parse
* @throws Exception if unable to parse class
*/
public void parse (Set<? extends Handler> handlers, Class<?> clazz, ClassNameResolver resolver, boolean visitSuperClasses)
public void parse (Set<? extends Handler> handlers, Class<?> clazz, boolean visitSuperClasses)
throws Exception
{
Class<?> cz = clazz;
while (cz != null)
{
if (!resolver.isExcluded(cz.getName()))
if (!isParsed(cz.getName()))
{
if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
{
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
if (visitSuperClasses)
cz = cz.getSuperclass();
else
@ -622,13 +617,13 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, String[] classNames, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, String[] classNames)
throws Exception
{
if (classNames == null)
return;
parse(handlers, Arrays.asList(classNames), resolver);
parse(handlers, Arrays.asList(classNames));
}
@ -640,7 +635,7 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, List<String> classNames, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, List<String> classNames)
throws Exception
{
MultiException me = new MultiException();
@ -649,7 +644,7 @@ public class AnnotationParser
{
try
{
if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
if (!isParsed(s))
{
s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(s);
@ -680,7 +675,7 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
protected void parseDir (Set<? extends Handler> handlers, Resource dir, ClassNameResolver resolver)
protected void parseDir (Set<? extends Handler> handlers, Resource dir)
throws Exception
{
// skip dirs whose name start with . (ie hidden)
@ -696,7 +691,7 @@ public class AnnotationParser
{
Resource res = dir.addPath(files[f]);
if (res.isDirectory())
parseDir(handlers, res, resolver);
parseDir(handlers, res);
else
{
//we've already verified the directories, so just verify the class file name
@ -706,7 +701,7 @@ public class AnnotationParser
try
{
String name = res.getName();
if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
if (!isParsed(name))
{
Resource r = Resource.newResource(res.getURL());
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);};
@ -744,7 +739,7 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive)
throws Exception
{
if (loader==null)
@ -762,7 +757,7 @@ public class AnnotationParser
{
try
{
parseJarEntry(handlers, Resource.newResource(jarUri), entry, resolver);
parseJarEntry(handlers, Resource.newResource(jarUri), entry);
}
catch (Exception e)
{
@ -785,7 +780,7 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, final URI[] uris, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, final URI[] uris)
throws Exception
{
if (uris==null)
@ -797,7 +792,7 @@ public class AnnotationParser
{
try
{
parse(handlers, uri, resolver);
parse(handlers, uri);
}
catch (Exception e)
{
@ -815,13 +810,13 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, URI uri, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, URI uri)
throws Exception
{
if (uri == null)
return;
parse (handlers, Resource.newResource(uri), resolver);
parse (handlers, Resource.newResource(uri));
}
@ -833,7 +828,7 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, Resource r, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, Resource r)
throws Exception
{
if (r == null)
@ -841,14 +836,14 @@ public class AnnotationParser
if (r.exists() && r.isDirectory())
{
parseDir(handlers, r, resolver);
parseDir(handlers, r);
return;
}
String fullname = r.toString();
if (fullname.endsWith(".jar"))
{
parseJar(handlers, r, resolver);
parseJar(handlers, r);
return;
}
@ -875,7 +870,7 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
protected void parseJar (Set<? extends Handler> handlers, Resource jarResource, final ClassNameResolver resolver)
protected void parseJar (Set<? extends Handler> handlers, Resource jarResource)
throws Exception
{
if (jarResource == null)
@ -899,7 +894,7 @@ public class AnnotationParser
{
try
{
parseJarEntry(handlers, jarResource, entry, resolver);
parseJarEntry(handlers, jarResource, entry);
}
catch (Exception e)
{
@ -930,7 +925,7 @@ public class AnnotationParser
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry, final ClassNameResolver resolver)
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry)
throws Exception
{
if (jar == null || entry == null)
@ -947,9 +942,7 @@ public class AnnotationParser
{
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null)
||
(!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
if (!isParsed(shortName))
{
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);};

View File

@ -1,42 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.annotations;
public interface ClassNameResolver
{
/**
* Based on the execution context, should the class represented
* by "name" be excluded from consideration?
* @param name the name to test
* @return true if classname is excluded
*/
public boolean isExcluded (String name);
/**
* Based on the execution context, if a duplicate class
* represented by "name" is detected, should the existing
* one be overridden or not?
* @param name the name to test
* @return true if name should be overridden
*/
public boolean shouldOverride (String name);
}

View File

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

View File

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

View File

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

View File

@ -44,23 +44,30 @@ public class JettyWeldInitializer
{
initContext(webapp);
// TODO use location bases include/exclude
// webapp cannot change / replace weld classes
webapp.addSystemClass("org.jboss.weld.");
webapp.addSystemClass("org.jboss.classfilewriter.");
webapp.addSystemClass("org.jboss.logging.");
webapp.addSystemClass("com.google.common.");
webapp.addSystemClass("org.eclipse.jetty.cdi.websocket.annotation.");
webapp.getSystemClasspathPattern()
.include(
"org.jboss.weld.",
"org.jboss.classfilewriter.",
"org.jboss.logging.",
"com.google.common.",
"org.eclipse.jetty.cdi.websocket.annotation."
);
// don't hide weld classes from webapps (allow webapp to use ones from system classloader)
webapp.prependServerClass("-org.eclipse.jetty.cdi.websocket.annotation.");
webapp.prependServerClass("-org.eclipse.jetty.cdi.core.");
webapp.prependServerClass("-org.eclipse.jetty.cdi.servlet.");
webapp.addServerClass("-org.jboss.weld.");
webapp.addServerClass("-org.jboss.classfilewriter.");
webapp.addServerClass("-org.jboss.logging.");
webapp.addServerClass("-com.google.common.");
webapp.getServerClasspathPattern()
.exclude(
"org.eclipse.jetty.cdi.websocket.annotation.",
"org.eclipse.jetty.cdi.core.",
"org.eclipse.jetty.cdi.servlet.",
"org.jboss.weld.",
"org.jboss.classfilewriter.",
"org.jboss.logging.",
"com.google.common.");
}
public static void initContext(ContextHandler handler) throws NamingException

View File

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

View File

@ -0,0 +1,23 @@
[description]
Control GCloud API classpath
[files]
basehome:modules/gcloud/gcloud.xml|etc/gcloud.xml
[lib]
lib/gcloud/*.jar
[xml]
etc/gcloud.xml
[license]
GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
https://github.com/GoogleCloudPlatform/gcloud-java
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
## Configure the jars and packages exposed or hidden from webapps by comma separated
## list of classnames, package names or file URIs (See ClasspathPattern)
## Eg. to hide all gcloud dependencies other than the com.google.guava package:
## Default is all jars in lib/gcloud are hidden
# gcloud.addServerClasses=file:${jetty.base}/lib/gcloud,-com.google.guava.

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- ===================================================================== -->
<!-- Configure a GCloud classpath exposed to webapps -->
<!-- ===================================================================== -->
<Call class="org.eclipse.jetty.webapp.WebAppContext" name="addServerClasses">
<Arg><Ref refid="Server"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="gcloud.addServerClasses"><Default>file:${jetty.base}/lib/gcloud</Default></Property></Arg>
</Call>
</Arg>
</Call>
</Configure>

View File

@ -5,88 +5,20 @@ Enables GCloudDatastore session management.
session-store
[depends]
gcloud-datastore
annotations
webapp
sessions
jcl-api
jcl-impl
[files]
basehome:etc/sessions/gcloud/index.yaml|etc/index.yaml
maven://com.google.cloud/google-cloud-datastore/0.3.0|lib/gcloud/google-cloud-datastore-0.3.0.jar
maven://com.google.cloud/google-cloud-core/0.3.0|lib/gcloud/google-cloud-core-0.3.0.jar
maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar
maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar
maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar
maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar
maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar
maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar
maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar
maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar
maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar
maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar
maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar
maven://com.google.protobuf/protobuf-java/3.0.0-beta-3|lib/gcloud/protobuf-java-3.0.0-beta-3.jar
maven://com.google.api/gax/0.0.16|lib/gcloud/gax-0.0.16.jar
maven://io.grpc/grpc-all/0.15.0|lib/gcloud/grpc-all-0.15.0.jar
maven://io.grpc/grpc-auth/0.15.0|lib/gcloud/grpc-auth-0.15.0.jar
maven://io.grpc/grpc-netty/0.15.0|lib/gcloud/grpc-netty-0.15.0.jar
maven://io.netty/netty-codec-http2/4.1.1.Final|lib/gcloud/netty-codec-http2-4.1.1.jar
maven://io.netty/netty-codec-http/4.1.1.Final|lib/gcloud/netty-codec-http-4.1.1.Final.jar
maven://io.netty/netty-codec/4.1.1.Final|lib/gcloud/netty-codec-4.1.1.Final.jar
maven://io.netty/netty-handler/4.1.1.Final|lib/gcloud/netty-handler-4.1.1.Final.jar
maven://io.netty/netty-buffer/4.1.1.Final|lib/gcloud/netty-buffer-4.1.1.Final.jar
maven://io.netty/netty-common/4.1.1.Final|lib/gcloud/netty-common-4.1.1.Final.jar
maven://io.netty/netty-transport/4.1.1.Final|lib/gcloud/netty-transport-4.1.1.Final.jar
maven://io.netty/netty-resolver/4.1.1.Final|lib/gcloud/netty-resolver-4.1.1.Final.jar
maven://io.grpc/grpc-okhttp/0.15.0|lib/gcloud/grpc-okhttp-0.15.0.jar
maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar
maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar
maven://io.grpc/grpc-protobuf-nano/0.15.0|lib/gcloud/grpc-protobuf-nano-0.15.0.jar
maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano-3.0.0-alpha-5.jar
maven://io.grpc/grpc-stub/0.15.0|lib/gcloud/grpc-stub-0.15.0.jar
maven://io.grpc/grpc-protobuf/0.15.0|lib/gcloud/grpc-protobuf-0.15.0.jar
maven://com.google.protobuf/protobuf-java-util/3.0.0-beta-3|lib/gcloud/protobuf-java-util-3.0.0-beta-3.jar
maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar
maven://io.grpc/grpc-protobuf-lite/0.15.0|lib/gcloud/grpc-protobuf-lite-0.15.0.jar
maven://io.grpc/grpc-core/0.15.0|lib/gcloud/grpc-core-0.15.0.jar
maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar
maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar
maven://javax.inject/javax.inject/1|lib/gcloud/javax.inject-1.jar
maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar
maven://com.google.api.grpc/grpc-google-common-protos/0.0.7|lib/gcloud/grpc-google-common-protos-0.0.7.jar
maven://org.json/json/20151123|lib/gcloud/json-20151123.jar
maven://com.google.cloud.datastore/datastore-v1-protos/1.0.1|lib/gcloud/datastore-v1-protos-1.0.1-beta.jar
maven://com.google.cloud.datastore/datastore-v1-proto-client/1.1.0|lib/gcloud/datastore-v1-proto-client-1.1.0.jar
maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar
maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar
maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar
basehome:modules/gcloud/index.yaml|etc/index.yaml
[lib]
lib/jetty-gcloud-session-manager-${jetty.version}.jar
lib/gcloud/*.jar
[xml]
etc/sessions/gcloud/session-store.xml
[license]
GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
https://github.com/GoogleCloudPlatform/gcloud-java
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
## GCloudDatastore Session config

View File

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

View File

@ -18,11 +18,14 @@
package org.eclipse.jetty.osgi.annotations;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import org.eclipse.jetty.annotations.AnnotationParser.Handler;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.util.log.Log;
@ -44,9 +47,9 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
public class BundleParserTask extends ParserTask
{
public BundleParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver)
public BundleParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource)
{
super(parser, handlers, resource, resolver);
super(parser, handlers, resource);
}
public Void call() throws Exception
@ -57,7 +60,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
Bundle bundle = osgiAnnotationParser.getBundle(_resource);
if (_stat != null)
_stat.start();
osgiAnnotationParser.parse(_handlers, bundle, _resolver);
osgiAnnotationParser.parse(_handlers, bundle);
if (_stat != null)
_stat.end();
}
@ -79,6 +82,17 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
return new AnnotationParser();
}
@Override
public Resource getJarFor(ServletContainerInitializer service) throws MalformedURLException, IOException
{
Resource resource = super.getJarFor(service);
// TODO This is not correct, but implemented like this to be bug for bug compatible
// with previous implementation that could only handle actual jars and not bundles.
if (resource!=null && !resource.toString().endsWith(".jar"))
return null;
return resource;
}
/**
* Here is the order in which jars and osgi artifacts are scanned for discoverable annotations.
* <ol>
@ -195,47 +209,13 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
handlers.add(_classInheritanceHandler);
handlers.addAll(_containerInitializerAnnotationHandlers);
ClassNameResolver classNameResolver = createClassNameResolver(context);
if (_parserTasks != null)
{
BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes, classNameResolver);
BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes);
_parserTasks.add(task);
if (LOG.isDebugEnabled())
task.setStatistic(new TimeStatistic());
}
}
/**
* Returns the same classname resolver than for the webInfjar scanner
* @param context the web app context
* @return the class name resolver
*/
protected ClassNameResolver createClassNameResolver(final WebAppContext context)
{
return createClassNameResolver(context,true,false,false,false);
}
protected ClassNameResolver createClassNameResolver(final WebAppContext context,
final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse,
final boolean overrideIsParenLoaderIsPriority)
{
return new ClassNameResolver ()
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return excludeSysClass;
if (context.isServerClass(name)) return excludeServerClass;
return excludeEverythingElse;
}
public boolean shouldOverride (String name)
{
//looking at system classpath
if (context.isParentLoaderPriority())
return overrideIsParenLoaderIsPriority;
return !overrideIsParenLoaderIsPriority;
}
};
}
}

View File

@ -29,7 +29,6 @@ import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.resource.Resource;
@ -85,7 +84,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
*
*/
@Override
public void parse (Set<? extends Handler> handlers, URI[] uris, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, URI[] uris)
throws Exception
{
for (URI uri : uris)
@ -99,16 +98,16 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
}
//a jar in WEB-INF/lib or the WEB-INF/classes
//use the behavior of the super class for a standard jar.
super.parse(handlers, new URI[] {uri},resolver);
super.parse(handlers, new URI[] {uri});
}
else
{
parse(handlers, associatedBundle,resolver);
parse(handlers, associatedBundle);
}
}
}
protected void parse(Set<? extends Handler> handlers, Bundle bundle, ClassNameResolver resolver)
protected void parse(Set<? extends Handler> handlers, Bundle bundle)
throws Exception
{
URI uri = _bundleToUri.get(bundle);
@ -205,7 +204,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
}
//transform into a classname to pass to the resolver
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null) || (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
if (!isParsed(shortName))
{
try (InputStream classInputStream = classUrl.openStream())
{

View File

@ -47,18 +47,16 @@ public abstract class AbstractOSGiApp extends App
private static final Logger LOG = Log.getLogger(AbstractOSGiApp.class);
protected Bundle _bundle;
protected Dictionary _properties;
protected Dictionary<?,?> _properties;
protected ServiceRegistration _registration;
/* ------------------------------------------------------------ */
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
{
super(manager, provider, originId);
_properties = bundle.getHeaders();
_bundle = bundle;
this (manager, provider, bundle, bundle.getHeaders(), originId);
}
/* ------------------------------------------------------------ */
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId)
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary<?,?> properties, String originId)
{
super(manager, provider, originId);
_properties = properties;

View File

@ -405,18 +405,23 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement
}
}
}
if (contextXmlUrl == null) return;
if (contextXmlUrl == null)
return;
// Apply it just as the standard jetty ContextProvider would do
LOG.info("Applying " + contextXmlUrl + " to " + _webApp);
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
HashMap properties = new HashMap();
properties.put("Server", getDeploymentManager().getServer());
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
properties.put(OSGiServerConstants.JETTY_HOME, getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(_webApp);
WebAppClassLoader.runWithServerClassAccess(()->
{
HashMap<String,String> properties = new HashMap<>();
xmlConfiguration.getIdMap().put("Server",getDeploymentManager().getServer());
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
properties.put(OSGiServerConstants.JETTY_HOME, (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(_webApp);
return null;
});
}
finally
{

View File

@ -175,7 +175,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
String contextPath = null;
try
{
Dictionary headers = bundle.getHeaders();
Dictionary<String,String> headers = bundle.getHeaders();
//does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers);
@ -217,7 +217,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
{
//Could be a static webapp with no web.xml
String base = ".";
contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
contextPath = headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
String originId = getOriginId(bundle,base);
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);

View File

@ -78,8 +78,6 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
private Bundle _contributor;
private boolean _lookInOsgiFirst = true;
/* ------------------------------------------------------------ */
/**
* @param parent The parent classloader.
@ -96,11 +94,26 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
}
/* ------------------------------------------------------------ */
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
return super.loadClass(name);
try
{
return _osgiBundleClassLoader.loadClass(name);
}
catch (ClassNotFoundException cne)
{
try
{
return super.loadClass(name);
}
catch (ClassNotFoundException cne2)
{
throw cne;
}
}
}
/* ------------------------------------------------------------ */
@ -121,36 +134,18 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
{
Enumeration<URL> osgiUrls = _osgiBundleClassLoader.getResources(name);
Enumeration<URL> urls = super.getResources(name);
if (_lookInOsgiFirst)
{
return Collections.enumeration(toList(osgiUrls, urls));
}
else
{
return Collections.enumeration(toList(urls, osgiUrls));
}
List<URL> resources = toList(osgiUrls, urls);
return Collections.enumeration(resources);
}
/* ------------------------------------------------------------ */
@Override
public URL getResource(String name)
{
if (_lookInOsgiFirst)
{
URL url = _osgiBundleClassLoader.getResource(name);
return url != null ? url : super.getResource(name);
}
else
{
URL url = super.getResource(name);
return url != null ? url : _osgiBundleClassLoader.getResource(name);
}
URL url = _osgiBundleClassLoader.getResource(name);
return url != null ? url : super.getResource(name);
}
/* ------------------------------------------------------------ */
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
{
@ -160,30 +155,7 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
while (e2 != null && e2.hasMoreElements())
list.add(e2.nextElement());
return list;
}
/* ------------------------------------------------------------ */
protected Class<?> findClass(String name) throws ClassNotFoundException
{
try
{
return _lookInOsgiFirst ? _osgiBundleClassLoader.loadClass(name) : super.findClass(name);
}
catch (ClassNotFoundException cne)
{
try
{
return _lookInOsgiFirst ? super.findClass(name) : _osgiBundleClassLoader.loadClass(name);
}
catch (ClassNotFoundException cne2)
{
throw cne;
}
}
}
}
/* ------------------------------------------------------------ */
/**

View File

@ -50,8 +50,8 @@ public class TestConfiguration
WebAppContext wac = new WebAppContext();
wac.setServer(server);
wac.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), wac));
wac.addSystemClass("org.eclipse.jetty.jndi.");
wac.prependServerClass("-org.eclipse.jetty.jndi.");
wac.getSystemClasspathPattern().include("org.eclipse.jetty.jndi.");
wac.getServerClasspathPattern().exclude("org.eclipse.jetty.jndi.");
MetaData metaData = new MetaData();

View File

@ -133,7 +133,7 @@ public class BufferedResponseHandler extends HandlerWrapper
}
// If not a supported method - no Vary because no matter what client, this URI is always excluded
if (!_methods.matches(baseRequest.getMethod()))
if (!_methods.test(baseRequest.getMethod()))
{
LOG.debug("{} excluded by method {}",this,request);
_handler.handle(target,baseRequest, request, response);
@ -173,7 +173,7 @@ public class BufferedResponseHandler extends HandlerWrapper
/* ------------------------------------------------------------ */
protected boolean isMimeTypeBufferable(String mimetype)
{
return _mimeTypes.matches(mimetype);
return _mimeTypes.test(mimetype);
}
/* ------------------------------------------------------------ */
@ -182,7 +182,7 @@ public class BufferedResponseHandler extends HandlerWrapper
if (requestURI == null)
return true;
return _paths.matches(requestURI);
return _paths.test(requestURI);
}
/* ------------------------------------------------------------ */

View File

@ -457,7 +457,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
}
// If not a supported method - no Vary because no matter what client, this URI is always excluded
if (!_methods.matches(baseRequest.getMethod()))
if (!_methods.test(baseRequest.getMethod()))
{
LOG.debug("{} excluded by method {}",this,request);
_handler.handle(target,baseRequest, request, response);
@ -549,14 +549,14 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (ua == null)
return false;
return _agentPatterns.matches(ua);
return _agentPatterns.test(ua);
}
/* ------------------------------------------------------------ */
@Override
public boolean isMimeTypeGzipable(String mimetype)
{
return _mimeTypes.matches(mimetype);
return _mimeTypes.test(mimetype);
}
/* ------------------------------------------------------------ */
@ -572,7 +572,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (requestURI == null)
return true;
return _paths.matches(requestURI);
return _paths.test(requestURI);
}
/* ------------------------------------------------------------ */

View File

@ -19,8 +19,10 @@
package org.eclipse.jetty.util;
import java.nio.ByteBuffer;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -495,6 +497,39 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
return keys;
}
public int size()
{
int s=0;
for (int r=0;r<=_rows;r++)
{
if (_key[r]!=null && _value[r]!=null)
s++;
}
return s;
}
public boolean isEmpty()
{
for (int r=0;r<=_rows;r++)
{
if (_key[r]!=null && _value[r]!=null)
return false;
}
return true;
}
public Set<Map.Entry<String,V>> entrySet()
{
Set<Map.Entry<String,V>> entries = new HashSet<>();
for (int r=0;r<=_rows;r++)
{
if (_key[r]!=null && _value[r]!=null)
entries.add(new AbstractMap.SimpleEntry<>(_key[r],_value[r]));
}
return entries;
}
@Override
public boolean isFull()
{
@ -524,4 +559,143 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
}
}
public static class Growing<V> implements Trie<V>
{
private final int _growby;
private ArrayTernaryTrie<V> _trie;
public Growing()
{
this(1024,1024);
}
public Growing(int capacity, int growby)
{
_growby=growby;
_trie = new ArrayTernaryTrie<>(capacity);
}
public Growing(boolean insensitive, int capacity, int growby)
{
_growby=growby;
_trie = new ArrayTernaryTrie<>(insensitive,capacity);
}
public boolean put(V v)
{
return put(v.toString(),v);
}
public int hashCode()
{
return _trie.hashCode();
}
public V remove(String s)
{
return _trie.remove(s);
}
public V get(String s)
{
return _trie.get(s);
}
public V get(ByteBuffer b)
{
return _trie.get(b);
}
public V getBest(byte[] b, int offset, int len)
{
return _trie.getBest(b,offset,len);
}
public boolean isCaseInsensitive()
{
return _trie.isCaseInsensitive();
}
public boolean equals(Object obj)
{
return _trie.equals(obj);
}
public void clear()
{
_trie.clear();
}
public boolean put(String s, V v)
{
boolean added = _trie.put(s,v);
while (!added)
{
ArrayTernaryTrie<V> bigger = new ArrayTernaryTrie<>(_trie._key.length+_growby);
for (Map.Entry<String,V> entry : _trie.entrySet())
bigger.put(entry.getKey(),entry.getValue());
added = _trie.put(s,v);
}
return true;
}
public V get(String s, int offset, int len)
{
return _trie.get(s,offset,len);
}
public V get(ByteBuffer b, int offset, int len)
{
return _trie.get(b,offset,len);
}
public V getBest(String s)
{
return _trie.getBest(s);
}
public V getBest(String s, int offset, int length)
{
return _trie.getBest(s,offset,length);
}
public V getBest(ByteBuffer b, int offset, int len)
{
return _trie.getBest(b,offset,len);
}
public String toString()
{
return _trie.toString();
}
public Set<String> keySet()
{
return _trie.keySet();
}
public boolean isFull()
{
return false;
}
public void dump()
{
_trie.dump();
}
public boolean isEmpty()
{
return _trie.isEmpty();
}
public int size()
{
return _trie.size();
}
}
}

View File

@ -25,21 +25,21 @@ import java.util.function.Predicate;
/** Utility class to maintain a set of inclusions and exclusions.
* <p>Maintains a set of included and excluded elements. The method {@link #matches(Object)}
* <p>Maintains a set of included and excluded elements. The method {@link #test(Object)}
* will return true IFF the passed object is not in the excluded set AND ( either the
* included set is empty OR the object is in the included set)
* <p>The type of the underlying {@link Set} used may be passed into the
* constructor, so special sets like Servlet PathMap may be used.
* <p>
* @param <P> The type of element of the set (often a pattern)
* @param <T> The type of the instance passed to the predicate
* @param <T> The type of element of the set (often a pattern)
* @param <P> The type of the instance passed to the predicate
*/
public class IncludeExcludeSet<P,T> implements Predicate<T>
public class IncludeExcludeSet<T,P> implements Predicate<P>
{
private final Set<P> _includes;
private final Predicate<T> _includePredicate;
private final Set<P> _excludes;
private final Predicate<T> _excludePredicate;
private final Set<T> _includes;
private final Predicate<P> _includePredicate;
private final Set<T> _excludes;
private final Predicate<P> _excludePredicate;
private static class SetContainsPredicate<T> implements Predicate<T>
{
@ -73,7 +73,7 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
* is created.
* @param <SET> The type of a set to use as the backing store
*/
public <SET extends Set<P>> IncludeExcludeSet(Class<SET> setClass)
public <SET extends Set<T>> IncludeExcludeSet(Class<SET> setClass)
{
try
{
@ -82,7 +82,7 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
if(_includes instanceof Predicate)
{
_includePredicate = (Predicate<T>)_includes;
_includePredicate = (Predicate<P>)_includes;
}
else
{
@ -91,7 +91,7 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
if(_excludes instanceof Predicate)
{
_excludePredicate = (Predicate<T>)_excludes;
_excludePredicate = (Predicate<P>)_excludes;
}
else
{
@ -113,7 +113,7 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
* @param excludePredicate the Predicate for excluded item testing (null for simple {@link Set#contains(Object)} test)
* @param <SET> The type of a set to use as the backing store
*/
public <SET extends Set<P>> IncludeExcludeSet(Set<P> includeSet, Predicate<T> includePredicate, Set<P> excludeSet, Predicate<T> excludePredicate)
public <SET extends Set<T>> IncludeExcludeSet(Set<T> includeSet, Predicate<P> includePredicate, Set<T> excludeSet, Predicate<P> excludePredicate)
{
Objects.requireNonNull(includeSet,"Include Set");
Objects.requireNonNull(includePredicate,"Include Predicate");
@ -126,51 +126,73 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
_excludePredicate = excludePredicate;
}
public void include(P element)
public void include(T element)
{
_includes.add(element);
}
public void include(P... element)
public void include(T... element)
{
for (P e: element)
for (T e: element)
_includes.add(e);
}
public void exclude(P element)
public void exclude(T element)
{
_excludes.add(element);
}
public void exclude(P... element)
public void exclude(T... element)
{
for (P e: element)
for (T e: element)
_excludes.add(e);
}
public boolean matches(T t)
@Deprecated
public boolean matches(P t)
{
return test(t);
}
public boolean test(T t)
@Override
public boolean test(P t)
{
if (!_includes.isEmpty() && !_includePredicate.test(t))
return false;
return !_excludePredicate.test(t);
}
/**
* Test Included and not Excluded
* @param t The item to test
* @return Boolean.TRUE if t is included, Boolean.FALSE if t is excluded and null if neither
*/
public Boolean isIncludedAndNotExcluded(P t)
{
if (_excludePredicate.test(t))
return Boolean.FALSE;
if (_includePredicate.test(t))
return Boolean.TRUE;
return null;
}
public boolean hasIncludes()
{
return !_includes.isEmpty();
}
public int size()
{
return _includes.size()+_excludes.size();
}
public Set<P> getIncluded()
public Set<T> getIncluded()
{
return _includes;
}
public Set<P> getExcluded()
public Set<T> getExcluded()
{
return _excludes;
}

View File

@ -29,7 +29,7 @@ import java.util.Set;
public interface Trie<V>
{
/* ------------------------------------------------------------ */
/** Put and entry into the Trie
/** Put an entry into the Trie
* @param s The key for the entry
* @param v The value of the entry
* @return True if the Trie had capacity to add the field.
@ -47,14 +47,14 @@ public interface Trie<V>
public V remove(String s);
/* ------------------------------------------------------------ */
/** Get and exact match from a String key
/** Get an exact match from a String key
* @param s The key
* @return the value for the string key
*/
public V get(String s);
/* ------------------------------------------------------------ */
/** Get and exact match from a String key
/** Get an exact match from a String key
* @param s The key
* @param offset The offset within the string of the key
* @param len the length of the key
@ -63,14 +63,14 @@ public interface Trie<V>
public V get(String s,int offset,int len);
/* ------------------------------------------------------------ */
/** Get and exact match from a segment of a ByteBuufer as key
/** Get an exact match from a segment of a ByteBuufer as key
* @param b The buffer
* @return The value or null if not found
*/
public V get(ByteBuffer b);
/* ------------------------------------------------------------ */
/** Get and exact match from a segment of a ByteBuufer as key
/** Get an exact match from a segment of a ByteBuufer as key
* @param b The buffer
* @param offset The offset within the buffer of the key
* @param len the length of the key

View File

@ -24,6 +24,9 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@ -31,9 +34,12 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.servlet.ServletContainerInitializer;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
/* ------------------------------------------------------------ */
@ -693,4 +699,38 @@ public class TypeUtil
return !((Boolean)o).booleanValue();
return "false".equalsIgnoreCase(o.toString());
}
/* ------------------------------------------------------------ */
public static Resource getLoadedFrom(Class<?> clazz)
{
ProtectionDomain domain = clazz.getProtectionDomain();
if (domain!=null)
{
CodeSource source = domain.getCodeSource();
if (source!=null)
{
URL location = source.getLocation();
if (location!=null)
return Resource.newResource(location);
}
}
String rname = clazz.getName().replace('.','/')+".class";
ClassLoader loader = clazz.getClassLoader();
URL url = (loader==null?ClassLoader.getSystemClassLoader():loader).getResource(rname);
if (url!=null)
{
try
{
return Resource.newResource(URIUtil.getJarSource(url.toString()));
}
catch(Exception e)
{
LOG.debug(e);
}
}
return null;
}
}

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.util;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
@ -845,4 +846,30 @@ public class URIUtil
return URI.create(buf.toString());
}
public static URI getJarSource(URI uri)
{
try
{
if (!"jar".equals(uri.getScheme()))
return uri;
String s = uri.getSchemeSpecificPart();
int bang_slash = s.indexOf("!/");
if (bang_slash>=0)
s=s.substring(0,bang_slash);
return new URI(s);
}
catch(URISyntaxException e)
{
throw new IllegalArgumentException(e);
}
}
public static String getJarSource(String uri)
{
if (!uri.startsWith("jar:"))
return uri;
int bang_slash = uri.indexOf("!/");
return (bang_slash>=0)?uri.substring(4,bang_slash):uri.substring(4);
}
}

View File

@ -32,7 +32,7 @@ public class IncludeExcludeTest
IncludeExclude<String> ie = new IncludeExclude<>();
assertThat("Empty IncludeExclude", ie.size(), is(0));
assertThat("Matches 'foo'",ie.matches("foo"),is(true));
assertThat("Matches 'foo'",ie.test("foo"),is(true));
}
@Test
@ -43,10 +43,10 @@ public class IncludeExcludeTest
ie.include("bar");
assertThat("IncludeExclude.size", ie.size(), is(2));
assertEquals(false,ie.matches(""));
assertEquals(true,ie.matches("foo"));
assertEquals(true,ie.matches("bar"));
assertEquals(false,ie.matches("foobar"));
assertEquals(false,ie.test(""));
assertEquals(true,ie.test("foo"));
assertEquals(true,ie.test("bar"));
assertEquals(false,ie.test("foobar"));
}
@Test
@ -58,11 +58,11 @@ public class IncludeExcludeTest
assertEquals(2,ie.size());
assertEquals(false,ie.matches("foo"));
assertEquals(false,ie.matches("bar"));
assertEquals(true,ie.matches(""));
assertEquals(true,ie.matches("foobar"));
assertEquals(true,ie.matches("wibble"));
assertEquals(false,ie.test("foo"));
assertEquals(false,ie.test("bar"));
assertEquals(true,ie.test(""));
assertEquals(true,ie.test("foobar"));
assertEquals(true,ie.test("wibble"));
}
@Test
@ -76,11 +76,11 @@ public class IncludeExcludeTest
assertEquals(4,ie.size());
assertEquals(true,ie.matches("foo"));
assertEquals(false,ie.matches("bar"));
assertEquals(false,ie.matches(""));
assertEquals(false,ie.matches("foobar"));
assertEquals(false,ie.matches("xxx"));
assertEquals(true,ie.test("foo"));
assertEquals(false,ie.test("bar"));
assertEquals(false,ie.test(""));
assertEquals(false,ie.test("foobar"));
assertEquals(false,ie.test("xxx"));
}
@ -91,7 +91,7 @@ public class IncludeExcludeTest
IncludeExclude<String> ie = new IncludeExclude<>(RegexSet.class);
assertEquals(0,ie.size());
assertEquals(true,ie.matches("foo"));
assertEquals(true,ie.test("foo"));
}
@Test
@ -102,13 +102,13 @@ public class IncludeExcludeTest
ie.include("b((ar)|(oo))");
assertEquals(2,ie.size());
assertEquals(false,ie.matches(""));
assertEquals(true,ie.matches("foo"));
assertEquals(true,ie.matches("far"));
assertEquals(true,ie.matches("bar"));
assertEquals(true,ie.matches("boo"));
assertEquals(false,ie.matches("foobar"));
assertEquals(false,ie.matches("xxx"));
assertEquals(false,ie.test(""));
assertEquals(true,ie.test("foo"));
assertEquals(true,ie.test("far"));
assertEquals(true,ie.test("bar"));
assertEquals(true,ie.test("boo"));
assertEquals(false,ie.test("foobar"));
assertEquals(false,ie.test("xxx"));
}
@Test
@ -120,13 +120,13 @@ public class IncludeExcludeTest
assertEquals(2,ie.size());
assertEquals(false,ie.matches("foo"));
assertEquals(false,ie.matches("far"));
assertEquals(false,ie.matches("bar"));
assertEquals(false,ie.matches("boo"));
assertEquals(true,ie.matches(""));
assertEquals(true,ie.matches("foobar"));
assertEquals(true,ie.matches("xxx"));
assertEquals(false,ie.test("foo"));
assertEquals(false,ie.test("far"));
assertEquals(false,ie.test("bar"));
assertEquals(false,ie.test("boo"));
assertEquals(true,ie.test(""));
assertEquals(true,ie.test("foobar"));
assertEquals(true,ie.test("xxx"));
}
@Test
@ -139,14 +139,14 @@ public class IncludeExcludeTest
ie.exclude("b((ar)|(oo))");
assertEquals(4,ie.size());
assertEquals(false,ie.matches("foo"));
assertEquals(false,ie.matches("far"));
assertEquals(false,ie.matches("bar"));
assertEquals(false,ie.matches("boo"));
assertEquals(false,ie.matches(""));
assertEquals(false,ie.matches("xxx"));
assertEquals(false,ie.test("foo"));
assertEquals(false,ie.test("far"));
assertEquals(false,ie.test("bar"));
assertEquals(false,ie.test("boo"));
assertEquals(false,ie.test(""));
assertEquals(false,ie.test("xxx"));
assertEquals(true,ie.matches("foobar"));
assertEquals(true,ie.matches("Ant"));
assertEquals(true,ie.test("foobar"));
assertEquals(true,ie.test("Ant"));
}
}

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.util;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
@ -119,4 +120,12 @@ public class TypeUtilTest
Assert.assertFalse(TypeUtil.isFalse("blargle"));
Assert.assertFalse(TypeUtil.isFalse(new Object(){@Override public String toString(){return "true";}}));
}
@Test
public void testLoadedFrom() throws Exception
{
Assert.assertThat(TypeUtil.getLoadedFrom(String.class).toString(),Matchers.containsString("/rt.jar"));
Assert.assertThat(TypeUtil.getLoadedFrom(Assert.class).toString(),Matchers.containsString(".jar"));
Assert.assertThat(TypeUtil.getLoadedFrom(TypeUtil.class).toString(),Matchers.containsString("/classes/"));
}
}

View File

@ -18,12 +18,17 @@
package org.eclipse.jetty.util;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
@ -286,4 +291,15 @@ public class URIUtilTest
}
/* ------------------------------------------------------------ */
@Test
public void testJarSource() throws Exception
{
assertThat(URIUtil.getJarSource("file:///tmp/"),is("file:///tmp/"));
assertThat(URIUtil.getJarSource("jar:file:///tmp/foo.jar"),is("file:///tmp/foo.jar"));
assertThat(URIUtil.getJarSource("jar:file:///tmp/foo.jar!/some/path"),is("file:///tmp/foo.jar"));
assertThat(URIUtil.getJarSource(new URI("file:///tmp/")),is(new URI("file:///tmp/")));
assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar")),is(new URI("file:///tmp/foo.jar")));
assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar!/some/path")),is(new URI("file:///tmp/foo.jar")));
}
}

View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call class="org.eclipse.jetty.webapp.WebAppContext" name="addSystemClasses">
<Arg><Ref refid="Server"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addSystemClasses"/></Arg>
</Call>
</Arg>
</Call>
<Call class="org.eclipse.jetty.webapp.WebAppContext" name="addServerClasses">
<Arg><Ref refid="Server"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addServerClasses"/></Arg>
</Call>
</Arg>
</Call>
</Configure>

View File

@ -6,5 +6,23 @@ classpath. Without this, only Jetty specific handlers may be deployed.
servlet
security
[xml]
etc/jetty-webapp.xml
[lib]
lib/jetty-webapp-${jetty.version}.jar
[ini-template]
## Add to the server wide default jars and packages protected or hidden from webapps.
## System classes are protected and cannot be overridden by a webapp.
## Server classes are hidden and cannot be seen by a webapp
## Lists of patterns are comma separated and may be either:
## + a qualified classname e.g. 'com.acme.Foo'
## + a package name e.g. 'net.example.'
## + a jar file e.g. 'file:${jetty.base}/lib/dependency.jar'
## + a directory of jars,resource or classes e.g. 'file:${jetty.base}/resources'
## + A pattern preceeded with a '-' is an exclusion, all other patterns are inclusions
##
#jetty.webapp.addSystemClasses=
#jetty.webapp.addServerClasses=

View File

@ -19,15 +19,36 @@
package org.eclipse.jetty.webapp;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import java.io.File;
import java.net.URL;
import java.nio.file.Path;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.IncludeExcludeSet;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
/* ------------------------------------------------------------ */
/**
* Classpath classes list performs pattern matching of a class name
* against an classpath pattern entries.
* A class pattern is a string of one of the forms/rules:<ul>
* Classpath classes list performs sequential pattern matching of a class name
* against an internal array of classpath pattern entries.
* A class pattern is a string of one of the forms:<ul>
* <li>'org.package.SomeClass' will match a specific class
* <li>'org.package.' will match a specific package hierarchy
* <li>'-org.package.Classname' excludes a specific class
@ -36,45 +57,64 @@ import java.util.stream.Collectors;
* are to be explicitly included or excluded (eg. org.example.MyClass$NestedClass).
* <li>Nested classes are matched by their containing class. (eg. -org.example.MyClass
* would exclude org.example.MyClass$AnyNestedClass)
* <li>Package or Class exclusions are applied before inclusive patterns.
* </ul>
* When class is initialized from a classpath pattern string, entries
* in this string should be separated by ':' (semicolon) or ',' (comma).
*/
public class ClasspathPattern
public class ClasspathPattern extends AbstractSet<String>
{
private static final Logger LOG = Log.getLogger(ClasspathPattern.class);
enum Type { PACKAGE, CLASSNAME, LOCATION }
private static class Entry
{
final String _pattern;
final String _name;
final boolean _inclusive;
final boolean _package;
private final String _pattern;
private final String _name;
private final boolean _inclusive;
private final Type _type;
Entry(String pattern)
{
_pattern=pattern;
_inclusive = !pattern.startsWith("-");
_package = pattern.endsWith(".");
_name = _inclusive ? pattern : pattern.substring(1).trim();
_type = (_name.startsWith("file:"))?Type.LOCATION:(_name.endsWith(".")?Type.PACKAGE:Type.CLASSNAME);
}
boolean isInclusive()
Entry(String name, boolean include)
{
return _inclusive;
_pattern=include?name:("-"+name);
_inclusive = include;
_name = name;
_type = (_name.startsWith("file:"))?Type.LOCATION:(_name.endsWith(".")?Type.PACKAGE:Type.CLASSNAME);
}
@Override
public boolean equals(Object o)
public String getPattern()
{
if (o instanceof Entry)
{
Entry e=(Entry)o;
if (_pattern==null && e._pattern==null)
return true;
return _pattern.equals(e._pattern);
}
return false;
return _pattern;
}
public boolean isPackage()
{
return _type==Type.PACKAGE;
}
public boolean isClassName()
{
return _type==Type.CLASSNAME;
}
public boolean isLocation()
{
return _type==Type.LOCATION;
}
public String getName()
{
return _name;
}
@Override
@ -82,183 +122,407 @@ public class ClasspathPattern
{
return _pattern;
}
@Override
public int hashCode()
{
return _pattern.hashCode();
}
@Override
public boolean equals(Object o)
{
return (o instanceof Entry)
&& _pattern.equals(((Entry)o)._pattern);
}
public boolean isInclusive()
{
return _inclusive;
}
}
final private List<Entry> _entries = new ArrayList<Entry>();
/* ------------------------------------------------------------ */
public static class ByPackage extends AbstractSet<Entry> implements Predicate<String>
{
private final ArrayTernaryTrie.Growing<Entry> _entries = new ArrayTernaryTrie.Growing<>(false,512,512);
@Override
public boolean test(String name)
{
return _entries.getBest(name)!=null;
}
@Override
public Iterator<Entry> iterator()
{
return _entries.keySet().stream().map(k->_entries.get(k)).iterator();
}
@Override
public int size()
{
return _entries.size();
}
@Override
public boolean isEmpty()
{
return _entries.isEmpty();
}
@Override
public boolean add(Entry entry)
{
String name = entry.getName();
if (entry.isClassName())
name+="$";
else if (entry.isLocation())
throw new IllegalArgumentException(entry.toString());
else if (".".equals(name))
name="";
if (_entries.get(name)!=null)
return false;
_entries.put(name,entry);
return true;
}
@Override
public boolean remove(Object entry)
{
if (!(entry instanceof Entry))
return false;
return _entries.remove(((Entry)entry).getName())!=null;
}
@Override
public void clear()
{
_entries.clear();
}
}
@SuppressWarnings("serial")
public static class ByName extends HashSet<Entry> implements Predicate<String>
{
private final Map<String,Entry> _entries = new HashMap<>();
@Override
public boolean test(String name)
{
return _entries.containsKey(name);
}
@Override
public Iterator<Entry> iterator()
{
return _entries.values().iterator();
}
@Override
public int size()
{
return _entries.size();
}
@Override
public boolean add(Entry entry)
{
if (!entry.isClassName())
throw new IllegalArgumentException(entry.toString());
return _entries.put(entry.getName(),entry)==null;
}
@Override
public boolean remove(Object entry)
{
if (!(entry instanceof Entry))
return false;
return _entries.remove(((Entry)entry).getName())!=null;
}
}
public static class ByPackageOrName extends AbstractSet<Entry> implements Predicate<String>
{
private final ByName _byName = new ByName();
private final ByPackage _byPackage = new ByPackage();
@Override
public boolean test(String name)
{
return _byPackage.test(name)
|| _byName.test(name) ;
}
@Override
public Iterator<Entry> iterator()
{
// by package contains all entries (classes are also $ packages).
return _byPackage.iterator();
}
@Override
public int size()
{
return _byPackage.size();
}
@Override
public boolean add(Entry e)
{
if (e.isLocation())
throw new IllegalArgumentException();
if (e.isPackage())
return _byPackage.add(e);
// Add class name to packages also as classes act
// as packages for nested classes.
boolean added = _byPackage.add(e);
added = _byName.add(e) || added;
return added;
}
@Override
public boolean remove(Object o)
{
if (!(o instanceof Entry))
return false;
boolean removed = _byPackage.remove(o);
if (!((Entry)o).isPackage())
removed = _byName.remove(o) || removed;
return removed;
}
@Override
public void clear()
{
_byPackage.clear();
_byName.clear();
}
}
@SuppressWarnings("serial")
public static class ByLocation extends HashSet<File> implements Predicate<Path>
{
@Override
public boolean test(Path path)
{
for (File file: this)
{
if (file.isDirectory())
{
if (path.startsWith(file.toPath()))
return true;
}
else
{
if (path.equals(file.toPath()))
return true;
}
}
return false;
}
}
Map<String,Entry> _entries = new HashMap<>();
Set<String> _classes = new HashSet<>();
IncludeExcludeSet<Entry,String> _patterns = new IncludeExcludeSet<>(ByPackageOrName.class);
IncludeExcludeSet<File,Path> _locations = new IncludeExcludeSet<>(ByLocation.class);
public ClasspathPattern()
{
}
public ClasspathPattern(ClasspathPattern patterns)
{
if (patterns!=null)
setAll(patterns.getPatterns());
}
/* ------------------------------------------------------------ */
public ClasspathPattern(String... patterns)
{
if (patterns!=null && patterns.length>0)
add(patterns);
setAll(patterns);
}
/* ------------------------------------------------------------ */
public ClasspathPattern(String pattern)
{
add(pattern);
}
/* ------------------------------------------------------------ */
public ClasspathPattern(ClasspathPattern patterns)
public boolean include(String name)
{
add(patterns);
if (name==null)
return false;
return add(new Entry(name,true));
}
public boolean include(String... name)
{
boolean added = false;
for (String n:name)
if (n!=null)
added = add(new Entry(n,true)) || added;
return added;
}
public boolean exclude(String name)
{
if (name==null)
return false;
return add(new Entry(name,false));
}
public boolean exclude(String... name)
{
boolean added = false;
for (String n:name)
if (n!=null)
added = add(new Entry(n,false)) || added;
return added;
}
@Override
public boolean add(String pattern)
{
if (pattern==null)
return false;
return add(new Entry(pattern));
}
public boolean add(String... pattern)
{
boolean added = false;
for (String p:pattern)
if (p!=null)
added = add(new Entry(p)) || added;
return added;
}
protected boolean add(Entry entry)
{
if (_entries.containsKey(entry.getPattern()))
return false;
_entries.put(entry.getPattern(),entry);
if (entry.isLocation())
{
try
{
File file = Resource.newResource(entry.getName()).getFile().getAbsoluteFile().getCanonicalFile();
if (entry.isInclusive())
_locations.include(file);
else
_locations.exclude(file);
}
catch (Exception e)
{
throw new IllegalArgumentException(e);
}
}
else
{
if (entry.isInclusive())
_patterns.include(entry);
else
_patterns.exclude(entry);
}
return true;
}
/* ------------------------------------------------------------ */
@Override
public boolean remove(Object o)
{
if (!(o instanceof String))
return false;
String pattern = (String)o;
Entry entry = _entries.remove(pattern);
if (entry==null)
return false;
List<Entry> saved = new ArrayList<>(_entries.values());
clear();
for (Entry e:saved)
add(e);
return true;
}
@Override
public void clear()
{
_entries.clear();
_patterns.clear();
_locations.clear();
}
/* ------------------------------------------------------------ */
public boolean isEmpty()
@Override
public Iterator<String> iterator()
{
return _entries.isEmpty();
return _entries.keySet().iterator();
}
/* ------------------------------------------------------------ */
public void exclude(String... patterns)
{
if (patterns==null || patterns.length==0)
return;
for (String p :patterns)
{
if (p.startsWith("-"))
throw new IllegalArgumentException();
String x="-"+p;
if (_entries.stream().anyMatch(e->{return x.equals(e.toString());}))
continue;
Entry e = new Entry(x);
_entries.add(0,e);
}
}
/* ------------------------------------------------------------ */
public void add(String... patterns)
{
if (patterns==null || patterns.length==0)
return;
for (String p :patterns)
{
if (_entries.stream().anyMatch(e->{return p.equals(e.toString());}))
continue;
Entry e = new Entry(p);
if (e.isInclusive())
_entries.add(e);
else
_entries.add(0,e);
}
}
/* ------------------------------------------------------------ */
public void add(ClasspathPattern pattern)
{
if (pattern==null)
return;
for (Entry e :pattern._entries)
{
if (_entries.contains(e))
continue;
if (e.isInclusive())
_entries.add(e);
else
_entries.add(0,e);
}
}
/* ------------------------------------------------------------ */
public void addInclusions(ClasspathPattern pattern)
@Override
public int size()
{
if (pattern==null)
return;
return _entries.size();
}
for (Entry e :pattern._entries)
{
if (_entries.contains(e))
continue;
if (e.isInclusive())
_entries.add(e);
}
}
/* ------------------------------------------------------------ */
public void addExclusions(ClasspathPattern pattern)
/**
* Initialize the matcher by parsing each classpath pattern in an array
*
* @param classes array of classpath patterns
*/
private void setAll(String[] classes)
{
if (pattern==null)
return;
for (Entry e :pattern._entries)
{
if (_entries.contains(e))
continue;
if (!e.isInclusive())
_entries.add(0,e);
}
_entries.clear();
addAll(classes);
}
/* ------------------------------------------------------------ */
public boolean remove(String pattern)
/**
* @param classes array of classpath patterns
*/
private void addAll(String[] classes)
{
for (int i=_entries.size();i-->0;)
{
if (pattern.equals(_entries.get(i)._pattern))
{
_entries.remove(i);
return true;
}
}
return false;
if (classes!=null)
addAll(Arrays.asList(classes));
}
/* ------------------------------------------------------------ */
/**
* @return array of classpath patterns
*/
public String[] toArray()
public String[] getPatterns()
{
return _entries.stream().map(e->{return e.toString();}).toArray(String[]::new);
return toArray(new String[_entries.size()]);
}
/* ------------------------------------------------------------ */
/**
* @return array of classpath patterns
* @return array of inclusive classpath patterns
*/
public List<String> getPatterns()
public String[] getInclusions()
{
return _entries.stream().map(e->{return e.toString();}).collect(Collectors.toList());
return _entries.values().stream().filter(Entry::isInclusive).map(Entry::getName).toArray(String[]::new);
}
/* ------------------------------------------------------------ */
/**
* @return List of classes excluded class exclusions and package patterns
* @return array of excluded classpath patterns (without '-' prefix)
*/
public List<String> getClasses()
public String[] getExclusions()
{
List<String> list = new ArrayList<>();
for (Entry e:_entries)
{
if (e._inclusive && !e._package)
list.add(e._name);
}
return list;
return _entries.values().stream().filter(e->!e.isInclusive()).map(Entry::getName).toArray(String[]::new);
}
/* ------------------------------------------------------------ */
/**
* Match the class name against the pattern
*
@ -267,26 +531,67 @@ public class ClasspathPattern
*/
public boolean match(String name)
{
name = name.replace('/','.');
for (Entry entry : _entries)
return _patterns.test(name);
}
/**
* Match the class name against the pattern
*
* @param clazz A class to try to match
* @return true if class matches the pattern
*/
public boolean match(Class<?> clazz)
{
try
{
if (entry==null)
continue;
if (entry._package)
{
if (name.startsWith(entry._name) || ".".equals(entry._pattern))
return entry._inclusive;
}
else
{
if (name.equals(entry._name))
return entry._inclusive;
if (name.length()>entry._name.length() && '$'==name.charAt(entry._name.length()) && name.startsWith(entry._name))
return entry._inclusive;
}
Resource resource = TypeUtil.getLoadedFrom(clazz);
Path path = resource.getFile().toPath();
Boolean byName = _patterns.isIncludedAndNotExcluded(clazz.getName());
Boolean byLocation = _locations.isIncludedAndNotExcluded(path);
// Combine the tri-state match of both IncludeExclude Sets
boolean included = byName==TRUE || byLocation==TRUE
|| (byName==null && !_patterns.hasIncludes() && byLocation==null && !_locations.hasIncludes());
boolean excluded = byName==FALSE || byLocation==FALSE;
return included && !excluded;
}
catch (Exception e)
{
LOG.warn(e);
}
return false;
}
public boolean match(String name, URL url)
{
// Strip class suffix for name matching
if (name.endsWith(".class"))
name=name.substring(0,name.length()-6);
// Treat path elements as packages for name matching
name=name.replace("/",".");
Boolean byName = _patterns.isIncludedAndNotExcluded(name);
// Try to find a file path for location matching
Boolean byLocation = null;
try
{
Resource resource = Resource.newResource(URIUtil.getJarSource(url.toURI()));
File file = resource.getFile();
byLocation = _locations.isIncludedAndNotExcluded(file.toPath());
}
catch(Exception e)
{
LOG.ignore(e);
}
// Combine the tri-state match of both IncludeExclude Sets
boolean included = byName==TRUE || byLocation==TRUE
|| (byName==null && !_patterns.hasIncludes() && byLocation==null && !_locations.hasIncludes());
boolean excluded = byName==FALSE || byLocation==FALSE;
return included && !excluded;
}
}

View File

@ -101,7 +101,7 @@ public class WebAppClassLoader extends URLClassLoader
* @return Returns the permissions.
*/
PermissionCollection getPermissions();
/* ------------------------------------------------------------ */
/** Is the class a System Class.
* A System class is a class that is visible to a webapplication,
@ -110,7 +110,7 @@ public class WebAppClassLoader extends URLClassLoader
* @param clazz The fully qualified name of the class.
* @return True if the class is a system class.
*/
boolean isSystemClass(String clazz);
boolean isSystemClass(Class<?> clazz);
/* ------------------------------------------------------------ */
/** Is the class a Server Class.
@ -121,7 +121,7 @@ public class WebAppClassLoader extends URLClassLoader
* @param clazz The fully qualified name of the class.
* @return True if the class is a server class.
*/
boolean isServerClass(String clazz);
boolean isServerClass(Class<?> clazz);
/* ------------------------------------------------------------ */
/**
@ -134,6 +134,10 @@ public class WebAppClassLoader extends URLClassLoader
/* ------------------------------------------------------------ */
String getExtraClasspath();
boolean isServerResource(String name, URL parent_url);
boolean isSystemResource(String name, URL webapp_url);
}
@ -141,9 +145,10 @@ public class WebAppClassLoader extends URLClassLoader
/** Run an action with access to ServerClasses
* <p>Run the passed {@link PrivilegedExceptionAction} with the classloader
* configured so as to allow server classes to be visible</p>
* @param <T> The type returned by the action
* @param action The action to run
* @return The return from the action
* @throws Exception when not able to run with server classes
* @throws Exception if thrown by the action
* @param <T> the type of PrivilegedExceptionAction
*/
public static <T> T runWithServerClassAccess(PrivilegedExceptionAction<T> action) throws Exception
@ -361,27 +366,42 @@ public class WebAppClassLoader extends URLClassLoader
@Override
public Enumeration<URL> getResources(String name) throws IOException
{
boolean system_class=_context.isSystemClass(name);
boolean server_class=_context.isServerClass(name) && !Boolean.TRUE.equals(__loadServerClasses.get());
List<URL> from_parent = new ArrayList<>();
List<URL> from_webapp = new ArrayList<>();
Enumeration<URL> urls = _parent.getResources(name);
while (urls!=null && urls.hasMoreElements())
{
URL url = urls.nextElement();
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerResource(name,url))
from_parent.add(url);
}
urls = this.findResources(name);
while (urls!=null && urls.hasMoreElements())
{
URL url = urls.nextElement();
if (!_context.isSystemResource(name,url) || from_parent.isEmpty())
from_webapp.add(url);
}
List<URL> resources;
List<URL> from_parent = toList(server_class?null:_parent.getResources(name));
List<URL> from_webapp = toList((system_class&&!from_parent.isEmpty())?null:this.findResources(name));
if (_context.isParentLoaderPriority())
{
from_parent.addAll(from_webapp);
return Collections.enumeration(from_parent);
resources = from_parent;
}
from_webapp.addAll(from_parent);
return Collections.enumeration(from_webapp);
}
else
{
from_webapp.addAll(from_parent);
resources = from_webapp;
}
if (LOG.isDebugEnabled())
LOG.debug("getResources {} {}",name,resources);
/* ------------------------------------------------------------ */
private List<URL> toList(Enumeration<URL> e)
{
if (e==null)
return new ArrayList<URL>();
return Collections.list(e);
return Collections.enumeration(resources);
}
/* ------------------------------------------------------------ */
@ -395,138 +415,180 @@ public class WebAppClassLoader extends URLClassLoader
@Override
public URL getResource(String name)
{
URL url= null;
boolean tried_parent= false;
//If the resource is a class name with .class suffix, strip it off before comparison
//as the server and system patterns are specified without a .class suffix
String tmp = name;
if (tmp != null && tmp.endsWith(".class"))
tmp = tmp.substring(0, tmp.length()-6);
boolean system_class=_context.isSystemClass(tmp);
boolean server_class=_context.isServerClass(tmp) && !Boolean.TRUE.equals(__loadServerClasses.get());
if (LOG.isDebugEnabled())
LOG.debug("getResource({}) system={} server={} cl={}",name,system_class,server_class,this);
if (system_class && server_class)
return null;
ClassLoader source=null;
if (_parent!=null &&(_context.isParentLoaderPriority() || system_class ) && !server_class)
URL resource=null;
if (_context.isParentLoaderPriority())
{
tried_parent= true;
URL parent_url=_parent.getResource(name);
if (_parent!=null)
// return if we have a url the webapp is allowed to see
if (parent_url!=null
&& (Boolean.TRUE.equals(__loadServerClasses.get())
|| !_context.isServerResource(name,parent_url)))
resource = parent_url;
else
{
source=_parent;
url=_parent.getResource(name);
URL webapp_url = this.findResource(name);
// If found here then OK to use regardless of system or server classes
// If it is a system resource, we've already tried to load from parent, so
// would have returned it.
// If it is a server resource, doesn't matter as we have loaded it from the
// webapp
if (webapp_url!=null)
resource = webapp_url;
}
}
if (url == null)
else
{
url= this.findResource(name);
source=this;
if (url == null && name.startsWith("/"))
url= this.findResource(name.substring(1));
}
URL webapp_url = this.findResource(name);
if (url == null && !tried_parent && !server_class )
{
if (_parent!=null)
if (webapp_url!=null && !_context.isSystemResource(name,webapp_url))
resource = webapp_url;
else
{
tried_parent=true;
source=_parent;
url= _parent.getResource(name);
// Couldn't find or see a webapp resource, so try a parent
URL parent_url=_parent.getResource(name);
if (parent_url!=null
&& (Boolean.TRUE.equals(__loadServerClasses.get())
|| !_context.isServerResource(name,parent_url)))
resource = parent_url;
// We couldn't find a parent resource, so OK to return a webapp one if it exists
// and we just couldn't see it before
else if (webapp_url!=null)
resource = webapp_url;
}
}
// Perhaps this failed due to leading /
if (resource==null && name.startsWith("/"))
resource = getResource(name.substring(1));
if (LOG.isDebugEnabled())
LOG.debug("gotResource({})=={} from={} tried_parent={}",name,url,source,tried_parent);
return url;
LOG.debug("getResource {} {}",name,resource);
return resource;
}
/* ------------------------------------------------------------ */
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
LOG.setDebugEnabled(true);
WebAppContext.LOG.setDebugEnabled(true);
synchronized (getClassLoadingLock(name))
{
Class<?> c= findLoadedClass(name);
{
ClassNotFoundException ex= null;
boolean tried_parent= false;
boolean system_class=_context.isSystemClass(name);
boolean server_class=_context.isServerClass(name) && !Boolean.TRUE.equals(__loadServerClasses.get());
if (LOG.isDebugEnabled())
LOG.debug("loadClass({}) system={} server={} cl={}",name,system_class,server_class,this);
Class<?> parent_class = null;
Class<?> webapp_class = null;
ClassLoader source=null;
if (system_class && server_class)
{
return null;
}
if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class)
{
tried_parent= true;
source=_parent;
try
{
c= _parent.loadClass(name);
if (LOG.isDebugEnabled())
LOG.debug("loaded " + c);
}
catch (ClassNotFoundException e)
{
ex= e;
}
}
if (c == null)
{
try
{
source=this;
c= this.findClass(name);
}
catch (ClassNotFoundException e)
{
ex= e;
}
}
if (c == null && _parent!=null && !tried_parent && !server_class )
{
tried_parent=true;
source=_parent;
c= _parent.loadClass(name);
}
if (c == null && ex!=null)
// Has this loader loaded the class already?
webapp_class = findLoadedClass(name);
if (webapp_class != null)
{
if (LOG.isDebugEnabled())
LOG.debug("!loadedClass({}) from={} tried_parent={}",name,this,tried_parent);
LOG.debug("found webapp loaded {}",webapp_class);
return webapp_class;
}
// Should we try the parent loader first?
if (_context.isParentLoaderPriority())
{
// Try the parent loader
try
{
parent_class = _parent.loadClass(name);
// If the webapp is allowed to see this class
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parent_class))
{
if (LOG.isDebugEnabled())
LOG.debug("PLP parent loaded {}",parent_class);
return parent_class;
}
}
catch (ClassNotFoundException e)
{
// Save it for later
ex = e;
}
// Try the webapp loader
try
{
// If found here then OK to use regardless of system or server classes
// If it is a system class, we've already tried to load from parent, so
// would have returned it.
// If it is a server class, doesn't matter as we have loaded it from the
// webapp
webapp_class = this.findClass(name);
resolveClass(webapp_class);
if (LOG.isDebugEnabled())
LOG.debug("PLP webapp loaded {}",webapp_class);
return webapp_class;
}
catch (ClassNotFoundException e)
{
if (ex==null)
ex = e;
else
ex.addSuppressed(e);
}
throw ex;
}
if (LOG.isDebugEnabled())
LOG.debug("loadedClass({})=={} from={} tried_parent={}",name,c,source,tried_parent);
if (resolve)
else
{
resolveClass(c);
if (LOG.isDebugEnabled())
LOG.debug("resolved({})=={} from={} tried_parent={}",name,c,source,tried_parent);
}
// Not parent loader priority, so...
return c;
// Try the webapp classloader first
// Look in the webapp classloader as a resource, to avoid
// loading a system class.
String path = name.replace('.', '/').concat(".class");
URL webapp_url = findResource(path);
if (webapp_url!=null && !_context.isSystemResource(name,webapp_url))
{
webapp_class = this.foundClass(name,webapp_url);
resolveClass(webapp_class);
if (LOG.isDebugEnabled())
LOG.debug("WAP webapp loaded {}",webapp_class);
return webapp_class;
}
// Try the parent loader
try
{
parent_class = _parent.loadClass(name);
// If the webapp is allowed to see this class
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parent_class))
{
if (LOG.isDebugEnabled())
LOG.debug("WAP parent loaded {}",parent_class);
return parent_class;
}
}
catch (ClassNotFoundException e)
{
ex=e;
}
// We couldn't find a parent class, so OK to return a webapp one if it exists
// and we just couldn't see it before
if (webapp_url!=null)
{
webapp_class = this.foundClass(name,webapp_url);
resolveClass(webapp_class);
if (LOG.isDebugEnabled())
LOG.debug("WAP !server webapp loaded {}",webapp_class);
return webapp_class;
}
throw ex==null?new ClassNotFoundException(name):ex;
}
}
}
@ -564,69 +626,71 @@ public class WebAppClassLoader extends URLClassLoader
{
return _transformers.remove(transformer);
}
/* ------------------------------------------------------------ */
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException
{
Class<?> clazz=null;
if (_transformers.isEmpty())
clazz = super.findClass(name);
else
return super.findClass(name);
String path = name.replace('.', '/').concat(".class");
URL url = findResource(path);
if (url==null)
throw new ClassNotFoundException(name);
return foundClass(name,url);
}
/* ------------------------------------------------------------ */
protected Class<?> foundClass(final String name, URL url) throws ClassNotFoundException
{
if (_transformers.isEmpty())
return super.findClass(name);
InputStream content=null;
try
{
String path = name.replace('.', '/').concat(".class");
URL url = getResource(path);
if (url==null)
throw new ClassNotFoundException(name);
content = url.openStream();
byte[] bytes = IO.readBytes(content);
InputStream content=null;
try
if (LOG.isDebugEnabled())
LOG.debug("foundClass({}) url={} cl={}",name,url,this);
for (ClassFileTransformer transformer : _transformers)
{
content = url.openStream();
byte[] bytes = IO.readBytes(content);
byte[] tmp = transformer.transform(this,name,null,null,bytes);
if (tmp != null)
bytes = tmp;
}
if (LOG.isDebugEnabled())
LOG.debug("foundClass({}) url={} cl={}",name,url,this);
for (ClassFileTransformer transformer : _transformers)
return defineClass(name,bytes,0,bytes.length);
}
catch (IOException e)
{
throw new ClassNotFoundException(name,e);
}
catch (IllegalClassFormatException e)
{
throw new ClassNotFoundException(name,e);
}
finally
{
if (content!=null)
{
try
{
byte[] tmp = transformer.transform(this,name,null,null,bytes);
if (tmp != null)
bytes = tmp;
content.close();
}
clazz=defineClass(name,bytes,0,bytes.length);
}
catch (IOException e)
{
throw new ClassNotFoundException(name,e);
}
catch (IllegalClassFormatException e)
{
throw new ClassNotFoundException(name,e);
}
finally
{
if (content!=null)
catch (IOException e)
{
try
{
content.close();
}
catch (IOException e)
{
throw new ClassNotFoundException(name,e);
}
throw new ClassNotFoundException(name,e);
}
}
}
return clazz;
}
/* ------------------------------------------------------------ */
@Override
public void close() throws IOException
{
@ -639,4 +703,5 @@ public class WebAppClassLoader extends URLClassLoader
{
return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode());
}
}

View File

@ -25,6 +25,7 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EventListener;
@ -63,6 +64,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.TopologicalSort;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ -155,7 +157,7 @@ import org.eclipse.jetty.util.resource.ResourceCollection;
@ManagedObject("Web Application ContextHandler")
public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context
{
private static final Logger LOG = Log.getLogger(WebAppContext.class);
static final Logger LOG = Log.getLogger(WebAppContext.class);
public static final String TEMPDIR = "javax.servlet.context.tempdir";
public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir";
@ -177,6 +179,23 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
"org.w3c." // javax.xml
) ;
// Find the location of the JVM lib directory
public final static String __jvmlib;
static
{
String lib=null;
try
{
lib=TypeUtil.getLoadedFrom(System.class).getFile().getParentFile().toURI().toString();
}
catch(Exception e)
{
LOG.warn(e);
lib=null;
}
__jvmlib=lib;
}
// Server classes are classes that are hidden from being
// loaded by the web application using system classloader,
// so if web application needs to load any of such classes,
@ -476,15 +495,15 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
{
// Add the known server class inclusions for all known configurations
for (Configuration configuration : Configurations.getKnown())
_serverClasses.addInclusions(configuration.getServerClasses());
_serverClasses.include(configuration.getServerClasses().getInclusions());
// Setup Configuration classes for this webapp!
loadConfigurations();
_configurations.sort();
for (Configuration configuration:_configurations)
{
_systemClasses.add(configuration.getSystemClasses());
_serverClasses.addExclusions(configuration.getServerClasses());
_systemClasses.add(configuration.getSystemClasses().getPatterns());
_serverClasses.exclude(configuration.getServerClasses().getExclusions());
}
// Configure classloader
@ -679,17 +698,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
return _permissions;
}
/* ------------------------------------------------------------ */
/**
* @see #setServerClasses(String[])
* @return Returns the serverClasses.
*/
@ManagedAttribute(value="classes and packages hidden by the context classloader", readonly=true)
public String[] getServerClasses()
{
return _serverClasses.toArray();
}
/* ------------------------------------------------------------ */
/**
* Set the server classes patterns.
@ -703,7 +711,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
public void setServerClasspathPattern(ClasspathPattern serverClasses)
{
_serverClasses.clear();
_serverClasses.add(serverClasses);
_serverClasses.add(serverClasses.getPatterns());
}
/* ------------------------------------------------------------ */
@ -718,122 +726,98 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
public void setSystemClasspathPattern(ClasspathPattern systemClasses)
{
_systemClasses.clear();
_systemClasses.add(systemClasses);
_systemClasses.add(systemClasses.getPatterns());
}
/* ------------------------------------------------------------ */
public void addServerClasspathPattern(ClasspathPattern serverClasses)
{
_serverClasses.add(serverClasses);
_serverClasses.add(serverClasses.getPatterns());
}
/* ------------------------------------------------------------ */
public void addSystemClasspathPattern(ClasspathPattern systemClasses)
{
_serverClasses.add(systemClasses);
}
/* ------------------------------------------------------------ */
public ClasspathPattern getServerClasspathPattern()
{
return _serverClasses;
_serverClasses.add(systemClasses.getPatterns());
}
/* ------------------------------------------------------------ */
/**
* @return The ClasspathPattern used to match System (protected) classes
*/
public ClasspathPattern getSystemClasspathPattern()
{
return _systemClasses;
}
/* ------------------------------------------------------------ */
/** Add to the list of Server classes.
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the server classes. This argument
* may also be a comma separated list of classOrPackage patterns.
* @deprecated use {@link #addServerClasspathPattern(ClasspathPattern)}
* @see #setServerClasses(String[])
* @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
/**
* @return The ClasspathPattern used to match Server (hidden) classes
*/
public void addServerClass(String classOrPackage)
public ClasspathPattern getServerClasspathPattern()
{
_serverClasses.add(classOrPackage);
return _serverClasses;
}
/* ------------------------------------------------------------ */
/** Prepend to the list of Server classes.
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the server classes. This argument may also be a comma
* separated list of classOrPackage patterns.
* @deprecated use {@link #addServerClasspathPattern(ClasspathPattern)}
* @see #setServerClasses(String[])
* @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
*/
public void prependServerClass(String classOrPackage)
@ManagedAttribute(value="classes and packages protected by context classloader", readonly=true)
public String[] getSystemClasses()
{
addServerClass(classOrPackage);
return _systemClasses.getPatterns();
}
/* ------------------------------------------------------------ */
/**
* @deprecated use {@link #getSystemClasspathPattern()}.
* @see #setSystemClasses(String[])
* @return Returns the systemClasses.
* @see #setServerClasses(String[])
* @return Returns the serverClasses.
*/
@ManagedAttribute(value="classes and packages given priority by context classloader", readonly=true)
public String[] getSystemClasses()
@ManagedAttribute(value="classes and packages hidden by the context classloader", readonly=true)
public String[] getServerClasses()
{
return _systemClasses.toArray();
return _serverClasses.getPatterns();
}
/* ------------------------------------------------------------ */
@Override
public boolean isServerClass(Class<?> clazz)
{
boolean result = _serverClasses.match(clazz);
if (LOG.isDebugEnabled())
LOG.debug("isServerClass=={} {}",result,clazz);
return result;
}
/* ------------------------------------------------------------ */
/** Add to the list of System classes.
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the system classes.
* This argument may also be a comma
* separated list of classOrPackage patterns.
* @deprecated use {@link #addSystemClasspathPattern(ClasspathPattern)}
* @see #setSystemClasses(String[])
* @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
*/
public void addSystemClass(String classOrPackage)
@Override
public boolean isSystemClass(Class<?> clazz)
{
_systemClasses.add(classOrPackage);
boolean result = _systemClasses.match(clazz);
if (LOG.isDebugEnabled())
LOG.debug("isSystemClass=={} {}",result,clazz);
return result;
}
/* ------------------------------------------------------------ */
/** Prepend to the list of System classes.
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the system classes.
* This argument may also be a comma
* separated list of classOrPackage patterns.
* @deprecated use {@link #addSystemClasspathPattern(ClasspathPattern)}
* @see #setSystemClasses(String[])
* @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
*/
public void prependSystemClass(String classOrPackage)
@Override
public boolean isServerResource(String name, URL url)
{
_systemClasses.add(classOrPackage);
boolean result = _serverClasses.match(name,url);
if (LOG.isDebugEnabled())
LOG.debug("isServerResource=={} {} {}",result,name,url);
return result;
}
/* ------------------------------------------------------------ */
@Override
public boolean isServerClass(String name)
public boolean isSystemResource(String name, URL url)
{
return _serverClasses.match(name);
boolean result = _systemClasses.match(name,url);
if (LOG.isDebugEnabled())
LOG.debug("isSystemResource=={} {} {}",result,name,url);
return result;
}
/* ------------------------------------------------------------ */
@Override
public boolean isSystemClass(String name)
{
return _systemClasses.match(name);
}
/* ------------------------------------------------------------ */
@Override
public void setServer(Server server)
@ -847,7 +831,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
if (systemClasses instanceof String[])
systemClasses = new ClasspathPattern((String[])systemClasses);
if (systemClasses instanceof ClasspathPattern)
_systemClasses.add((ClasspathPattern)systemClasses);
_systemClasses.add(((ClasspathPattern)systemClasses).getPatterns());
}
if (_serverClasses.isEmpty())
@ -856,7 +840,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
if (serverClasses instanceof String[])
serverClasses = new ClasspathPattern((String[])serverClasses);
if (serverClasses instanceof ClasspathPattern)
_systemClasses.add((ClasspathPattern)serverClasses);
_systemClasses.add(((ClasspathPattern)serverClasses).getPatterns());
}
}
}
@ -969,10 +953,24 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
@Override
public void dump(Appendable out, String indent) throws IOException
{
List<String> system_classes=null;
if (_systemClasses!=null)
{
system_classes=new ArrayList<>(_systemClasses);
Collections.sort(system_classes);
}
List<String> server_classes=null;
if (_serverClasses!=null)
{
server_classes=new ArrayList<>(_serverClasses);
Collections.sort(server_classes);
}
dumpBeans(out,indent,
Collections.singletonList(new ClassLoaderDump(getClassLoader())),
Collections.singletonList(new DumpableCollection("Systemclasses "+this,_systemClasses==null?Collections.emptyList():_systemClasses.getPatterns())),
Collections.singletonList(new DumpableCollection("Serverclasses "+this,_serverClasses==null?Collections.emptyList():_serverClasses.getPatterns())),
Collections.singletonList(new DumpableCollection("Systemclasses "+this,system_classes)),
Collections.singletonList(new DumpableCollection("Serverclasses "+this,server_classes)),
Collections.singletonList(new DumpableCollection("Configurations "+this,_configurations.getConfigurations())),
Collections.singletonList(new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet())),
Collections.singletonList(new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet())),
@ -1497,7 +1495,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
{
//not one of the standard servlet listeners, check our extended session listener types
boolean ok = false;
for (Class l:SessionHandler.SESSION_LISTENER_TYPES)
for (Class<?> l:SessionHandler.SESSION_LISTENER_TYPES)
{
if (l.isAssignableFrom(listener))
{
@ -1525,11 +1523,11 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
for (int i=resources.length;i-->0;)
{
if (resources[i].getName().startsWith("jar:file"))
return resources[i].getURL();
return resources[i].getURI().toURL();
}
}
return resource.getURL();
return resource.getURI().toURL();
}
/* ------------------------------------------------------------ */
@ -1555,7 +1553,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
return servletContext;
}
}
}
/* ------------------------------------------------------------ */
@ -1564,4 +1561,52 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
return _metadata;
}
/* ------------------------------------------------------------ */
public static void addServerClasses(Server server,String... pattern )
{
// look for a Server attribute with the list of Server classes
// to apply to every web application. If not present, use our defaults.
Object o = server.getAttribute(SERVER_SRV_CLASSES);
if (o instanceof ClasspathPattern)
{
((ClasspathPattern)o).add(pattern);
return;
}
String[] server_classes;
if (o instanceof String[])
server_classes = (String[])o;
else
server_classes = __dftServerClasses.getPatterns();
int l = server_classes.length;
server_classes = Arrays.copyOf(server_classes,l+pattern.length);
System.arraycopy(pattern,0,server_classes,l,pattern.length);
server.setAttribute(SERVER_SRV_CLASSES,server_classes);
}
/* ------------------------------------------------------------ */
public static void addSystemClasses(Server server,String... pattern )
{
// look for a Server attribute with the list of System classes
// to apply to every web application. If not present, use our defaults.
Object o = server.getAttribute(SERVER_SYS_CLASSES);
if (o instanceof ClasspathPattern)
{
((ClasspathPattern)o).add(pattern);
return;
}
String[] system_classes;
if (o instanceof String[])
system_classes = (String[])o;
else
system_classes = __dftSystemClasses.getPatterns();
int l = system_classes.length;
system_classes = Arrays.copyOf(system_classes,l+pattern.length);
System.arraycopy(pattern,0,system_classes,l,pattern.length);
server.setAttribute(SERVER_SYS_CLASSES,system_classes);
}
}

View File

@ -18,77 +18,214 @@
package org.eclipse.jetty.webapp;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.eclipse.jetty.toolchain.test.JDK;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import sun.security.provider.Sun;
public class ClasspathPatternTest
{
private ClasspathPattern pattern = new ClasspathPattern();
private final ClasspathPattern _pattern = new ClasspathPattern();
@Before
public void before()
{
pattern = new ClasspathPattern();
pattern.add("org.package.");
pattern.add("-org.excluded.");
pattern.add("org.example.FooBar");
pattern.add("-org.example.Excluded");
pattern.add("-org.example.Nested$Minus","org.example.Nested","org.example.Nested$Something");
_pattern.clear();
_pattern.add("org.package.");
_pattern.add("-org.excluded.");
_pattern.add("org.example.FooBar");
_pattern.add("-org.example.Excluded");
_pattern.addAll(Arrays.asList(new String[]{
"-org.example.Nested$Minus",
"org.example.Nested",
"org.example.Nested$Something"}));
assertThat(_pattern,containsInAnyOrder(
"org.package.",
"-org.excluded.",
"org.example.FooBar",
"-org.example.Excluded",
"-org.example.Nested$Minus",
"org.example.Nested",
"org.example.Nested$Something"
));
}
@Test
public void testClassMatch()
{
assertTrue(pattern.match("org.example.FooBar"));
assertTrue(pattern.match("org.example.Nested"));
assertTrue(_pattern.match("org.example.FooBar"));
assertTrue(_pattern.match("org.example.Nested"));
assertFalse(pattern.match("org.example.Unknown"));
assertFalse(pattern.match("org.example.FooBar.Unknown"));
assertFalse(_pattern.match("org.example.Unknown"));
assertFalse(_pattern.match("org.example.FooBar.Unknown"));
}
@Test
public void testPackageMatch()
{
assertTrue(pattern.match("org.package.Something"));
assertTrue(pattern.match("org.package.other.Something"));
assertTrue(_pattern.match("org.package.Something"));
assertTrue(_pattern.match("org.package.other.Something"));
assertFalse(pattern.match("org.example.Unknown"));
assertFalse(pattern.match("org.example.FooBar.Unknown"));
assertFalse(pattern.match("org.example.FooBarElse"));
assertFalse(_pattern.match("org.example.Unknown"));
assertFalse(_pattern.match("org.example.FooBar.Unknown"));
assertFalse(_pattern.match("org.example.FooBarElse"));
}
@Test
public void testExplicitNestedMatch()
{
assertTrue(pattern.match("org.example.Nested$Something"));
assertFalse(pattern.match("org.example.Nested$Minus"));
assertTrue(pattern.match("org.example.Nested$Other"));
assertTrue(_pattern.match("org.example.Nested$Something"));
assertFalse(_pattern.match("org.example.Nested$Minus"));
assertTrue(_pattern.match("org.example.Nested$Other"));
}
@Test
public void testImplicitNestedMatch()
{
assertTrue(pattern.match("org.example.FooBar$Other"));
assertTrue(pattern.match("org.example.Nested$Other"));
assertTrue(_pattern.match("org.example.FooBar$Other"));
assertTrue(_pattern.match("org.example.Nested$Other"));
}
@Test
public void testDoubledNested()
{
assertTrue(pattern.match("org.example.Nested$Something$Else"));
assertTrue(_pattern.match("org.example.Nested$Something$Else"));
assertFalse(pattern.match("org.example.Nested$Minus$Else"));
assertFalse(_pattern.match("org.example.Nested$Minus$Else"));
}
@Test
public void testMatchAll()
{
pattern.clear();
pattern.add(".");
assertTrue(pattern.match("org.example.Anything"));
assertTrue(pattern.match("org.example.Anything$Else"));
_pattern.clear();
_pattern.add(".");
assertTrue(_pattern.match("org.example.Anything"));
assertTrue(_pattern.match("org.example.Anything$Else"));
}
/**
*
*/
@SuppressWarnings("restriction")
@Test
public void testiIncludedLocations() throws Exception
{
// jar from JVM classloader
Resource loc_string = TypeUtil.getLoadedFrom(String.class);
// System.err.println(loc_string);
// another jar from JVM classloader
Resource loc_jsse = TypeUtil.getLoadedFrom(Sun.class);
// System.err.println(loc_jsse);
// a jar from maven repo jar
Resource loc_junit = TypeUtil.getLoadedFrom(Test.class);
// System.err.println(loc_junit);
// a jar from another maven repo jar
Resource loc_tool = TypeUtil.getLoadedFrom(JDK.class);
// System.err.println(loc_tool);
// class file
Resource loc_test = TypeUtil.getLoadedFrom(ClasspathPatternTest.class);
// System.err.println(loc_test);
ClasspathPattern pattern = new ClasspathPattern();
pattern.include("something");
assertThat(pattern.match(String.class),is(false));
assertThat(pattern.match(Sun.class),is(false));
assertThat(pattern.match(Test.class),is(false));
assertThat(pattern.match(JDK.class),is(false));
assertThat(pattern.match(ClasspathPatternTest.class),is(false));
// Add directory for both JVM classes
pattern.include(loc_string.getFile().getParentFile().toURI().toString());
// Add jar for individual class and classes directory
pattern.include(loc_junit.toString(),loc_test.toString());
assertThat(pattern.match(String.class),is(true));
assertThat(pattern.match(Sun.class),is(true));
assertThat(pattern.match(Test.class),is(true));
assertThat(pattern.match(JDK.class),is(false));
assertThat(pattern.match(ClasspathPatternTest.class),is(true));
// exclude by package name still works
pattern.add("-sun.security.provider.Sun");
assertThat(pattern.match(String.class),is(true));
assertThat(pattern.match(Sun.class),is(false));
assertThat(pattern.match(Test.class),is(true));
assertThat(pattern.match(JDK.class),is(false));
assertThat(pattern.match(ClasspathPatternTest.class),is(true));
}
/**
*
*/
@SuppressWarnings("restriction")
@Test
public void testExcludeLocations() throws Exception
{
// jar from JVM classloader
Resource loc_string = TypeUtil.getLoadedFrom(String.class);
// System.err.println(loc_string);
// another jar from JVM classloader
Resource loc_jsse = TypeUtil.getLoadedFrom(Sun.class);
// System.err.println(loc_jsse);
// a jar from maven repo jar
Resource loc_junit = TypeUtil.getLoadedFrom(Test.class);
// System.err.println(loc_junit);
// a jar from another maven repo jar
Resource loc_tool = TypeUtil.getLoadedFrom(JDK.class);
// System.err.println(loc_tool);
// class file
Resource loc_test = TypeUtil.getLoadedFrom(ClasspathPatternTest.class);
// System.err.println(loc_test);
ClasspathPattern pattern = new ClasspathPattern();
// include everything
pattern.include(".");
assertThat(pattern.match(String.class),is(true));
assertThat(pattern.match(Sun.class),is(true));
assertThat(pattern.match(Test.class),is(true));
assertThat(pattern.match(JDK.class),is(true));
assertThat(pattern.match(ClasspathPatternTest.class),is(true));
// Add directory for both JVM classes
pattern.exclude(loc_string.getFile().getParentFile().toURI().toString());
// Add jar for individual class and classes directory
pattern.exclude(loc_junit.toString(),loc_test.toString());
assertThat(pattern.match(String.class),is(false));
assertThat(pattern.match(Sun.class),is(false));
assertThat(pattern.match(Test.class),is(false));
assertThat(pattern.match(JDK.class),is(true));
assertThat(pattern.match(ClasspathPatternTest.class),is(false));
}
}

View File

@ -29,13 +29,13 @@ import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource;
@ -67,6 +67,8 @@ public class WebAppClassLoaderTest
_loader.addJars(webapp.addPath("WEB-INF/lib"));
_loader.addClassPath(webapp.addPath("WEB-INF/classes"));
_loader.setName("test");
_context.setServer(new Server());
}
public void assertCanLoadClass(String clazz) throws ClassNotFoundException
@ -286,7 +288,7 @@ public class WebAppClassLoaderTest
URL targetTestClasses = this.getClass().getClassLoader().getResource("org/acme/resource.txt");
_context.setParentLoaderPriority(false);
dump(_context);
resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
expected.clear();
@ -296,12 +298,6 @@ public class WebAppClassLoaderTest
assertThat("Resources Found (Parent Loader Priority == false)",resources,ordered(expected));
// dump(resources);
// assertEquals(3,resources.size());
// assertEquals(0,resources.get(0).toString().indexOf("jar:file:"));
// assertEquals(-1,resources.get(1).toString().indexOf("test-classes"));
// assertEquals(0,resources.get(2).toString().indexOf("file:"));
_context.setParentLoaderPriority(true);
// dump(_context);
resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
@ -356,49 +352,6 @@ public class WebAppClassLoaderTest
assertThat("Resources Found (Parent Loader Priority == true) (with systemClasses filtering)",resources,ordered(expected));
// dump(resources);
// assertEquals(1,resources.size());
// assertEquals(0,resources.get(0).toString().indexOf("file:"));
}
private void dump(WebAppContext wac)
{
System.err.println("--Dump WebAppContext - " + wac);
System.err.printf(" context.getClass().getClassLoader() = %s%n",wac.getClass().getClassLoader());
dumpClassLoaderHierarchy(" ",wac.getClass().getClassLoader());
System.err.printf(" context.getClassLoader() = %s%n",wac.getClassLoader());
dumpClassLoaderHierarchy(" ",wac.getClassLoader());
}
private void dumpClassLoaderHierarchy(String indent, ClassLoader classLoader)
{
if (classLoader != null)
{
if(classLoader instanceof URLClassLoader)
{
URLClassLoader urlCL = (URLClassLoader)classLoader;
URL urls[] = urlCL.getURLs();
for (URL url : urls)
{
System.err.printf("%s url[] = %s%n",indent,url);
}
}
ClassLoader parent = classLoader.getParent();
if (parent != null)
{
System.err.printf("%s .parent = %s%n",indent,parent);
dumpClassLoaderHierarchy(indent + " ",parent);
}
}
}
private void dump(List<URL> resources)
{
System.err.println("--Dump--");
for(URL url: resources)
{
System.err.printf(" \"%s\"%n",url);
}
}
}