Issue #963 Location based classpath pattern (#978)

Issue #963 location based white/black classpath lists
- removed outdated annotations/ClassNameResolver
- implemented loadedFrom in TypeUtil
- created a growable Trie
- reimplemented classpathpattern
- simplified OSGi classloading
This commit is contained in:
Greg Wilkins 2016-10-06 10:47:09 +11:00 committed by GitHub
parent 85f50da053
commit afb750515e
35 changed files with 1685 additions and 1005 deletions

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.annotations;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -48,6 +47,7 @@ import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.StringUtil; 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.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -81,8 +81,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>(); protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
protected List<ParserTask> _parserTasks; protected List<ParserTask> _parserTasks;
protected WebAppClassNameResolver _webAppClassNameResolver;
protected ContainerClassNameResolver _containerClassNameResolver;
protected CounterStatistic _containerPathStats; protected CounterStatistic _containerPathStats;
protected CounterStatistic _webInfLibStats; protected CounterStatistic _webInfLibStats;
@ -138,15 +136,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected Exception _exception; protected Exception _exception;
protected final AnnotationParser _parser; protected final AnnotationParser _parser;
protected final Set<? extends Handler> _handlers; protected final Set<? extends Handler> _handlers;
protected final ClassNameResolver _resolver;
protected final Resource _resource; protected final Resource _resource;
protected TimeStatistic _stat; 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; _parser = parser;
_handlers = handlers; _handlers = handlers;
_resolver = resolver;
_resource = resource; _resource = resource;
} }
@ -160,7 +156,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_stat != null) if (_stat != null)
_stat.start(); _stat.start();
if (_parser != null) if (_parser != null)
_parser.parse(_handlers, _resource, _resolver); _parser.parse(_handlers, _resource);
if (_stat != null) if (_stat != null)
_stat.end(); _stat.end();
return null; return null;
@ -174,83 +170,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getResource() public Resource getResource()
{ {
return _resource; return _resource;
} }
}
/**
* WebAppClassNameResolver
*
* Checks to see if a classname belongs to hidden or visible packages when scanning,
* and whether a classname that is a duplicate should override a previously
* scanned classname.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class WebAppClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public WebAppClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return true;
if (_context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class
//of same name - did it come from system or duplicate in webapp?
if (_context.isParentLoaderPriority())
return false;
return true;
}
}
/**
* ContainerClassNameResolver
*
* Checks to see if a classname belongs to a hidden or visible package
* when scanning for annotations and thus whether it should be excluded from
* consideration or not.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class ContainerClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public ContainerClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return false;
if (_context.isServerClass(name)) return true;
return false;
}
public boolean shouldOverride (String name)
{
//visiting the container classpath,
if (_context.isParentLoaderPriority())
return true;
return false;
}
} }
@ -390,8 +310,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override @Override
public void preConfigure(final WebAppContext context) throws Exception 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); String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN);
_sciExcludePattern = (tmp==null?null:Pattern.compile(tmp)); _sciExcludePattern = (tmp==null?null:Pattern.compile(tmp));
} }
@ -445,15 +363,15 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty()) if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
scanForAnnotations(context); scanForAnnotations(context);
// Resolve container initializers // Resolve container initializers
List<ContainerInitializer> initializers = List<ContainerInitializer> initializers =
(List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); (List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
if (initializers != null && initializers.size()>0) if (initializers != null && initializers.size()>0)
{ {
Map<String, Set<String>> map = ( Map<String, Set<String>>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP); Map<String, Set<String>> map = ( Map<String, Set<String>>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
for (ContainerInitializer i : initializers) for (ContainerInitializer i : initializers)
i.resolveClasses(context,map); i.resolveClasses(context,map);
} }
} }
@ -723,23 +641,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getJarFor (ServletContainerInitializer service) public Resource getJarFor (ServletContainerInitializer service)
throws MalformedURLException, IOException throws MalformedURLException, IOException
{ {
//try the thread context classloader to get the jar that loaded the class return TypeUtil.getLoadedFrom(service.getClass());
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);
} }
/** /**
@ -760,26 +662,41 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (context == null) if (context == null)
throw new IllegalArgumentException("WebAppContext 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 //A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering
//of WEB-INF/lib jars //of WEB-INF/lib jars
if (isFromContainerClassPath(context, sci)) if (isFromContainerClassPath(context, sci))
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} from container classpath", sci);
return false; return false;
}
//If no ordering, nothing is excluded //If no ordering, nothing is excluded
if (context.getMetaData().getOrdering() == null) if (context.getMetaData().getOrdering() == null)
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} no ordering", sci);
return false; return false;
}
List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars(); List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
//there is an ordering, but there are no jars resulting from the ordering, everything excluded //there is an ordering, but there are no jars resulting from the ordering, everything excluded
if (orderedJars.isEmpty()) if (orderedJars.isEmpty())
{
if (LOG.isDebugEnabled())
LOG.debug("Excluded {} empty ordering", sci);
return true; return true;
}
if (sciResource == null) 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(); URI loadingJarURI = sciResource.getURI();
boolean found = false; boolean found = false;
@ -790,10 +707,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
found = r.getURI().equals(loadingJarURI); found = r.getURI().equals(loadingJarURI);
} }
if (LOG.isDebugEnabled())
LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found);
return !found; return !found;
} }
/** /**
* Test if the ServletContainerIntializer is excluded by the * Test if the ServletContainerIntializer is excluded by the
* o.e.j.containerInitializerExclusionPattern * o.e.j.containerInitializerExclusionPattern
@ -808,7 +726,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
return false; return false;
//test if name of class matches the regex //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(); return _sciExcludePattern.matcher(sci.getClass().getName()).matches();
} }
@ -866,17 +785,20 @@ public class AnnotationConfiguration extends AbstractConfiguration
//because containerInitializerOrdering omits it //because containerInitializerOrdering omits it
for (ServletContainerInitializer sci:_loadedInitializers) for (ServletContainerInitializer sci:_loadedInitializers)
{ {
LOG.setDebugEnabled(true);
if (matchesExclusionPattern(sci)) if (matchesExclusionPattern(sci))
{ {
if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci); if (LOG.isDebugEnabled())
LOG.debug("{} excluded by pattern", sci);
continue; continue;
} }
Resource sciResource = getJarFor(sci); Resource sciResource = getJarFor(sci);
if (isFromExcludedJar(context, sci, sciResource)) 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; continue;
} }
@ -885,7 +807,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (initializerOrdering != null if (initializerOrdering != null
&& (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0)) && (!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; continue;
} }
@ -912,12 +835,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
//no web.xml ordering defined, add SCIs in any order //no web.xml ordering defined, add SCIs in any order
if (context.getMetaData().getOrdering() == null) 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()); nonExcludedInitializers.addAll(sciResourceMap.keySet());
} }
else 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()) for (Map.Entry<ServletContainerInitializer, Resource> entry:sciResourceMap.entrySet())
{ {
//add in SCIs from the container classpath //add in SCIs from the container classpath
@ -992,7 +917,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
//queue it up for scanning if using multithreaded mode //queue it up for scanning if using multithreaded mode
if (_parserTasks != null) if (_parserTasks != null)
{ {
ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver); ParserTask task = new ParserTask(parser, handlers, r);
_parserTasks.add(task); _parserTasks.add(task);
_containerPathStats.increment(); _containerPathStats.increment();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -1054,7 +979,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_parserTasks != null) if (_parserTasks != null)
{ {
ParserTask task = new ParserTask(parser, handlers,r, _webAppClassNameResolver); ParserTask task = new ParserTask(parser, handlers,r);
_parserTasks.add (task); _parserTasks.add (task);
_webInfLibStats.increment(); _webInfLibStats.increment();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -1087,7 +1012,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
{ {
if (_parserTasks != null) if (_parserTasks != null)
{ {
ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver); ParserTask task = new ParserTask(parser, handlers, dir);
_parserTasks.add(task); _parserTasks.add(task);
_webInfClassesStats.increment(); _webInfClassesStats.increment();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())

View File

@ -547,25 +547,22 @@ public class AnnotationParser
* @param resolver the class name resolver to use * @param resolver the class name resolver to use
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (className == null) if (className == null)
return; 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"; Resource r = Resource.newResource(resource);
URL resource = Loader.getResource(className); try (InputStream is = r.getInputStream())
if (resource!= null)
{ {
Resource r = Resource.newResource(resource); scanClass(handlers, null, is);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
} }
} }
} }
@ -582,29 +579,27 @@ public class AnnotationParser
* @param visitSuperClasses if true, also visit super classes for parse * @param visitSuperClasses if true, also visit super classes for parse
* @throws Exception if unable to parse class * @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 throws Exception
{ {
Class<?> cz = clazz; Class<?> cz = clazz;
while (cz != null) 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"; Resource r = Resource.newResource(resource);
URL resource = Loader.getResource(nameAsResource); try (InputStream is = r.getInputStream())
if (resource!= null)
{ {
Resource r = Resource.newResource(resource); scanClass(handlers, null, is);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
} }
} }
} }
if (visitSuperClasses) if (visitSuperClasses)
cz = cz.getSuperclass(); cz = cz.getSuperclass();
else else
@ -622,13 +617,13 @@ public class AnnotationParser
* @param resolver the class name resolver * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (classNames == null) if (classNames == null)
return; 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 * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
MultiException me = new MultiException(); MultiException me = new MultiException();
@ -649,7 +644,7 @@ public class AnnotationParser
{ {
try try
{ {
if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s)))) if (!isParsed(s))
{ {
s = s.replace('.', '/')+".class"; s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(s); URL resource = Loader.getResource(s);
@ -680,7 +675,7 @@ public class AnnotationParser
* @param resolver the class name resolver * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
// skip dirs whose name start with . (ie hidden) // skip dirs whose name start with . (ie hidden)
@ -696,7 +691,7 @@ public class AnnotationParser
{ {
Resource res = dir.addPath(files[f]); Resource res = dir.addPath(files[f]);
if (res.isDirectory()) if (res.isDirectory())
parseDir(handlers, res, resolver); parseDir(handlers, res);
else else
{ {
//we've already verified the directories, so just verify the class file name //we've already verified the directories, so just verify the class file name
@ -706,7 +701,7 @@ public class AnnotationParser
try try
{ {
String name = res.getName(); String name = res.getName();
if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name)))) if (!isParsed(name))
{ {
Resource r = Resource.newResource(res.getURL()); Resource r = Resource.newResource(res.getURL());
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);}; if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);};
@ -744,7 +739,7 @@ public class AnnotationParser
* @param resolver the class name resolver * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (loader==null) if (loader==null)
@ -762,7 +757,7 @@ public class AnnotationParser
{ {
try try
{ {
parseJarEntry(handlers, Resource.newResource(jarUri), entry, resolver); parseJarEntry(handlers, Resource.newResource(jarUri), entry);
} }
catch (Exception e) catch (Exception e)
{ {
@ -785,7 +780,7 @@ public class AnnotationParser
* @param resolver the class name resolver * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (uris==null) if (uris==null)
@ -797,7 +792,7 @@ public class AnnotationParser
{ {
try try
{ {
parse(handlers, uri, resolver); parse(handlers, uri);
} }
catch (Exception e) catch (Exception e)
{ {
@ -815,13 +810,13 @@ public class AnnotationParser
* @param resolver the class name resolver * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (uri == null) if (uri == null)
return; 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 * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (r == null) if (r == null)
@ -841,14 +836,14 @@ public class AnnotationParser
if (r.exists() && r.isDirectory()) if (r.exists() && r.isDirectory())
{ {
parseDir(handlers, r, resolver); parseDir(handlers, r);
return; return;
} }
String fullname = r.toString(); String fullname = r.toString();
if (fullname.endsWith(".jar")) if (fullname.endsWith(".jar"))
{ {
parseJar(handlers, r, resolver); parseJar(handlers, r);
return; return;
} }
@ -875,7 +870,7 @@ public class AnnotationParser
* @param resolver the class name resolver * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (jarResource == null) if (jarResource == null)
@ -899,7 +894,7 @@ public class AnnotationParser
{ {
try try
{ {
parseJarEntry(handlers, jarResource, entry, resolver); parseJarEntry(handlers, jarResource, entry);
} }
catch (Exception e) catch (Exception e)
{ {
@ -930,7 +925,7 @@ public class AnnotationParser
* @param resolver the class name resolver * @param resolver the class name resolver
* @throws Exception if unable to parse * @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 throws Exception
{ {
if (jar == null || entry == null) if (jar == null || entry == null)
@ -947,9 +942,7 @@ public class AnnotationParser
{ {
String shortName = name.replace('/', '.').substring(0,name.length()-6); String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null) if (!isParsed(shortName))
||
(!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
{ {
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name); Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);}; 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; return;
annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName()); annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName());
} }
@Override
public String toString()
{
return annotatedClassNames.toString()+annotatedMethods+annotatedFields;
}
} }
@After @After
@ -93,18 +99,7 @@ public class TestAnnotationInheritance
SampleHandler handler = new SampleHandler(); SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser(); AnnotationParser parser = new AnnotationParser();
parser.parse(Collections.singleton(handler), classNames, new ClassNameResolver () parser.parse(Collections.singleton(handler), classNames);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
//check we got 2 class annotations //check we got 2 class annotations
assertEquals(2, handler.annotatedClassNames.size()); assertEquals(2, handler.annotatedClassNames.size());
@ -129,18 +124,7 @@ public class TestAnnotationInheritance
{ {
SampleHandler handler = new SampleHandler(); SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser(); AnnotationParser parser = new AnnotationParser();
parser.parse(Collections.singleton(handler), ClassB.class, new ClassNameResolver () parser.parse(Collections.singleton(handler), ClassB.class, true);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
}, true);
//check we got 2 class annotations //check we got 2 class annotations
assertEquals(2, handler.annotatedClassNames.size()); assertEquals(2, handler.annotatedClassNames.size());
@ -160,46 +144,6 @@ public class TestAnnotationInheritance
assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); 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 @Test
public void testTypeInheritanceHandling() throws Exception public void testTypeInheritanceHandling() throws Exception
{ {
@ -218,7 +162,7 @@ public class TestAnnotationInheritance
classNames.add(InterfaceD.class.getName()); classNames.add(InterfaceD.class.getName());
classNames.add(Foo.class.getName()); classNames.add(Foo.class.getName());
parser.parse(Collections.singleton(handler), classNames, null); parser.parse(Collections.singleton(handler), classNames);
assertNotNull(map); assertNotNull(map);
assertFalse(map.isEmpty()); assertFalse(map.isEmpty());

View File

@ -111,19 +111,7 @@ public class TestAnnotationParser
} }
//long start = System.currentTimeMillis(); //long start = System.currentTimeMillis();
parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver() parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
//long end = System.currentTimeMillis(); //long end = System.currentTimeMillis();
//System.err.println("Time to parse class: " + ((end - start))); //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 @Test
@ -171,7 +159,7 @@ public class TestAnnotationParser
File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar"); File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar");
AnnotationParser parser = new AnnotationParser(); AnnotationParser parser = new AnnotationParser();
Set<Handler> emptySet = Collections.emptySet(); 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 // 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(); AnnotationParser parser = new AnnotationParser();
// Parse // Parse
parser.parse(Collections.singleton(tracker), basedir.toURI(),null); parser.parse(Collections.singleton(tracker), basedir.toURI());
// Validate // Validate
Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName())); 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); TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results);
parser.parse(Collections.singleton(handler), classes, new ClassNameResolver () parser.parse(Collections.singleton(handler), classes);
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
assertEquals(1, results.size()); assertEquals(1, results.size());

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 session-store
[depends] [depends]
gcloud-datastore
annotations annotations
webapp webapp
sessions sessions
jcl-api
jcl-impl
[files] [files]
basehome:etc/sessions/gcloud/index.yaml|etc/index.yaml basehome:modules/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
[lib] [lib]
lib/jetty-gcloud-session-manager-${jetty.version}.jar lib/jetty-gcloud-session-manager-${jetty.version}.jar
lib/gcloud/*.jar
[xml] [xml]
etc/sessions/gcloud/session-store.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] [ini-template]
## GCloudDatastore Session config ## GCloudDatastore Session config

View File

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

View File

@ -18,11 +18,14 @@
package org.eclipse.jetty.osgi.annotations; package org.eclipse.jetty.osgi.annotations;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import org.eclipse.jetty.annotations.AnnotationParser.Handler; 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.OSGiWebInfConfiguration;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.util.log.Log; 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 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 public Void call() throws Exception
@ -57,7 +60,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
Bundle bundle = osgiAnnotationParser.getBundle(_resource); Bundle bundle = osgiAnnotationParser.getBundle(_resource);
if (_stat != null) if (_stat != null)
_stat.start(); _stat.start();
osgiAnnotationParser.parse(_handlers, bundle, _resolver); osgiAnnotationParser.parse(_handlers, bundle);
if (_stat != null) if (_stat != null)
_stat.end(); _stat.end();
} }
@ -79,6 +82,17 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
return new AnnotationParser(); 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. * Here is the order in which jars and osgi artifacts are scanned for discoverable annotations.
* <ol> * <ol>
@ -195,47 +209,13 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
handlers.add(_classInheritanceHandler); handlers.add(_classInheritanceHandler);
handlers.addAll(_containerInitializerAnnotationHandlers); handlers.addAll(_containerInitializerAnnotationHandlers);
ClassNameResolver classNameResolver = createClassNameResolver(context);
if (_parserTasks != null) if (_parserTasks != null)
{ {
BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes, classNameResolver); BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes);
_parserTasks.add(task); _parserTasks.add(task);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
task.setStatistic(new TimeStatistic()); 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.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -85,7 +84,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
* *
*/ */
@Override @Override
public void parse (Set<? extends Handler> handlers, URI[] uris, ClassNameResolver resolver) public void parse (Set<? extends Handler> handlers, URI[] uris)
throws Exception throws Exception
{ {
for (URI uri : uris) 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 //a jar in WEB-INF/lib or the WEB-INF/classes
//use the behavior of the super class for a standard jar. //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 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 throws Exception
{ {
URI uri = _bundleToUri.get(bundle); 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 //transform into a classname to pass to the resolver
String shortName = name.replace('/', '.').substring(0,name.length()-6); 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()) 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); private static final Logger LOG = Log.getLogger(AbstractOSGiApp.class);
protected Bundle _bundle; protected Bundle _bundle;
protected Dictionary _properties; protected Dictionary<?,?> _properties;
protected ServiceRegistration _registration; protected ServiceRegistration _registration;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId) public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
{ {
super(manager, provider, originId); this (manager, provider, bundle, bundle.getHeaders(), originId);
_properties = bundle.getHeaders();
_bundle = bundle;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
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); super(manager, provider, originId);
_properties = properties; _properties = properties;

View File

@ -38,6 +38,7 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource; import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration; import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle; import org.osgi.framework.Bundle;
@ -436,18 +437,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 // Apply it just as the standard jetty ContextProvider would do
LOG.info("Applying " + contextXmlUrl + " to " + _webApp); LOG.info("Applying " + contextXmlUrl + " to " + _webApp);
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl); XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
HashMap properties = new HashMap(); WebAppClassLoader.runWithServerClassAccess(()->
properties.put("Server", getDeploymentManager().getServer()); {
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); HashMap<String,String> properties = new HashMap<>();
properties.put(OSGiServerConstants.JETTY_HOME, getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME)); xmlConfiguration.getIdMap().put("Server",getDeploymentManager().getServer());
xmlConfiguration.getProperties().putAll(properties); properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
xmlConfiguration.configure(_webApp); properties.put(OSGiServerConstants.JETTY_HOME, (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(_webApp);
return null;
});
} }
finally finally
{ {

View File

@ -175,7 +175,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
String contextPath = null; String contextPath = null;
try try
{ {
Dictionary headers = bundle.getHeaders(); Dictionary<String,String> headers = bundle.getHeaders();
//does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH //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); 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 //Could be a static webapp with no web.xml
String base = "."; String base = ".";
contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); contextPath = headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
String originId = getOriginId(bundle,base); String originId = getOriginId(bundle,base);
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); 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 Bundle _contributor;
private boolean _lookInOsgiFirst = true;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* @param parent The parent classloader. * @param parent The parent classloader.
@ -96,11 +94,26 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
} }
/* ------------------------------------------------------------ */
@Override @Override
public Class<?> loadClass(String name) throws ClassNotFoundException 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> osgiUrls = _osgiBundleClassLoader.getResources(name);
Enumeration<URL> urls = super.getResources(name); Enumeration<URL> urls = super.getResources(name);
if (_lookInOsgiFirst) List<URL> resources = toList(osgiUrls, urls);
{ return Collections.enumeration(resources);
return Collections.enumeration(toList(osgiUrls, urls));
}
else
{
return Collections.enumeration(toList(urls, osgiUrls));
}
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Override
public URL getResource(String name) public URL getResource(String name)
{ {
if (_lookInOsgiFirst) URL url = _osgiBundleClassLoader.getResource(name);
{ return url != null ? url : super.getResource(name);
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);
}
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2) 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()) while (e2 != null && e2.hasMoreElements())
list.add(e2.nextElement()); list.add(e2.nextElement());
return list; 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

@ -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 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); LOG.debug("{} excluded by method {}",this,request);
_handler.handle(target,baseRequest, request, response); _handler.handle(target,baseRequest, request, response);
@ -173,7 +173,7 @@ public class BufferedResponseHandler extends HandlerWrapper
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
protected boolean isMimeTypeBufferable(String mimetype) 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) if (requestURI == null)
return true; 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 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); LOG.debug("{} excluded by method {}",this,request);
_handler.handle(target,baseRequest, request, response); _handler.handle(target,baseRequest, request, response);
@ -549,14 +549,14 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (ua == null) if (ua == null)
return false; return false;
return _agentPatterns.matches(ua); return _agentPatterns.test(ua);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Override
public boolean isMimeTypeGzipable(String mimetype) 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) if (requestURI == null)
return true; return true;
return _paths.matches(requestURI); return _paths.test(requestURI);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -19,8 +19,10 @@
package org.eclipse.jetty.util; package org.eclipse.jetty.util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.AbstractMap;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
@ -495,6 +497,39 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
return keys; 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 @Override
public boolean isFull() 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. /** 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 * 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) * 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 * <p>The type of the underlying {@link Set} used may be passed into the
* constructor, so special sets like Servlet PathMap may be used. * constructor, so special sets like Servlet PathMap may be used.
* <p> * <p>
* @param <P> The type of element of the set (often a pattern) * @param <T> The type of element of the set (often a pattern)
* @param <T> The type of the instance passed to the predicate * @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 Set<T> _includes;
private final Predicate<T> _includePredicate; private final Predicate<P> _includePredicate;
private final Set<P> _excludes; private final Set<T> _excludes;
private final Predicate<T> _excludePredicate; private final Predicate<P> _excludePredicate;
private static class SetContainsPredicate<T> implements Predicate<T> private static class SetContainsPredicate<T> implements Predicate<T>
{ {
@ -73,7 +73,7 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
* is created. * is created.
* @param <SET> The type of a set to use as the backing store * @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 try
{ {
@ -82,7 +82,7 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
if(_includes instanceof Predicate) if(_includes instanceof Predicate)
{ {
_includePredicate = (Predicate<T>)_includes; _includePredicate = (Predicate<P>)_includes;
} }
else else
{ {
@ -91,7 +91,7 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
if(_excludes instanceof Predicate) if(_excludes instanceof Predicate)
{ {
_excludePredicate = (Predicate<T>)_excludes; _excludePredicate = (Predicate<P>)_excludes;
} }
else 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 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 * @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(includeSet,"Include Set");
Objects.requireNonNull(includePredicate,"Include Predicate"); Objects.requireNonNull(includePredicate,"Include Predicate");
@ -126,51 +126,73 @@ public class IncludeExcludeSet<P,T> implements Predicate<T>
_excludePredicate = excludePredicate; _excludePredicate = excludePredicate;
} }
public void include(P element) public void include(T element)
{ {
_includes.add(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); _includes.add(e);
} }
public void exclude(P element) public void exclude(T element)
{ {
_excludes.add(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); _excludes.add(e);
} }
public boolean matches(T t) @Deprecated
public boolean matches(P t)
{ {
return test(t); return test(t);
} }
public boolean test(T t) @Override
public boolean test(P t)
{ {
if (!_includes.isEmpty() && !_includePredicate.test(t)) if (!_includes.isEmpty() && !_includePredicate.test(t))
return false; return false;
return !_excludePredicate.test(t); 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() public int size()
{ {
return _includes.size()+_excludes.size(); return _includes.size()+_excludes.size();
} }
public Set<P> getIncluded() public Set<T> getIncluded()
{ {
return _includes; return _includes;
} }
public Set<P> getExcluded() public Set<T> getExcluded()
{ {
return _excludes; return _excludes;
} }

View File

@ -29,7 +29,7 @@ import java.util.Set;
public interface Trie<V> public interface Trie<V>
{ {
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Put and entry into the Trie /** Put an entry into the Trie
* @param s The key for the entry * @param s The key for the entry
* @param v The value of the entry * @param v The value of the entry
* @return True if the Trie had capacity to add the field. * @return True if the Trie had capacity to add the field.
@ -47,14 +47,14 @@ public interface Trie<V>
public V remove(String s); 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 * @param s The key
* @return the value for the string key * @return the value for the string key
*/ */
public V get(String s); 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 s The key
* @param offset The offset within the string of the key * @param offset The offset within the string of the key
* @param len the length 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); 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 * @param b The buffer
* @return The value or null if not found * @return The value or null if not found
*/ */
public V get(ByteBuffer b); 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 b The buffer
* @param offset The offset within the buffer of the key * @param offset The offset within the buffer of the key
* @param len the length 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.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -31,9 +34,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.servlet.ServletContainerInitializer;
import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; 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 !((Boolean)o).booleanValue();
return "false".equalsIgnoreCase(o.toString()); 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; package org.eclipse.jetty.util;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
@ -843,4 +844,30 @@ public class URIUtil
return URI.create(buf.toString()); 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<>(); IncludeExclude<String> ie = new IncludeExclude<>();
assertThat("Empty IncludeExclude", ie.size(), is(0)); assertThat("Empty IncludeExclude", ie.size(), is(0));
assertThat("Matches 'foo'",ie.matches("foo"),is(true)); assertThat("Matches 'foo'",ie.test("foo"),is(true));
} }
@Test @Test
@ -43,10 +43,10 @@ public class IncludeExcludeTest
ie.include("bar"); ie.include("bar");
assertThat("IncludeExclude.size", ie.size(), is(2)); assertThat("IncludeExclude.size", ie.size(), is(2));
assertEquals(false,ie.matches("")); assertEquals(false,ie.test(""));
assertEquals(true,ie.matches("foo")); assertEquals(true,ie.test("foo"));
assertEquals(true,ie.matches("bar")); assertEquals(true,ie.test("bar"));
assertEquals(false,ie.matches("foobar")); assertEquals(false,ie.test("foobar"));
} }
@Test @Test
@ -58,11 +58,11 @@ public class IncludeExcludeTest
assertEquals(2,ie.size()); assertEquals(2,ie.size());
assertEquals(false,ie.matches("foo")); assertEquals(false,ie.test("foo"));
assertEquals(false,ie.matches("bar")); assertEquals(false,ie.test("bar"));
assertEquals(true,ie.matches("")); assertEquals(true,ie.test(""));
assertEquals(true,ie.matches("foobar")); assertEquals(true,ie.test("foobar"));
assertEquals(true,ie.matches("wibble")); assertEquals(true,ie.test("wibble"));
} }
@Test @Test
@ -76,11 +76,11 @@ public class IncludeExcludeTest
assertEquals(4,ie.size()); assertEquals(4,ie.size());
assertEquals(true,ie.matches("foo")); assertEquals(true,ie.test("foo"));
assertEquals(false,ie.matches("bar")); assertEquals(false,ie.test("bar"));
assertEquals(false,ie.matches("")); assertEquals(false,ie.test(""));
assertEquals(false,ie.matches("foobar")); assertEquals(false,ie.test("foobar"));
assertEquals(false,ie.matches("xxx")); assertEquals(false,ie.test("xxx"));
} }
@ -91,7 +91,7 @@ public class IncludeExcludeTest
IncludeExclude<String> ie = new IncludeExclude<>(RegexSet.class); IncludeExclude<String> ie = new IncludeExclude<>(RegexSet.class);
assertEquals(0,ie.size()); assertEquals(0,ie.size());
assertEquals(true,ie.matches("foo")); assertEquals(true,ie.test("foo"));
} }
@Test @Test
@ -102,13 +102,13 @@ public class IncludeExcludeTest
ie.include("b((ar)|(oo))"); ie.include("b((ar)|(oo))");
assertEquals(2,ie.size()); assertEquals(2,ie.size());
assertEquals(false,ie.matches("")); assertEquals(false,ie.test(""));
assertEquals(true,ie.matches("foo")); assertEquals(true,ie.test("foo"));
assertEquals(true,ie.matches("far")); assertEquals(true,ie.test("far"));
assertEquals(true,ie.matches("bar")); assertEquals(true,ie.test("bar"));
assertEquals(true,ie.matches("boo")); assertEquals(true,ie.test("boo"));
assertEquals(false,ie.matches("foobar")); assertEquals(false,ie.test("foobar"));
assertEquals(false,ie.matches("xxx")); assertEquals(false,ie.test("xxx"));
} }
@Test @Test
@ -120,13 +120,13 @@ public class IncludeExcludeTest
assertEquals(2,ie.size()); assertEquals(2,ie.size());
assertEquals(false,ie.matches("foo")); assertEquals(false,ie.test("foo"));
assertEquals(false,ie.matches("far")); assertEquals(false,ie.test("far"));
assertEquals(false,ie.matches("bar")); assertEquals(false,ie.test("bar"));
assertEquals(false,ie.matches("boo")); assertEquals(false,ie.test("boo"));
assertEquals(true,ie.matches("")); assertEquals(true,ie.test(""));
assertEquals(true,ie.matches("foobar")); assertEquals(true,ie.test("foobar"));
assertEquals(true,ie.matches("xxx")); assertEquals(true,ie.test("xxx"));
} }
@Test @Test
@ -139,14 +139,14 @@ public class IncludeExcludeTest
ie.exclude("b((ar)|(oo))"); ie.exclude("b((ar)|(oo))");
assertEquals(4,ie.size()); assertEquals(4,ie.size());
assertEquals(false,ie.matches("foo")); assertEquals(false,ie.test("foo"));
assertEquals(false,ie.matches("far")); assertEquals(false,ie.test("far"));
assertEquals(false,ie.matches("bar")); assertEquals(false,ie.test("bar"));
assertEquals(false,ie.matches("boo")); assertEquals(false,ie.test("boo"));
assertEquals(false,ie.matches("")); assertEquals(false,ie.test(""));
assertEquals(false,ie.matches("xxx")); assertEquals(false,ie.test("xxx"));
assertEquals(true,ie.matches("foobar")); assertEquals(true,ie.test("foobar"));
assertEquals(true,ie.matches("Ant")); assertEquals(true,ie.test("Ant"));
} }
} }

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.util; package org.eclipse.jetty.util;
import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -119,4 +120,12 @@ public class TypeUtilTest
Assert.assertFalse(TypeUtil.isFalse("blargle")); Assert.assertFalse(TypeUtil.isFalse("blargle"));
Assert.assertFalse(TypeUtil.isFalse(new Object(){@Override public String toString(){return "true";}})); 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; package org.eclipse.jetty.util;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test; 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 servlet
security security
[xml]
etc/jetty-webapp.xml
[lib] [lib]
lib/jetty-webapp-${jetty.version}.jar 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,13 +19,30 @@
package org.eclipse.jetty.webapp; package org.eclipse.jetty.webapp;
import java.util.AbstractList; 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.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import org.eclipse.jetty.util.StringUtil; 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;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
@ -45,21 +62,59 @@ import org.eclipse.jetty.util.StringUtil;
* in this string should be separated by ':' (semicolon) or ',' (comma). * in this string should be separated by ':' (semicolon) or ',' (comma).
*/ */
public class ClasspathPattern extends AbstractList<String> public class ClasspathPattern extends AbstractSet<String>
{ {
private static final Logger LOG = Log.getLogger(ClasspathPattern.class);
enum Type { PACKAGE, CLASSNAME, LOCATION }
private static class Entry private static class Entry
{ {
public final String _pattern; private final String _pattern;
public final String _name; private final String _name;
public final boolean _inclusive; private final boolean _inclusive;
public final boolean _package; private final Type _type;
Entry(String pattern) Entry(String pattern)
{ {
_pattern=pattern; _pattern=pattern;
_inclusive = !pattern.startsWith("-"); _inclusive = !pattern.startsWith("-");
_package = pattern.endsWith(".");
_name = _inclusive ? pattern : pattern.substring(1).trim(); _name = _inclusive ? pattern : pattern.substring(1).trim();
_type = (_name.startsWith("file:"))?Type.LOCATION:(_name.endsWith(".")?Type.PACKAGE:Type.CLASSNAME);
}
Entry(String name, boolean include)
{
_pattern=include?name:("-"+name);
_inclusive = include;
_name = name;
_type = (_name.startsWith("file:"))?Type.LOCATION:(_name.endsWith(".")?Type.PACKAGE:Type.CLASSNAME);
}
public String getPattern()
{
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 @Override
@ -67,86 +122,356 @@ public class ClasspathPattern extends AbstractList<String>
{ {
return _pattern; 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()
{ {
} }
/* ------------------------------------------------------------ */
public ClasspathPattern(String[] patterns) public ClasspathPattern(String[] patterns)
{ {
setAll(patterns); setAll(patterns);
} }
/* ------------------------------------------------------------ */
public ClasspathPattern(String pattern) public ClasspathPattern(String pattern)
{ {
add(pattern); add(pattern);
} }
/* ------------------------------------------------------------ */ public boolean include(String name)
@Override
public String get(int index)
{ {
return _entries.get(index)._pattern; if (name==null)
} return false;
return add(new Entry(name,true));
/* ------------------------------------------------------------ */
@Override
public String set(int index, String element)
{
Entry e = _entries.set(index,new Entry(element));
return e==null?null:e._pattern;
}
/* ------------------------------------------------------------ */
@Override
public void add(int index, String element)
{
_entries.add(index,new Entry(element));
}
/* ------------------------------------------------------------ */
@Deprecated
public void addPattern(String element)
{
add(element);
} }
/* ------------------------------------------------------------ */ public boolean include(String... name)
@Override
public String remove(int index)
{ {
Entry e = _entries.remove(index); boolean added = false;
return e==null?null:e._pattern; for (String n:name)
if (n!=null)
added = add(new Entry(n,true)) || added;
return added;
} }
/* ------------------------------------------------------------ */ public boolean exclude(String name)
public boolean remove(String pattern)
{ {
for (int i=_entries.size();i-->0;) 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())
{ {
if (pattern.equals(_entries.get(i)._pattern)) try
{ {
_entries.remove(i); File file = Resource.newResource(entry.getName()).getFile().getAbsoluteFile().getCanonicalFile();
return true; if (entry.isInclusive())
_locations.include(file);
else
_locations.exclude(file);
}
catch (Exception e)
{
throw new IllegalArgumentException(e);
} }
} }
return false; 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();
}
@Override
public Iterator<String> iterator()
{
return _entries.keySet().iterator();
} }
/* ------------------------------------------------------------ */
@Override @Override
public int size() public int size()
{ {
return _entries.size(); return _entries.size();
} }
/* ------------------------------------------------------------ */
/** /**
* Initialize the matcher by parsing each classpath pattern in an array * Initialize the matcher by parsing each classpath pattern in an array
* *
@ -158,7 +483,6 @@ public class ClasspathPattern extends AbstractList<String>
addAll(classes); addAll(classes);
} }
/* ------------------------------------------------------------ */
/** /**
* @param classes array of classpath patterns * @param classes array of classpath patterns
*/ */
@ -168,30 +492,6 @@ public class ClasspathPattern extends AbstractList<String>
addAll(Arrays.asList(classes)); addAll(Arrays.asList(classes));
} }
/* ------------------------------------------------------------ */
/**
* @param classes array of classpath patterns
*/
public void prepend(String[] classes)
{
if (classes != null)
{
int i=0;
for (String c : classes)
{
add(i,c);
i++;
}
}
}
/* ------------------------------------------------------------ */
public void prependPattern(String pattern)
{
add(0,pattern);
}
/* ------------------------------------------------------------ */
/** /**
* @return array of classpath patterns * @return array of classpath patterns
*/ */
@ -200,22 +500,7 @@ public class ClasspathPattern extends AbstractList<String>
return toArray(new String[_entries.size()]); return toArray(new String[_entries.size()]);
} }
/* ------------------------------------------------------------ */
/**
* @return List of classes excluded class exclusions and package patterns
*/
public List<String> getClasses()
{
List<String> list = new ArrayList<>();
for (Entry e:_entries)
{
if (e._inclusive && !e._package)
list.add(e._name);
}
return list;
}
/* ------------------------------------------------------------ */
/** /**
* Match the class name against the pattern * Match the class name against the pattern
* *
@ -224,65 +509,66 @@ public class ClasspathPattern extends AbstractList<String>
*/ */
public boolean match(String name) public boolean match(String name)
{ {
name = name.replace('/','.'); return _patterns.test(name);
}
for (Entry entry : _entries)
/**
* 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) Resource resource = TypeUtil.getLoadedFrom(clazz);
continue; Path path = resource.getFile().toPath();
if (entry._package)
{ Boolean byName = _patterns.isIncludedAndNotExcluded(clazz.getName());
if (name.startsWith(entry._name) || ".".equals(entry._pattern)) Boolean byLocation = _locations.isIncludedAndNotExcluded(path);
return entry._inclusive;
} // Combine the tri-state match of both IncludeExclude Sets
else boolean included = byName==TRUE || byLocation==TRUE
{ || (byName==null && !_patterns.hasIncludes() && byLocation==null && !_locations.hasIncludes());
if (name.equals(entry._name)) boolean excluded = byName==FALSE || byLocation==FALSE;
return entry._inclusive; return included && !excluded;
}
if (name.length()>entry._name.length() && '$'==name.charAt(entry._name.length()) && name.startsWith(entry._name)) catch (Exception e)
return entry._inclusive; {
} LOG.warn(e);
} }
return false; return false;
} }
public void addAfter(String afterPattern,String... patterns) public boolean match(String name, URL url)
{ {
if (patterns!=null && afterPattern!=null) // Strip class suffix for name matching
{ if (name.endsWith(".class"))
ListIterator<String> iter = listIterator(); name=name.substring(0,name.length()-6);
while (iter.hasNext())
{ // Treat path elements as packages for name matching
String cc=iter.next(); name=name.replace("/",".");
if (afterPattern.equals(cc))
{
for (int i=0;i<patterns.length;i++)
iter.add(patterns[i]);
return;
}
}
}
throw new IllegalArgumentException("after '"+afterPattern+"' not found in "+this);
}
public void addBefore(String beforePattern,String... patterns) Boolean byName = _patterns.isIncludedAndNotExcluded(name);
{
if (patterns!=null && beforePattern!=null) // Try to find a file path for location matching
Boolean byLocation = null;
try
{ {
ListIterator<String> iter = listIterator(); Resource resource = Resource.newResource(URIUtil.getJarSource(url.toURI()));
while (iter.hasNext()) File file = resource.getFile();
{ byLocation = _locations.isIncludedAndNotExcluded(file.toPath());
String cc=iter.next();
if (beforePattern.equals(cc))
{
iter.previous();
for (int i=0;i<patterns.length;i++)
iter.add(patterns[i]);
return;
}
}
} }
throw new IllegalArgumentException("before '"+beforePattern+"' not found in "+this); 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

@ -36,7 +36,6 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
@ -102,7 +101,7 @@ public class WebAppClassLoader extends URLClassLoader
* @return Returns the permissions. * @return Returns the permissions.
*/ */
PermissionCollection getPermissions(); PermissionCollection getPermissions();
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Is the class a System Class. /** Is the class a System Class.
* A System class is a class that is visible to a webapplication, * A System class is a class that is visible to a webapplication,
@ -111,7 +110,7 @@ public class WebAppClassLoader extends URLClassLoader
* @param clazz The fully qualified name of the class. * @param clazz The fully qualified name of the class.
* @return True if the class is a system class. * @return True if the class is a system class.
*/ */
boolean isSystemClass(String clazz); boolean isSystemClass(Class<?> clazz);
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Is the class a Server Class. /** Is the class a Server Class.
@ -122,7 +121,7 @@ public class WebAppClassLoader extends URLClassLoader
* @param clazz The fully qualified name of the class. * @param clazz The fully qualified name of the class.
* @return True if the class is a server class. * @return True if the class is a server class.
*/ */
boolean isServerClass(String clazz); boolean isServerClass(Class<?> clazz);
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
@ -135,6 +134,10 @@ public class WebAppClassLoader extends URLClassLoader
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
String getExtraClasspath(); String getExtraClasspath();
boolean isServerResource(String name, URL parent_url);
boolean isSystemResource(String name, URL webapp_url);
} }
@ -142,9 +145,10 @@ public class WebAppClassLoader extends URLClassLoader
/** Run an action with access to ServerClasses /** Run an action with access to ServerClasses
* <p>Run the passed {@link PrivilegedExceptionAction} with the classloader * <p>Run the passed {@link PrivilegedExceptionAction} with the classloader
* configured so as to allow server classes to be visible</p> * 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 * @param action The action to run
* @return The return from the action * @return The return from the action
* @throws Exception * @throws Exception if thrown by the action
*/ */
public static <T> T runWithServerClassAccess(PrivilegedExceptionAction<T> action) throws Exception public static <T> T runWithServerClassAccess(PrivilegedExceptionAction<T> action) throws Exception
{ {
@ -361,27 +365,42 @@ public class WebAppClassLoader extends URLClassLoader
@Override @Override
public Enumeration<URL> getResources(String name) throws IOException public Enumeration<URL> getResources(String name) throws IOException
{ {
boolean system_class=_context.isSystemClass(name); List<URL> from_parent = new ArrayList<>();
boolean server_class=_context.isServerClass(name) && !Boolean.TRUE.equals(__loadServerClasses.get()); 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()) if (_context.isParentLoaderPriority())
{ {
from_parent.addAll(from_webapp); from_parent.addAll(from_webapp);
return Collections.enumeration(from_parent); resources = from_parent;
} }
from_webapp.addAll(from_parent); else
return Collections.enumeration(from_webapp); {
} from_webapp.addAll(from_parent);
resources = from_webapp;
}
if (LOG.isDebugEnabled())
LOG.debug("getResources {} {}",name,resources);
/* ------------------------------------------------------------ */ return Collections.enumeration(resources);
private List<URL> toList(Enumeration<URL> e)
{
if (e==null)
return new ArrayList<URL>();
return Collections.list(e);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -395,138 +414,180 @@ public class WebAppClassLoader extends URLClassLoader
@Override @Override
public URL getResource(String name) public URL getResource(String name)
{ {
URL url= null; URL resource=null;
boolean tried_parent= false; if (_context.isParentLoaderPriority())
//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)
{ {
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 webapp_url = this.findResource(name);
url=_parent.getResource(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;
} }
} }
else
if (url == null)
{ {
url= this.findResource(name); URL webapp_url = this.findResource(name);
source=this;
if (url == null && name.startsWith("/"))
url= this.findResource(name.substring(1));
}
if (url == null && !tried_parent && !server_class ) if (webapp_url!=null && !_context.isSystemResource(name,webapp_url))
{ resource = webapp_url;
if (_parent!=null) else
{ {
tried_parent=true;
source=_parent; // Couldn't find or see a webapp resource, so try a parent
url= _parent.getResource(name); 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()) if (LOG.isDebugEnabled())
LOG.debug("gotResource({})=={} from={} tried_parent={}",name,url,source,tried_parent); LOG.debug("getResource {} {}",name,resource);
return url; return resource;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{ {
LOG.setDebugEnabled(true);
WebAppContext.LOG.setDebugEnabled(true);
synchronized (getClassLoadingLock(name)) synchronized (getClassLoadingLock(name))
{ {
Class<?> c= findLoadedClass(name);
ClassNotFoundException ex= null; ClassNotFoundException ex= null;
boolean tried_parent= false; Class<?> parent_class = null;
Class<?> webapp_class = null;
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);
ClassLoader source=null; // Has this loader loaded the class already?
webapp_class = findLoadedClass(name);
if (system_class && server_class) if (webapp_class != null)
{
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)
{ {
if (LOG.isDebugEnabled()) 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; throw ex;
} }
else
if (LOG.isDebugEnabled())
LOG.debug("loadedClass({})=={} from={} tried_parent={}",name,c,source,tried_parent);
if (resolve)
{ {
resolveClass(c); // Not parent loader priority, so...
if (LOG.isDebugEnabled())
LOG.debug("resolved({})=={} from={} tried_parent={}",name,c,source,tried_parent);
}
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 +625,71 @@ public class WebAppClassLoader extends URLClassLoader
{ {
return _transformers.remove(transformer); return _transformers.remove(transformer);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Override
protected Class<?> findClass(final String name) throws ClassNotFoundException protected Class<?> findClass(final String name) throws ClassNotFoundException
{ {
Class<?> clazz=null;
if (_transformers.isEmpty()) if (_transformers.isEmpty())
clazz = super.findClass(name); return super.findClass(name);
else
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"); content = url.openStream();
URL url = getResource(path); byte[] bytes = IO.readBytes(content);
if (url==null)
throw new ClassNotFoundException(name);
InputStream content=null; if (LOG.isDebugEnabled())
try LOG.debug("foundClass({}) url={} cl={}",name,url,this);
for (ClassFileTransformer transformer : _transformers)
{ {
content = url.openStream(); byte[] tmp = transformer.transform(this,name,null,null,bytes);
byte[] bytes = IO.readBytes(content); if (tmp != null)
bytes = tmp;
}
if (LOG.isDebugEnabled()) return defineClass(name,bytes,0,bytes.length);
LOG.debug("foundClass({}) url={} cl={}",name,url,this); }
catch (IOException e)
for (ClassFileTransformer transformer : _transformers) {
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); content.close();
if (tmp != null)
bytes = tmp;
} }
catch (IOException e)
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)
{ {
try throw new ClassNotFoundException(name,e);
{
content.close();
}
catch (IOException e)
{
throw new ClassNotFoundException(name,e);
}
} }
} }
} }
return clazz;
} }
/* ------------------------------------------------------------ */
@Override @Override
public void close() throws IOException public void close() throws IOException
{ {
@ -639,4 +702,5 @@ public class WebAppClassLoader extends URLClassLoader
{ {
return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode()); return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode());
} }
} }

View File

@ -24,7 +24,6 @@ import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.security.PermissionCollection; import java.security.PermissionCollection;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -35,7 +34,6 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration.Dynamic; import javax.servlet.ServletRegistration.Dynamic;
@ -63,6 +61,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ -87,7 +86,7 @@ import org.eclipse.jetty.util.resource.ResourceCollection;
@ManagedObject("Web Application ContextHandler") @ManagedObject("Web Application ContextHandler")
public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context 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 TEMPDIR = "javax.servlet.context.tempdir";
public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir"; public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir";
@ -131,12 +130,30 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
"org.eclipse.jetty.servlets.PushSessionCacheFilter" //must be loaded by container classpath "org.eclipse.jetty.servlets.PushSessionCacheFilter" //must be loaded by container classpath
} ; } ;
// 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 // Server classes are classes that are hidden from being
// loaded by the web application using system classloader, // loaded by the web application using system classloader,
// so if web application needs to load any of such classes, // so if web application needs to load any of such classes,
// it has to include them in its distribution. // it has to include them in its distribution.
// TODO This centrally managed list of features that are exposed/hidden needs to be replaced // TODO This centrally managed list of features that are exposed/hidden needs to be replaced
// with a more automatic distributed mechanism // with a more automatic distributed mechanism
// TODO should be white list rather than black list
public final static String[] __dftServerClasses = public final static String[] __dftServerClasses =
{ {
"-org.eclipse.jetty.server.session.SessionData", //don't hide SessionData for de/serialization purposes "-org.eclipse.jetty.server.session.SessionData", //don't hide SessionData for de/serialization purposes
@ -666,21 +683,25 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Add to the list of Server classes. /**
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass) * @return The ClasspathPattern used to match Server (hidden) classes
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the server classes and order is thus
* important when added system class patterns. This argument may also be a comma
* separated list of classOrPackage patterns.
* @see #setServerClasses(String[])
* @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
*/ */
public void addServerClass(String classOrPackage) public ClasspathPattern getServerClasspathPattern()
{ {
if (_serverClasses == null) if (_serverClasses == null)
loadServerClasses(); loadServerClasses();
_serverClasses.add(classOrPackage); return _serverClasses;
}
/* ------------------------------------------------------------ */
@Deprecated
public void addServerClass(String classOrPackageOrLocation)
{
if (_serverClasses == null)
loadServerClasses();
_serverClasses.add(classOrPackageOrLocation);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -693,12 +714,13 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
* @see #setServerClasses(String[]) * @see #setServerClasses(String[])
* @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a> * @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
*/ */
@Deprecated
public void prependServerClass(String classOrPackage) public void prependServerClass(String classOrPackage)
{ {
if (_serverClasses == null) if (_serverClasses == null)
loadServerClasses(); loadServerClasses();
_serverClasses.prependPattern(classOrPackage); _serverClasses.add(classOrPackage);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -714,17 +736,21 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
return _systemClasses.getPatterns(); return _systemClasses.getPatterns();
} }
/* ------------------------------------------------------------ */
/**
* @return The ClasspathPattern used to match System (protected) classes
*/
public ClasspathPattern getSystemClasspathPattern()
{
if (_systemClasses == null)
loadSystemClasses();
return _systemClasses;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Add to the list of System classes. @Deprecated
* @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 and order is thus
* important when added system class patterns. This argument may also be a comma
* separated list of classOrPackage patterns.
* @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) public void addSystemClass(String classOrPackage)
{ {
if (_systemClasses == null) if (_systemClasses == null)
@ -744,16 +770,17 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
* @see #setSystemClasses(String[]) * @see #setSystemClasses(String[])
* @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a> * @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
*/ */
@Deprecated
public void prependSystemClass(String classOrPackage) public void prependSystemClass(String classOrPackage)
{ {
if (_systemClasses == null) if (_systemClasses == null)
loadSystemClasses(); loadSystemClasses();
_systemClasses.prependPattern(classOrPackage); _systemClasses.add(classOrPackage);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Deprecated
public boolean isServerClass(String name) public boolean isServerClass(String name)
{ {
if (_serverClasses == null) if (_serverClasses == null)
@ -763,7 +790,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Deprecated
public boolean isSystemClass(String name) public boolean isSystemClass(String name)
{ {
if (_systemClasses == null) if (_systemClasses == null)
@ -771,6 +798,58 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
return _systemClasses.match(name); return _systemClasses.match(name);
} }
/* ------------------------------------------------------------ */
@Override
public boolean isServerClass(Class<?> clazz)
{
if (_serverClasses == null)
loadServerClasses();
boolean result = _serverClasses.match(clazz);
if (LOG.isDebugEnabled())
LOG.debug("isServerClass=={} {}",result,clazz);
return result;
}
/* ------------------------------------------------------------ */
@Override
public boolean isSystemClass(Class<?> clazz)
{
if (_systemClasses == null)
loadSystemClasses();
boolean result = _systemClasses.match(clazz);
if (LOG.isDebugEnabled())
LOG.debug("isSystemClass=={} {}",result,clazz);
return result;
}
/* ------------------------------------------------------------ */
@Override
public boolean isServerResource(String name, URL url)
{
if (_serverClasses == null)
loadServerClasses();
boolean result = _serverClasses.match(name,url);
if (LOG.isDebugEnabled())
LOG.debug("isServerResource=={} {} {}",result,name,url);
return result;
}
/* ------------------------------------------------------------ */
@Override
public boolean isSystemResource(String name, URL url)
{
if (_systemClasses == null)
loadSystemClasses();
boolean result = _systemClasses.match(name,url);
if (LOG.isDebugEnabled())
LOG.debug("isSystemResource=={} {} {}",result,name,url);
return result;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
protected void loadSystemClasses() protected void loadSystemClasses()
@ -784,8 +863,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
if (server != null) if (server != null)
{ {
Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES); Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES);
if (systemClasses != null && systemClasses instanceof String[]) if (systemClasses instanceof String[])
_systemClasses = new ClasspathPattern((String[])systemClasses); _systemClasses = new ClasspathPattern((String[])systemClasses);
else if (systemClasses instanceof ClasspathPattern)
_systemClasses = new ClasspathPattern(((ClasspathPattern)systemClasses).getPatterns());
} }
if (_systemClasses == null) if (_systemClasses == null)
@ -793,7 +874,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private void loadServerClasses() protected void loadServerClasses()
{ {
if (_serverClasses != null) if (_serverClasses != null)
{ {
@ -806,10 +887,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
if (server != null) if (server != null)
{ {
Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES); Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES);
if (serverClasses != null && serverClasses instanceof String[]) if (serverClasses instanceof String[])
{
_serverClasses = new ClasspathPattern((String[])serverClasses); _serverClasses = new ClasspathPattern((String[])serverClasses);
} else if (serverClasses instanceof ClasspathPattern)
_serverClasses = new ClasspathPattern(((ClasspathPattern)serverClasses).getPatterns());
} }
if (_serverClasses == null) if (_serverClasses == null)
@ -949,10 +1030,24 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
@Override @Override
public void dump(Appendable out, String indent) throws IOException 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, dumpBeans(out,indent,
Collections.singletonList(new ClassLoaderDump(getClassLoader())), Collections.singletonList(new ClassLoaderDump(getClassLoader())),
Collections.singletonList(new DumpableCollection("Systemclasses "+this,_systemClasses)), Collections.singletonList(new DumpableCollection("Systemclasses "+this,system_classes)),
Collections.singletonList(new DumpableCollection("Serverclasses "+this,_serverClasses)), Collections.singletonList(new DumpableCollection("Serverclasses "+this,server_classes)),
Collections.singletonList(new DumpableCollection("Configurations "+this,_configurations)), Collections.singletonList(new DumpableCollection("Configurations "+this,_configurations)),
Collections.singletonList(new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet())), Collections.singletonList(new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet())),
Collections.singletonList(new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet())), Collections.singletonList(new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet())),
@ -1478,7 +1573,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
{ {
//not one of the standard servlet listeners, check our extended session listener types //not one of the standard servlet listeners, check our extended session listener types
boolean ok = false; boolean ok = false;
for (Class l:SessionHandler.SESSION_LISTENER_TYPES) for (Class<?> l:SessionHandler.SESSION_LISTENER_TYPES)
{ {
if (l.isAssignableFrom(listener)) if (l.isAssignableFrom(listener))
{ {
@ -1506,11 +1601,11 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
for (int i=resources.length;i-->0;) for (int i=resources.length;i-->0;)
{ {
if (resources[i].getName().startsWith("jar:file")) if (resources[i].getName().startsWith("jar:file"))
return resources[i].getURL(); return resources[i].getURI().toURL();
} }
} }
return resource.getURL(); return resource.getURI().toURL();
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -1536,7 +1631,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
return servletContext; return servletContext;
} }
} }
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -1544,4 +1638,53 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
{ {
return _metadata; 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;
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;
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,101 +18,214 @@
package org.eclipse.jetty.webapp; 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.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.Arrays; 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.Before;
import org.junit.Test; import org.junit.Test;
import sun.security.provider.Sun;
public class ClasspathPatternTest public class ClasspathPatternTest
{ {
private final ClasspathPattern pattern = new ClasspathPattern(); private final ClasspathPattern _pattern = new ClasspathPattern();
@Before @Before
public void before() public void before()
{ {
pattern.clear(); _pattern.clear();
pattern.add("org.package."); _pattern.add("org.package.");
pattern.add("-org.excluded."); _pattern.add("-org.excluded.");
pattern.add("org.example.FooBar"); _pattern.add("org.example.FooBar");
pattern.add("-org.example.Excluded"); _pattern.add("-org.example.Excluded");
pattern.addAll(Arrays.asList(new String[]{"-org.example.Nested$Minus","org.example.Nested","org.example.Nested$Something"})); _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 @Test
public void testClassMatch() public void testClassMatch()
{ {
assertTrue(pattern.match("org.example.FooBar")); assertTrue(_pattern.match("org.example.FooBar"));
assertTrue(pattern.match("org.example.Nested")); assertTrue(_pattern.match("org.example.Nested"));
assertFalse(pattern.match("org.example.Unknown")); assertFalse(_pattern.match("org.example.Unknown"));
assertFalse(pattern.match("org.example.FooBar.Unknown")); assertFalse(_pattern.match("org.example.FooBar.Unknown"));
} }
@Test @Test
public void testPackageMatch() public void testPackageMatch()
{ {
assertTrue(pattern.match("org.package.Something")); assertTrue(_pattern.match("org.package.Something"));
assertTrue(pattern.match("org.package.other.Something")); assertTrue(_pattern.match("org.package.other.Something"));
assertFalse(pattern.match("org.example.Unknown")); assertFalse(_pattern.match("org.example.Unknown"));
assertFalse(pattern.match("org.example.FooBar.Unknown")); assertFalse(_pattern.match("org.example.FooBar.Unknown"));
assertFalse(pattern.match("org.example.FooBarElse")); assertFalse(_pattern.match("org.example.FooBarElse"));
} }
@Test @Test
public void testExplicitNestedMatch() public void testExplicitNestedMatch()
{ {
assertTrue(pattern.match("org.example.Nested$Something")); assertTrue(_pattern.match("org.example.Nested$Something"));
assertFalse(pattern.match("org.example.Nested$Minus")); assertFalse(_pattern.match("org.example.Nested$Minus"));
assertTrue(pattern.match("org.example.Nested$Other")); assertTrue(_pattern.match("org.example.Nested$Other"));
} }
@Test @Test
public void testImplicitNestedMatch() public void testImplicitNestedMatch()
{ {
assertTrue(pattern.match("org.example.FooBar$Other")); assertTrue(_pattern.match("org.example.FooBar$Other"));
assertTrue(pattern.match("org.example.Nested$Other")); assertTrue(_pattern.match("org.example.Nested$Other"));
} }
@Test
public void testAddBefore()
{
pattern.addBefore("-org.excluded.","org.excluded.ExceptionOne","org.excluded.ExceptionTwo");
assertTrue(pattern.match("org.excluded.ExceptionOne"));
assertTrue(pattern.match("org.excluded.ExceptionTwo"));
assertFalse(pattern.match("org.example.Unknown"));
}
@Test
public void testAddAfter()
{
pattern.addAfter("org.package.","org.excluded.ExceptionOne","org.excluded.ExceptionTwo");
assertTrue(pattern.match("org.excluded.ExceptionOne"));
assertTrue(pattern.match("org.excluded.ExceptionTwo"));
assertFalse(pattern.match("org.example.Unknown"));
}
@Test @Test
public void testDoubledNested() 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 @Test
public void testMatchAll() public void testMatchAll()
{ {
pattern.clear(); _pattern.clear();
pattern.add("."); _pattern.add(".");
assertTrue(pattern.match("org.example.Anything")); assertTrue(_pattern.match("org.example.Anything"));
assertTrue(pattern.match("org.example.Anything$Else")); 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

@ -56,8 +56,6 @@ public class WebAppClassLoaderTest
this.testWebappDir = MavenTestingUtils.getProjectDirPath("src/test/webapp"); this.testWebappDir = MavenTestingUtils.getProjectDirPath("src/test/webapp");
Resource webapp = new PathResource(testWebappDir); Resource webapp = new PathResource(testWebappDir);
System.err.printf("testWebappDir = %s%n", testWebappDir);
_context = new WebAppContext(); _context = new WebAppContext();
_context.setBaseResource(webapp); _context.setBaseResource(webapp);
_context.setContextPath("/test"); _context.setContextPath("/test");
@ -66,6 +64,9 @@ public class WebAppClassLoaderTest
_loader.addJars(webapp.addPath("WEB-INF/lib")); _loader.addJars(webapp.addPath("WEB-INF/lib"));
_loader.addClassPath(webapp.addPath("WEB-INF/classes")); _loader.addClassPath(webapp.addPath("WEB-INF/classes"));
_loader.setName("test"); _loader.setName("test");
_context.loadSystemClasses();
_context.loadServerClasses();
} }
public void assertCanLoadClass(String clazz) throws ClassNotFoundException public void assertCanLoadClass(String clazz) throws ClassNotFoundException
@ -250,7 +251,7 @@ public class WebAppClassLoaderTest
URL targetTestClasses = this.getClass().getClassLoader().getResource("org/acme/resource.txt"); URL targetTestClasses = this.getClass().getClassLoader().getResource("org/acme/resource.txt");
_context.setParentLoaderPriority(false); _context.setParentLoaderPriority(false);
dump(_context);
resources =Collections.list(_loader.getResources("org/acme/resource.txt")); resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
expected.clear(); expected.clear();
@ -260,12 +261,6 @@ public class WebAppClassLoaderTest
assertThat("Resources Found (Parent Loader Priority == false)",resources,ordered(expected)); 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); _context.setParentLoaderPriority(true);
// dump(_context); // dump(_context);
resources =Collections.list(_loader.getResources("org/acme/resource.txt")); resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
@ -320,49 +315,6 @@ public class WebAppClassLoaderTest
assertThat("Resources Found (Parent Loader Priority == true) (with systemClasses filtering)",resources,ordered(expected)); 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);
}
}
} }