diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index fcab2ac596af..bf2e54e66a84 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -48,6 +47,7 @@ import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -81,8 +81,6 @@ public class AnnotationConfiguration extends AbstractConfiguration protected List _containerInitializerAnnotationHandlers = new ArrayList(); protected List _parserTasks; - protected WebAppClassNameResolver _webAppClassNameResolver; - protected ContainerClassNameResolver _containerClassNameResolver; protected CounterStatistic _containerPathStats; protected CounterStatistic _webInfLibStats; @@ -138,15 +136,13 @@ public class ParserTask implements Callable protected Exception _exception; protected final AnnotationParser _parser; protected final Set _handlers; - protected final ClassNameResolver _resolver; protected final Resource _resource; protected TimeStatistic _stat; - public ParserTask (AnnotationParser parser, Sethandlers, Resource resource, ClassNameResolver resolver) + public ParserTask (AnnotationParser parser, Sethandlers, Resource resource) { _parser = parser; _handlers = handlers; - _resolver = resolver; _resource = resource; } @@ -160,7 +156,7 @@ public Void call() throws Exception if (_stat != null) _stat.start(); if (_parser != null) - _parser.parse(_handlers, _resource, _resolver); + _parser.parse(_handlers, _resource); if (_stat != null) _stat.end(); return null; @@ -174,83 +170,7 @@ public TimeStatistic getStatistic() public Resource getResource() { return _resource; - } - - } - - /** - * WebAppClassNameResolver - * - * Checks to see if a classname belongs to hidden or visible packages when scanning, - * and whether a classname that is a duplicate should override a previously - * scanned classname. - * - * This is analogous to the management of classes that the WebAppClassLoader is doing, - * however we don't want to load the classes at this point so we are doing it on - * the name only. - * - */ - public class WebAppClassNameResolver implements ClassNameResolver - { - private WebAppContext _context; - - public WebAppClassNameResolver (WebAppContext context) - { - _context = context; - } - - public boolean isExcluded (String name) - { - if (_context.isSystemClass(name)) return true; - if (_context.isServerClass(name)) return false; - return false; - } - - public boolean shouldOverride (String name) - { - //looking at webapp classpath, found already-parsed class - //of same name - did it come from system or duplicate in webapp? - if (_context.isParentLoaderPriority()) - return false; - return true; - } - } - - - /** - * ContainerClassNameResolver - * - * Checks to see if a classname belongs to a hidden or visible package - * when scanning for annotations and thus whether it should be excluded from - * consideration or not. - * - * This is analogous to the management of classes that the WebAppClassLoader is doing, - * however we don't want to load the classes at this point so we are doing it on - * the name only. - * - */ - public class ContainerClassNameResolver implements ClassNameResolver - { - private WebAppContext _context; - - public ContainerClassNameResolver (WebAppContext context) - { - _context = context; - } - public boolean isExcluded (String name) - { - if (_context.isSystemClass(name)) return false; - if (_context.isServerClass(name)) return true; - return false; - } - - public boolean shouldOverride (String name) - { - //visiting the container classpath, - if (_context.isParentLoaderPriority()) - return true; - return false; - } + } } @@ -390,8 +310,6 @@ public int compare(ServletContainerInitializer sci1, ServletContainerInitializer @Override public void preConfigure(final WebAppContext context) throws Exception { - _webAppClassNameResolver = new WebAppClassNameResolver(context); - _containerClassNameResolver = new ContainerClassNameResolver(context); String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN); _sciExcludePattern = (tmp==null?null:Pattern.compile(tmp)); } @@ -445,15 +363,15 @@ public void configure(WebAppContext context) throws Exception if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty()) scanForAnnotations(context); - + // Resolve container initializers List initializers = - (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); + (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); if (initializers != null && initializers.size()>0) { Map> map = ( Map>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP); for (ContainerInitializer i : initializers) - i.resolveClasses(context,map); + i.resolveClasses(context,map); } } @@ -723,23 +641,7 @@ public void createServletContainerInitializerAnnotationHandlers (WebAppContext c public Resource getJarFor (ServletContainerInitializer service) throws MalformedURLException, IOException { - //try the thread context classloader to get the jar that loaded the class - URL jarURL = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class"); - - //if for some reason that failed (eg we're in osgi and the TCCL does not know about the service) try the classloader that - //loaded the class - if (jarURL == null) - jarURL = service.getClass().getClassLoader().getResource(service.getClass().getName().replace('.','/')+".class"); - - String loadingJarName = jarURL.toString(); - - int i = loadingJarName.indexOf(".jar"); - if (i < 0) - return null; //not from a jar - - loadingJarName = loadingJarName.substring(0,i+4); - loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName); - return Resource.newResource(loadingJarName); + return TypeUtil.getLoadedFrom(service.getClass()); } /** @@ -760,26 +662,41 @@ public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitial if (context == null) throw new IllegalArgumentException("WebAppContext null"); - if (LOG.isDebugEnabled()) LOG.debug("Checking {} for jar exclusion", sci); - + //A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering //of WEB-INF/lib jars if (isFromContainerClassPath(context, sci)) + { + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} from container classpath", sci); return false; + } //If no ordering, nothing is excluded if (context.getMetaData().getOrdering() == null) + { + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} no ordering", sci); return false; - + } List orderedJars = context.getMetaData().getOrderedWebInfJars(); //there is an ordering, but there are no jars resulting from the ordering, everything excluded if (orderedJars.isEmpty()) + { + if (LOG.isDebugEnabled()) + LOG.debug("Excluded {} empty ordering", sci); return true; + } if (sciResource == null) - return false; //not from a jar therefore not from WEB-INF so not excludable + { + //not from a jar therefore not from WEB-INF so not excludable + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} not from jar", sci); + return false; + } URI loadingJarURI = sciResource.getURI(); boolean found = false; @@ -790,10 +707,11 @@ public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitial found = r.getURI().equals(loadingJarURI); } + if (LOG.isDebugEnabled()) + LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found); return !found; } - /** * Test if the ServletContainerIntializer is excluded by the * o.e.j.containerInitializerExclusionPattern @@ -808,7 +726,8 @@ public boolean matchesExclusionPattern(ServletContainerInitializer sci) return false; //test if name of class matches the regex - if (LOG.isDebugEnabled()) LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName()); + if (LOG.isDebugEnabled()) + LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName()); return _sciExcludePattern.matcher(sci.getClass().getName()).matches(); } @@ -866,17 +785,20 @@ public List getNonExcludedInitializers (WebAppConte //because containerInitializerOrdering omits it for (ServletContainerInitializer sci:_loadedInitializers) { + LOG.setDebugEnabled(true); if (matchesExclusionPattern(sci)) { - if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci); + if (LOG.isDebugEnabled()) + LOG.debug("{} excluded by pattern", sci); continue; } Resource sciResource = getJarFor(sci); if (isFromExcludedJar(context, sci, sciResource)) { - if (LOG.isDebugEnabled()) LOG.debug("{} is from excluded jar", sci); + if (LOG.isDebugEnabled()) + LOG.debug("{} is from excluded jar", sci); continue; } @@ -885,7 +807,8 @@ public List getNonExcludedInitializers (WebAppConte if (initializerOrdering != null && (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0)) { - if (LOG.isDebugEnabled()) LOG.debug("{} is excluded by ordering", sci); + if (LOG.isDebugEnabled()) + LOG.debug("{} is excluded by ordering", sci); continue; } @@ -912,12 +835,14 @@ public List getNonExcludedInitializers (WebAppConte //no web.xml ordering defined, add SCIs in any order if (context.getMetaData().getOrdering() == null) { - if (LOG.isDebugEnabled()) LOG.debug("No web.xml ordering, ServletContainerInitializers in random order"); + if (LOG.isDebugEnabled()) + LOG.debug("No web.xml ordering, ServletContainerInitializers in random order"); nonExcludedInitializers.addAll(sciResourceMap.keySet()); } else { - if (LOG.isDebugEnabled()) LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering()); + if (LOG.isDebugEnabled()) + LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering()); for (Map.Entry entry:sciResourceMap.entrySet()) { //add in SCIs from the container classpath @@ -992,7 +917,7 @@ public void parseContainerPath (final WebAppContext context, final AnnotationPar //queue it up for scanning if using multithreaded mode if (_parserTasks != null) { - ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver); + ParserTask task = new ParserTask(parser, handlers, r); _parserTasks.add(task); _containerPathStats.increment(); if (LOG.isDebugEnabled()) @@ -1054,7 +979,7 @@ public void parseWebInfLib (final WebAppContext context, final AnnotationParser if (_parserTasks != null) { - ParserTask task = new ParserTask(parser, handlers,r, _webAppClassNameResolver); + ParserTask task = new ParserTask(parser, handlers,r); _parserTasks.add (task); _webInfLibStats.increment(); if (LOG.isDebugEnabled()) @@ -1087,7 +1012,7 @@ public void parseWebInfClasses (final WebAppContext context, final AnnotationPar { if (_parserTasks != null) { - ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver); + ParserTask task = new ParserTask(parser, handlers, dir); _parserTasks.add(task); _webInfClassesStats.increment(); if (LOG.isDebugEnabled()) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 01a1c475d727..a297399a4978 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -547,25 +547,22 @@ public boolean isParsed (String className) * @param resolver the class name resolver to use * @throws Exception if unable to parse */ - public void parse (Set handlers, String className, ClassNameResolver resolver) + public void parse (Set handlers, String className) throws Exception { if (className == null) return; - if (!resolver.isExcluded(className)) + if (!isParsed(className)) { - if (!isParsed(className) || resolver.shouldOverride(className)) + className = className.replace('.', '/')+".class"; + URL resource = Loader.getResource(className); + if (resource!= null) { - className = className.replace('.', '/')+".class"; - URL resource = Loader.getResource(className); - if (resource!= null) + Resource r = Resource.newResource(resource); + try (InputStream is = r.getInputStream()) { - Resource r = Resource.newResource(resource); - try (InputStream is = r.getInputStream()) - { - scanClass(handlers, null, is); - } + scanClass(handlers, null, is); } } } @@ -582,29 +579,27 @@ public void parse (Set handlers, String className, ClassNameR * @param visitSuperClasses if true, also visit super classes for parse * @throws Exception if unable to parse class */ - public void parse (Set handlers, Class clazz, ClassNameResolver resolver, boolean visitSuperClasses) + public void parse (Set handlers, Class clazz, boolean visitSuperClasses) throws Exception { Class cz = clazz; while (cz != null) { - if (!resolver.isExcluded(cz.getName())) + if (!isParsed(cz.getName())) { - if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName())) + String nameAsResource = cz.getName().replace('.', '/')+".class"; + URL resource = Loader.getResource(nameAsResource); + if (resource!= null) { - String nameAsResource = cz.getName().replace('.', '/')+".class"; - URL resource = Loader.getResource(nameAsResource); - if (resource!= null) + Resource r = Resource.newResource(resource); + try (InputStream is = r.getInputStream()) { - Resource r = Resource.newResource(resource); - try (InputStream is = r.getInputStream()) - { - scanClass(handlers, null, is); - } + scanClass(handlers, null, is); } } } + if (visitSuperClasses) cz = cz.getSuperclass(); else @@ -622,13 +617,13 @@ public void parse (Set handlers, Class clazz, ClassNameRes * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (Set handlers, String[] classNames, ClassNameResolver resolver) + public void parse (Set handlers, String[] classNames) throws Exception { if (classNames == null) return; - parse(handlers, Arrays.asList(classNames), resolver); + parse(handlers, Arrays.asList(classNames)); } @@ -640,7 +635,7 @@ public void parse (Set handlers, String[] classNames, ClassNa * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (Set handlers, List classNames, ClassNameResolver resolver) + public void parse (Set handlers, List classNames) throws Exception { MultiException me = new MultiException(); @@ -649,7 +644,7 @@ public void parse (Set handlers, List classNames, Cla { try { - if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s)))) + if (!isParsed(s)) { s = s.replace('.', '/')+".class"; URL resource = Loader.getResource(s); @@ -680,7 +675,7 @@ public void parse (Set handlers, List classNames, Cla * @param resolver the class name resolver * @throws Exception if unable to parse */ - protected void parseDir (Set handlers, Resource dir, ClassNameResolver resolver) + protected void parseDir (Set handlers, Resource dir) throws Exception { // skip dirs whose name start with . (ie hidden) @@ -696,7 +691,7 @@ protected void parseDir (Set handlers, Resource dir, ClassNam { Resource res = dir.addPath(files[f]); if (res.isDirectory()) - parseDir(handlers, res, resolver); + parseDir(handlers, res); else { //we've already verified the directories, so just verify the class file name @@ -706,7 +701,7 @@ protected void parseDir (Set handlers, Resource dir, ClassNam try { String name = res.getName(); - if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name)))) + if (!isParsed(name)) { Resource r = Resource.newResource(res.getURL()); if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);}; @@ -744,7 +739,7 @@ protected void parseDir (Set handlers, Resource dir, ClassNam * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver) + public void parse (final Set handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive) throws Exception { if (loader==null) @@ -762,7 +757,7 @@ public void processEntry(URI jarUri, JarEntry entry) { try { - parseJarEntry(handlers, Resource.newResource(jarUri), entry, resolver); + parseJarEntry(handlers, Resource.newResource(jarUri), entry); } catch (Exception e) { @@ -785,7 +780,7 @@ public void processEntry(URI jarUri, JarEntry entry) * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, final URI[] uris, final ClassNameResolver resolver) + public void parse (final Set handlers, final URI[] uris) throws Exception { if (uris==null) @@ -797,7 +792,7 @@ public void parse (final Set handlers, final URI[] uris, fina { try { - parse(handlers, uri, resolver); + parse(handlers, uri); } catch (Exception e) { @@ -815,13 +810,13 @@ public void parse (final Set handlers, final URI[] uris, fina * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, URI uri, final ClassNameResolver resolver) + public void parse (final Set handlers, URI uri) throws Exception { if (uri == null) return; - parse (handlers, Resource.newResource(uri), resolver); + parse (handlers, Resource.newResource(uri)); } @@ -833,7 +828,7 @@ public void parse (final Set handlers, URI uri, final ClassNa * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, Resource r, final ClassNameResolver resolver) + public void parse (final Set handlers, Resource r) throws Exception { if (r == null) @@ -841,14 +836,14 @@ public void parse (final Set handlers, Resource r, final Clas if (r.exists() && r.isDirectory()) { - parseDir(handlers, r, resolver); + parseDir(handlers, r); return; } String fullname = r.toString(); if (fullname.endsWith(".jar")) { - parseJar(handlers, r, resolver); + parseJar(handlers, r); return; } @@ -875,7 +870,7 @@ public void parse (final Set handlers, Resource r, final Clas * @param resolver the class name resolver * @throws Exception if unable to parse */ - protected void parseJar (Set handlers, Resource jarResource, final ClassNameResolver resolver) + protected void parseJar (Set handlers, Resource jarResource) throws Exception { if (jarResource == null) @@ -899,7 +894,7 @@ protected void parseJar (Set handlers, Resource jarResource, { try { - parseJarEntry(handlers, jarResource, entry, resolver); + parseJarEntry(handlers, jarResource, entry); } catch (Exception e) { @@ -930,7 +925,7 @@ protected void parseJar (Set handlers, Resource jarResource, * @param resolver the class name resolver * @throws Exception if unable to parse */ - protected void parseJarEntry (Set handlers, Resource jar, JarEntry entry, final ClassNameResolver resolver) + protected void parseJarEntry (Set handlers, Resource jar, JarEntry entry) throws Exception { if (jar == null || entry == null) @@ -947,9 +942,7 @@ protected void parseJarEntry (Set handlers, Resource jar, Jar { String shortName = name.replace('/', '.').substring(0,name.length()-6); - if ((resolver == null) - || - (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName)))) + if (!isParsed(shortName)) { Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name); if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);}; diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java deleted file mode 100644 index 84905cb5d28f..000000000000 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java +++ /dev/null @@ -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); -} diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java index 643c3f840773..5a7ed8b56ac8 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java @@ -74,6 +74,12 @@ public void handle(MethodInfo info, String annotation) return; annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName()); } + + @Override + public String toString() + { + return annotatedClassNames.toString()+annotatedMethods+annotatedFields; + } } @After @@ -93,18 +99,7 @@ public void testParseClassNames() throws Exception SampleHandler handler = new SampleHandler(); AnnotationParser parser = new AnnotationParser(); - parser.parse(Collections.singleton(handler), classNames, new ClassNameResolver () - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); + parser.parse(Collections.singleton(handler), classNames); //check we got 2 class annotations assertEquals(2, handler.annotatedClassNames.size()); @@ -129,18 +124,7 @@ public void testParseClass() throws Exception { SampleHandler handler = new SampleHandler(); AnnotationParser parser = new AnnotationParser(); - parser.parse(Collections.singleton(handler), ClassB.class, new ClassNameResolver () - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }, true); + parser.parse(Collections.singleton(handler), ClassB.class, true); //check we got 2 class annotations assertEquals(2, handler.annotatedClassNames.size()); @@ -160,46 +144,6 @@ public boolean shouldOverride(String name) assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); } - @Test - public void testExclusions() throws Exception - { - AnnotationParser parser = new AnnotationParser(); - SampleHandler handler = new SampleHandler(); - parser.parse(Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver() - { - public boolean isExcluded(String name) - { - return true; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); - assertEquals (0, handler.annotatedClassNames.size()); - assertEquals (0, handler.annotatedFields.size()); - assertEquals (0, handler.annotatedMethods.size()); - - handler.annotatedClassNames.clear(); - handler.annotatedFields.clear(); - handler.annotatedMethods.clear(); - - parser.parse (Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver() - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); - assertEquals (1, handler.annotatedClassNames.size()); - } - @Test public void testTypeInheritanceHandling() throws Exception { @@ -218,7 +162,7 @@ class Foo implements InterfaceD classNames.add(InterfaceD.class.getName()); classNames.add(Foo.class.getName()); - parser.parse(Collections.singleton(handler), classNames, null); + parser.parse(Collections.singleton(handler), classNames); assertNotNull(map); assertFalse(map.isEmpty()); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java index d86283b32a5a..002e41bfa5c1 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java @@ -111,19 +111,7 @@ public void handle(MethodInfo info, String annotation) } //long start = System.currentTimeMillis(); - parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver() - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - - }); + parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames); //long end = System.currentTimeMillis(); //System.err.println("Time to parse class: " + ((end - start))); @@ -162,7 +150,7 @@ public void handle(MethodInfo info, String annotation) } } - parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames,null); + parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames); } @Test @@ -171,7 +159,7 @@ public void testHiddenFilesInJar() throws Exception File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar"); AnnotationParser parser = new AnnotationParser(); Set emptySet = Collections.emptySet(); - parser.parse(emptySet, badClassesJar.toURI(),null); + parser.parse(emptySet, badClassesJar.toURI()); // only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here } @@ -196,7 +184,7 @@ public void testBasedirExclusion() throws Exception AnnotationParser parser = new AnnotationParser(); // Parse - parser.parse(Collections.singleton(tracker), basedir.toURI(),null); + parser.parse(Collections.singleton(tracker), basedir.toURI()); // Validate Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName())); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java index e26f856035c8..01ed2f35d3a1 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java @@ -73,18 +73,7 @@ public void testServletAnnotation() throws Exception TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results); - parser.parse(Collections.singleton(handler), classes, new ClassNameResolver () - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); + parser.parse(Collections.singleton(handler), classes); assertEquals(1, results.size()); diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud-datastore.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud-datastore.mod new file mode 100644 index 000000000000..c98eaf225140 --- /dev/null +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud-datastore.mod @@ -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 diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud.mod new file mode 100644 index 000000000000..7c774c795d0f --- /dev/null +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud.mod @@ -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. diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud/gcloud.xml b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud/gcloud.xml new file mode 100644 index 000000000000..19f79a1eba78 --- /dev/null +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud/gcloud.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + file:${jetty.base}/lib/gcloud + + + + + diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/index.yaml b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud/index.yaml similarity index 100% rename from jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/index.yaml rename to jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud/index.yaml diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod index 7e8d0afcf731..3d6b26e04977 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod @@ -5,88 +5,20 @@ Enables GCloudDatastore session management. session-store [depends] +gcloud-datastore annotations webapp sessions -jcl-api -jcl-impl [files] -basehome:etc/sessions/gcloud/index.yaml|etc/index.yaml -maven://com.google.cloud/google-cloud-datastore/0.3.0|lib/gcloud/google-cloud-datastore-0.3.0.jar -maven://com.google.cloud/google-cloud-core/0.3.0|lib/gcloud/google-cloud-core-0.3.0.jar -maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar -maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar -maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar -maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar -maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar -maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar -maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar -maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar -maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar -maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar -maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar -maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar -maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar -maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar -maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar -maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar -maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar -maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar -maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar -maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar -maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar -maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar -maven://com.google.protobuf/protobuf-java/3.0.0-beta-3|lib/gcloud/protobuf-java-3.0.0-beta-3.jar -maven://com.google.api/gax/0.0.16|lib/gcloud/gax-0.0.16.jar -maven://io.grpc/grpc-all/0.15.0|lib/gcloud/grpc-all-0.15.0.jar -maven://io.grpc/grpc-auth/0.15.0|lib/gcloud/grpc-auth-0.15.0.jar -maven://io.grpc/grpc-netty/0.15.0|lib/gcloud/grpc-netty-0.15.0.jar -maven://io.netty/netty-codec-http2/4.1.1.Final|lib/gcloud/netty-codec-http2-4.1.1.jar -maven://io.netty/netty-codec-http/4.1.1.Final|lib/gcloud/netty-codec-http-4.1.1.Final.jar -maven://io.netty/netty-codec/4.1.1.Final|lib/gcloud/netty-codec-4.1.1.Final.jar -maven://io.netty/netty-handler/4.1.1.Final|lib/gcloud/netty-handler-4.1.1.Final.jar -maven://io.netty/netty-buffer/4.1.1.Final|lib/gcloud/netty-buffer-4.1.1.Final.jar -maven://io.netty/netty-common/4.1.1.Final|lib/gcloud/netty-common-4.1.1.Final.jar -maven://io.netty/netty-transport/4.1.1.Final|lib/gcloud/netty-transport-4.1.1.Final.jar -maven://io.netty/netty-resolver/4.1.1.Final|lib/gcloud/netty-resolver-4.1.1.Final.jar -maven://io.grpc/grpc-okhttp/0.15.0|lib/gcloud/grpc-okhttp-0.15.0.jar -maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar -maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar -maven://io.grpc/grpc-protobuf-nano/0.15.0|lib/gcloud/grpc-protobuf-nano-0.15.0.jar -maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano-3.0.0-alpha-5.jar -maven://io.grpc/grpc-stub/0.15.0|lib/gcloud/grpc-stub-0.15.0.jar -maven://io.grpc/grpc-protobuf/0.15.0|lib/gcloud/grpc-protobuf-0.15.0.jar -maven://com.google.protobuf/protobuf-java-util/3.0.0-beta-3|lib/gcloud/protobuf-java-util-3.0.0-beta-3.jar -maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar -maven://io.grpc/grpc-protobuf-lite/0.15.0|lib/gcloud/grpc-protobuf-lite-0.15.0.jar -maven://io.grpc/grpc-core/0.15.0|lib/gcloud/grpc-core-0.15.0.jar -maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar -maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar -maven://javax.inject/javax.inject/1|lib/gcloud/javax.inject-1.jar -maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar -maven://com.google.api.grpc/grpc-google-common-protos/0.0.7|lib/gcloud/grpc-google-common-protos-0.0.7.jar -maven://org.json/json/20151123|lib/gcloud/json-20151123.jar -maven://com.google.cloud.datastore/datastore-v1-protos/1.0.1|lib/gcloud/datastore-v1-protos-1.0.1-beta.jar -maven://com.google.cloud.datastore/datastore-v1-proto-client/1.1.0|lib/gcloud/datastore-v1-proto-client-1.1.0.jar -maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar -maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar -maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar - - +basehome:modules/gcloud/index.yaml|etc/index.yaml [lib] lib/jetty-gcloud-session-manager-${jetty.version}.jar -lib/gcloud/*.jar [xml] etc/sessions/gcloud/session-store.xml -[license] -GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license. -https://github.com/GoogleCloudPlatform/gcloud-java -http://www.apache.org/licenses/LICENSE-2.0.html - [ini-template] ## GCloudDatastore Session config diff --git a/jetty-gcloud/pom.xml b/jetty-gcloud/pom.xml index 6f2fb0a890c0..d73a0ab76672 100644 --- a/jetty-gcloud/pom.xml +++ b/jetty-gcloud/pom.xml @@ -13,7 +13,7 @@ Jetty :: GCloud - 0.3.0 + 0.4.0 diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java index d92ccd5f4d9e..70f8669cad58 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java @@ -18,11 +18,14 @@ package org.eclipse.jetty.osgi.annotations; +import java.io.IOException; +import java.net.MalformedURLException; import java.util.HashSet; import java.util.Set; +import javax.servlet.ServletContainerInitializer; + import org.eclipse.jetty.annotations.AnnotationParser.Handler; -import org.eclipse.jetty.annotations.ClassNameResolver; import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration; import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; import org.eclipse.jetty.util.log.Log; @@ -44,9 +47,9 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot public class BundleParserTask extends ParserTask { - public BundleParserTask (AnnotationParser parser, Sethandlers, Resource resource, ClassNameResolver resolver) + public BundleParserTask (AnnotationParser parser, Sethandlers, Resource resource) { - super(parser, handlers, resource, resolver); + super(parser, handlers, resource); } public Void call() throws Exception @@ -57,7 +60,7 @@ public Void call() throws Exception Bundle bundle = osgiAnnotationParser.getBundle(_resource); if (_stat != null) _stat.start(); - osgiAnnotationParser.parse(_handlers, bundle, _resolver); + osgiAnnotationParser.parse(_handlers, bundle); if (_stat != null) _stat.end(); } @@ -79,6 +82,17 @@ protected org.eclipse.jetty.annotations.AnnotationParser createAnnotationParser( 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. *
    @@ -195,47 +209,13 @@ protected void parseBundle(WebAppContext context, AnnotationParser parser, handlers.add(_classInheritanceHandler); handlers.addAll(_containerInitializerAnnotationHandlers); - ClassNameResolver classNameResolver = createClassNameResolver(context); if (_parserTasks != null) { - BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes, classNameResolver); + BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes); _parserTasks.add(task); if (LOG.isDebugEnabled()) task.setStatistic(new TimeStatistic()); } } - /** - * Returns the same classname resolver than for the webInfjar scanner - * @param context the web app context - * @return the class name resolver - */ - protected ClassNameResolver createClassNameResolver(final WebAppContext context) - { - return createClassNameResolver(context,true,false,false,false); - } - - protected ClassNameResolver createClassNameResolver(final WebAppContext context, - final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse, - final boolean overrideIsParenLoaderIsPriority) - { - return new ClassNameResolver () - { - public boolean isExcluded (String name) - { - if (context.isSystemClass(name)) return excludeSysClass; - if (context.isServerClass(name)) return excludeServerClass; - return excludeEverythingElse; - } - - public boolean shouldOverride (String name) - { - //looking at system classpath - if (context.isParentLoaderPriority()) - return overrideIsParenLoaderIsPriority; - return !overrideIsParenLoaderIsPriority; - } - }; - } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java index a22b4077113c..d454e9be7cf8 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java @@ -29,7 +29,6 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; -import org.eclipse.jetty.annotations.ClassNameResolver; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory; import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.resource.Resource; @@ -85,7 +84,7 @@ protected Bundle getBundle (Resource resource) * */ @Override - public void parse (Set handlers, URI[] uris, ClassNameResolver resolver) + public void parse (Set handlers, URI[] uris) throws Exception { for (URI uri : uris) @@ -99,16 +98,16 @@ public void parse (Set handlers, URI[] uris, ClassNameResolve } //a jar in WEB-INF/lib or the WEB-INF/classes //use the behavior of the super class for a standard jar. - super.parse(handlers, new URI[] {uri},resolver); + super.parse(handlers, new URI[] {uri}); } else { - parse(handlers, associatedBundle,resolver); + parse(handlers, associatedBundle); } } } - protected void parse(Set handlers, Bundle bundle, ClassNameResolver resolver) + protected void parse(Set handlers, Bundle bundle) throws Exception { URI uri = _bundleToUri.get(bundle); @@ -205,7 +204,7 @@ else if (bundle.getEntry("/target/classes/") != null) } //transform into a classname to pass to the resolver String shortName = name.replace('/', '.').substring(0,name.length()-6); - if ((resolver == null) || (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName)))) + if (!isParsed(shortName)) { try (InputStream classInputStream = classUrl.openStream()) { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java index a04f37adfb52..02c0feb35dc8 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java @@ -47,18 +47,16 @@ public abstract class AbstractOSGiApp extends App private static final Logger LOG = Log.getLogger(AbstractOSGiApp.class); protected Bundle _bundle; - protected Dictionary _properties; + protected Dictionary _properties; protected ServiceRegistration _registration; /* ------------------------------------------------------------ */ public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId) { - super(manager, provider, originId); - _properties = bundle.getHeaders(); - _bundle = bundle; + this (manager, provider, bundle, bundle.getHeaders(), originId); } /* ------------------------------------------------------------ */ - public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) + public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) { super(manager, provider, originId); _properties = properties; diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java index 0386f013c7ee..74d386cc8378 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java @@ -38,6 +38,7 @@ import org.eclipse.jetty.util.resource.JarResource; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.Configuration; +import org.eclipse.jetty.webapp.WebAppClassLoader; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.xml.XmlConfiguration; import org.osgi.framework.Bundle; @@ -436,18 +437,23 @@ protected void applyMetaInfContextXml(Resource rootResource, String overrideBund } } } - if (contextXmlUrl == null) return; + if (contextXmlUrl == null) + return; // Apply it just as the standard jetty ContextProvider would do LOG.info("Applying " + contextXmlUrl + " to " + _webApp); XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl); - HashMap properties = new HashMap(); - properties.put("Server", getDeploymentManager().getServer()); - properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); - properties.put(OSGiServerConstants.JETTY_HOME, getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME)); - xmlConfiguration.getProperties().putAll(properties); - xmlConfiguration.configure(_webApp); + WebAppClassLoader.runWithServerClassAccess(()-> + { + HashMap properties = new HashMap<>(); + xmlConfiguration.getIdMap().put("Server",getDeploymentManager().getServer()); + properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); + properties.put(OSGiServerConstants.JETTY_HOME, (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME)); + xmlConfiguration.getProperties().putAll(properties); + xmlConfiguration.configure(_webApp); + return null; + }); } finally { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java index 43bf2c4733c5..395c621139fd 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java @@ -175,7 +175,7 @@ public boolean bundleAdded (Bundle bundle) throws Exception String contextPath = null; try { - Dictionary headers = bundle.getHeaders(); + Dictionary headers = bundle.getHeaders(); //does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers); @@ -217,7 +217,7 @@ public boolean bundleAdded (Bundle bundle) throws Exception { //Could be a static webapp with no web.xml String base = "."; - contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); + contextPath = headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); String originId = getOriginId(bundle,base); OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java index 8c77b130d761..8ba7377e9c98 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java @@ -78,8 +78,6 @@ public static void addClassThatIdentifiesAJarThatMustBeRejected(String zclassNam private Bundle _contributor; - private boolean _lookInOsgiFirst = true; - /* ------------------------------------------------------------ */ /** * @param parent The parent classloader. @@ -96,11 +94,26 @@ public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle c } - + + /* ------------------------------------------------------------ */ @Override public Class loadClass(String name) throws ClassNotFoundException { - return super.loadClass(name); + try + { + return _osgiBundleClassLoader.loadClass(name); + } + catch (ClassNotFoundException cne) + { + try + { + return super.loadClass(name); + } + catch (ClassNotFoundException cne2) + { + throw cne; + } + } } /* ------------------------------------------------------------ */ @@ -121,36 +134,18 @@ public Enumeration getResources(String name) throws IOException { Enumeration osgiUrls = _osgiBundleClassLoader.getResources(name); Enumeration urls = super.getResources(name); - if (_lookInOsgiFirst) - { - return Collections.enumeration(toList(osgiUrls, urls)); - } - else - { - return Collections.enumeration(toList(urls, osgiUrls)); - } + List resources = toList(osgiUrls, urls); + return Collections.enumeration(resources); } - - /* ------------------------------------------------------------ */ @Override public URL getResource(String name) { - if (_lookInOsgiFirst) - { - URL url = _osgiBundleClassLoader.getResource(name); - return url != null ? url : super.getResource(name); - } - else - { - URL url = super.getResource(name); - return url != null ? url : _osgiBundleClassLoader.getResource(name); - } + URL url = _osgiBundleClassLoader.getResource(name); + return url != null ? url : super.getResource(name); } - - /* ------------------------------------------------------------ */ private List toList(Enumeration e, Enumeration e2) { @@ -160,30 +155,7 @@ private List toList(Enumeration e, Enumeration e2) while (e2 != null && e2.hasMoreElements()) list.add(e2.nextElement()); return list; - } - - - /* ------------------------------------------------------------ */ - protected Class findClass(String name) throws ClassNotFoundException - { - try - { - return _lookInOsgiFirst ? _osgiBundleClassLoader.loadClass(name) : super.findClass(name); - } - catch (ClassNotFoundException cne) - { - try - { - return _lookInOsgiFirst ? super.findClass(name) : _osgiBundleClassLoader.loadClass(name); - } - catch (ClassNotFoundException cne2) - { - throw cne; - } - } - } - - + } /* ------------------------------------------------------------ */ /** diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/BufferedResponseHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/BufferedResponseHandler.java index 19cccb6326ab..07e63fac3505 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/BufferedResponseHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/BufferedResponseHandler.java @@ -133,7 +133,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques } // If not a supported method - no Vary because no matter what client, this URI is always excluded - if (!_methods.matches(baseRequest.getMethod())) + if (!_methods.test(baseRequest.getMethod())) { LOG.debug("{} excluded by method {}",this,request); _handler.handle(target,baseRequest, request, response); @@ -173,7 +173,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques /* ------------------------------------------------------------ */ protected boolean isMimeTypeBufferable(String mimetype) { - return _mimeTypes.matches(mimetype); + return _mimeTypes.test(mimetype); } /* ------------------------------------------------------------ */ @@ -182,7 +182,7 @@ protected boolean isPathBufferable(String requestURI) if (requestURI == null) return true; - return _paths.matches(requestURI); + return _paths.test(requestURI); } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java index 3d5ff8df02d9..2ec6e6e2a538 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java @@ -457,7 +457,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques } // If not a supported method - no Vary because no matter what client, this URI is always excluded - if (!_methods.matches(baseRequest.getMethod())) + if (!_methods.test(baseRequest.getMethod())) { LOG.debug("{} excluded by method {}",this,request); _handler.handle(target,baseRequest, request, response); @@ -549,14 +549,14 @@ protected boolean isAgentGzipable(String ua) if (ua == null) return false; - return _agentPatterns.matches(ua); + return _agentPatterns.test(ua); } /* ------------------------------------------------------------ */ @Override public boolean isMimeTypeGzipable(String mimetype) { - return _mimeTypes.matches(mimetype); + return _mimeTypes.test(mimetype); } /* ------------------------------------------------------------ */ @@ -572,7 +572,7 @@ protected boolean isPathGzipable(String requestURI) if (requestURI == null) return true; - return _paths.matches(requestURI); + return _paths.test(requestURI); } /* ------------------------------------------------------------ */ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java index 710444d353af..8d095f19a066 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java @@ -19,8 +19,10 @@ package org.eclipse.jetty.util; import java.nio.ByteBuffer; +import java.util.AbstractMap; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; @@ -495,6 +497,39 @@ public Set keySet() 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> entrySet() + { + Set> entries = new HashSet<>(); + for (int r=0;r<=_rows;r++) + { + if (_key[r]!=null && _value[r]!=null) + entries.add(new AbstractMap.SimpleEntry<>(_key[r],_value[r])); + } + return entries; + } + @Override public boolean isFull() { @@ -524,4 +559,143 @@ public void dump() } } + + public static class Growing implements Trie + { + private final int _growby; + private ArrayTernaryTrie _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 bigger = new ArrayTernaryTrie<>(_trie._key.length+_growby); + for (Map.Entry 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 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(); + } + + } + } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExcludeSet.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExcludeSet.java index 622587f471d3..656b434d03e7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExcludeSet.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExcludeSet.java @@ -25,21 +25,21 @@ /** Utility class to maintain a set of inclusions and exclusions. - *

    Maintains a set of included and excluded elements. The method {@link #matches(Object)} + *

    Maintains a set of included and excluded elements. The method {@link #test(Object)} * will return true IFF the passed object is not in the excluded set AND ( either the * included set is empty OR the object is in the included set) *

    The type of the underlying {@link Set} used may be passed into the * constructor, so special sets like Servlet PathMap may be used. *

    - * @param

    The type of element of the set (often a pattern) - * @param The type of the instance passed to the predicate + * @param The type of element of the set (often a pattern) + * @param

    The type of the instance passed to the predicate */ -public class IncludeExcludeSet implements Predicate +public class IncludeExcludeSet implements Predicate

    { - private final Set

    _includes; - private final Predicate _includePredicate; - private final Set

    _excludes; - private final Predicate _excludePredicate; + private final Set _includes; + private final Predicate

    _includePredicate; + private final Set _excludes; + private final Predicate

    _excludePredicate; private static class SetContainsPredicate implements Predicate { @@ -73,7 +73,7 @@ public IncludeExcludeSet() * is created. * @param The type of a set to use as the backing store */ - public > IncludeExcludeSet(Class setClass) + public > IncludeExcludeSet(Class setClass) { try { @@ -82,7 +82,7 @@ public > IncludeExcludeSet(Class setClass) if(_includes instanceof Predicate) { - _includePredicate = (Predicate)_includes; + _includePredicate = (Predicate

    )_includes; } else { @@ -91,7 +91,7 @@ public > IncludeExcludeSet(Class setClass) if(_excludes instanceof Predicate) { - _excludePredicate = (Predicate)_excludes; + _excludePredicate = (Predicate

    )_excludes; } else { @@ -113,7 +113,7 @@ public > IncludeExcludeSet(Class setClass) * @param excludePredicate the Predicate for excluded item testing (null for simple {@link Set#contains(Object)} test) * @param The type of a set to use as the backing store */ - public > IncludeExcludeSet(Set

    includeSet, Predicate includePredicate, Set

    excludeSet, Predicate excludePredicate) + public > IncludeExcludeSet(Set includeSet, Predicate

    includePredicate, Set excludeSet, Predicate

    excludePredicate) { Objects.requireNonNull(includeSet,"Include Set"); Objects.requireNonNull(includePredicate,"Include Predicate"); @@ -126,51 +126,73 @@ public > IncludeExcludeSet(Set

    includeSet, Predicate in _excludePredicate = excludePredicate; } - public void include(P element) + public void include(T element) { _includes.add(element); } - public void include(P... element) + public void include(T... element) { - for (P e: element) + for (T e: element) _includes.add(e); } - public void exclude(P element) + public void exclude(T element) { _excludes.add(element); } - public void exclude(P... element) + public void exclude(T... element) { - for (P e: element) + for (T e: element) _excludes.add(e); } - - public boolean matches(T t) + + @Deprecated + public boolean matches(P t) { return test(t); } - public boolean test(T t) + @Override + public boolean test(P t) { if (!_includes.isEmpty() && !_includePredicate.test(t)) return false; return !_excludePredicate.test(t); } + /** + * Test Included and not Excluded + * @param t The item to test + * @return Boolean.TRUE if t is included, Boolean.FALSE if t is excluded and null if neither + */ + public Boolean isIncludedAndNotExcluded(P t) + { + if (_excludePredicate.test(t)) + return Boolean.FALSE; + if (_includePredicate.test(t)) + return Boolean.TRUE; + + return null; + } + + public boolean hasIncludes() + { + return !_includes.isEmpty(); + } + public int size() { return _includes.size()+_excludes.size(); } - public Set

    getIncluded() + public Set getIncluded() { return _includes; } - public Set

    getExcluded() + public Set getExcluded() { return _excludes; } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java index 1655f5529664..9eb355dafb98 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java @@ -29,7 +29,7 @@ public interface Trie { /* ------------------------------------------------------------ */ - /** Put and entry into the Trie + /** Put an entry into the Trie * @param s The key for the entry * @param v The value of the entry * @return True if the Trie had capacity to add the field. @@ -47,14 +47,14 @@ public interface Trie public V remove(String s); /* ------------------------------------------------------------ */ - /** Get and exact match from a String key + /** Get an exact match from a String key * @param s The key * @return the value for the string key */ public V get(String s); /* ------------------------------------------------------------ */ - /** Get and exact match from a String key + /** Get an exact match from a String key * @param s The key * @param offset The offset within the string of the key * @param len the length of the key @@ -63,14 +63,14 @@ public interface Trie public V get(String s,int offset,int len); /* ------------------------------------------------------------ */ - /** Get and exact match from a segment of a ByteBuufer as key + /** Get an exact match from a segment of a ByteBuufer as key * @param b The buffer * @return The value or null if not found */ public V get(ByteBuffer b); /* ------------------------------------------------------------ */ - /** Get and exact match from a segment of a ByteBuufer as key + /** Get an exact match from a segment of a ByteBuufer as key * @param b The buffer * @param offset The offset within the buffer of the key * @param len the length of the key diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 0173e55723df..31120dbf5e95 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -24,6 +24,9 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -31,9 +34,12 @@ import java.util.Map; import java.util.Objects; +import javax.servlet.ServletContainerInitializer; + import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; /* ------------------------------------------------------------ */ @@ -693,4 +699,38 @@ public static boolean isFalse(Object o) return !((Boolean)o).booleanValue(); return "false".equalsIgnoreCase(o.toString()); } + + /* ------------------------------------------------------------ */ + public static Resource getLoadedFrom(Class clazz) + { + ProtectionDomain domain = clazz.getProtectionDomain(); + if (domain!=null) + { + CodeSource source = domain.getCodeSource(); + if (source!=null) + { + URL location = source.getLocation(); + + if (location!=null) + return Resource.newResource(location); + } + } + + String rname = clazz.getName().replace('.','/')+".class"; + ClassLoader loader = clazz.getClassLoader(); + URL url = (loader==null?ClassLoader.getSystemClassLoader():loader).getResource(rname); + if (url!=null) + { + try + { + return Resource.newResource(URIUtil.getJarSource(url.toString())); + } + catch(Exception e) + { + LOG.debug(e); + } + } + + return null; + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java index 56652ea61470..742a69d31d75 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.util; import java.net.URI; +import java.net.URISyntaxException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; @@ -843,4 +844,30 @@ public static URI addDecodedPath(URI uri, String path) 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); + } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java index 5927218ab101..a7864326db05 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java @@ -32,7 +32,7 @@ public void testEmpty() IncludeExclude ie = new IncludeExclude<>(); assertThat("Empty IncludeExclude", ie.size(), is(0)); - assertThat("Matches 'foo'",ie.matches("foo"),is(true)); + assertThat("Matches 'foo'",ie.test("foo"),is(true)); } @Test @@ -43,10 +43,10 @@ public void testIncludeOnly() ie.include("bar"); assertThat("IncludeExclude.size", ie.size(), is(2)); - assertEquals(false,ie.matches("")); - assertEquals(true,ie.matches("foo")); - assertEquals(true,ie.matches("bar")); - assertEquals(false,ie.matches("foobar")); + assertEquals(false,ie.test("")); + assertEquals(true,ie.test("foo")); + assertEquals(true,ie.test("bar")); + assertEquals(false,ie.test("foobar")); } @Test @@ -58,11 +58,11 @@ public void testExcludeOnly() assertEquals(2,ie.size()); - assertEquals(false,ie.matches("foo")); - assertEquals(false,ie.matches("bar")); - assertEquals(true,ie.matches("")); - assertEquals(true,ie.matches("foobar")); - assertEquals(true,ie.matches("wibble")); + assertEquals(false,ie.test("foo")); + assertEquals(false,ie.test("bar")); + assertEquals(true,ie.test("")); + assertEquals(true,ie.test("foobar")); + assertEquals(true,ie.test("wibble")); } @Test @@ -76,11 +76,11 @@ public void testIncludeExclude() assertEquals(4,ie.size()); - assertEquals(true,ie.matches("foo")); - assertEquals(false,ie.matches("bar")); - assertEquals(false,ie.matches("")); - assertEquals(false,ie.matches("foobar")); - assertEquals(false,ie.matches("xxx")); + assertEquals(true,ie.test("foo")); + assertEquals(false,ie.test("bar")); + assertEquals(false,ie.test("")); + assertEquals(false,ie.test("foobar")); + assertEquals(false,ie.test("xxx")); } @@ -91,7 +91,7 @@ public void testEmptyRegex() IncludeExclude ie = new IncludeExclude<>(RegexSet.class); assertEquals(0,ie.size()); - assertEquals(true,ie.matches("foo")); + assertEquals(true,ie.test("foo")); } @Test @@ -102,13 +102,13 @@ public void testIncludeRegex() ie.include("b((ar)|(oo))"); assertEquals(2,ie.size()); - assertEquals(false,ie.matches("")); - assertEquals(true,ie.matches("foo")); - assertEquals(true,ie.matches("far")); - assertEquals(true,ie.matches("bar")); - assertEquals(true,ie.matches("boo")); - assertEquals(false,ie.matches("foobar")); - assertEquals(false,ie.matches("xxx")); + assertEquals(false,ie.test("")); + assertEquals(true,ie.test("foo")); + assertEquals(true,ie.test("far")); + assertEquals(true,ie.test("bar")); + assertEquals(true,ie.test("boo")); + assertEquals(false,ie.test("foobar")); + assertEquals(false,ie.test("xxx")); } @Test @@ -120,13 +120,13 @@ public void testExcludeRegex() assertEquals(2,ie.size()); - assertEquals(false,ie.matches("foo")); - assertEquals(false,ie.matches("far")); - assertEquals(false,ie.matches("bar")); - assertEquals(false,ie.matches("boo")); - assertEquals(true,ie.matches("")); - assertEquals(true,ie.matches("foobar")); - assertEquals(true,ie.matches("xxx")); + assertEquals(false,ie.test("foo")); + assertEquals(false,ie.test("far")); + assertEquals(false,ie.test("bar")); + assertEquals(false,ie.test("boo")); + assertEquals(true,ie.test("")); + assertEquals(true,ie.test("foobar")); + assertEquals(true,ie.test("xxx")); } @Test @@ -139,14 +139,14 @@ public void testIncludeExcludeRegex() ie.exclude("b((ar)|(oo))"); assertEquals(4,ie.size()); - assertEquals(false,ie.matches("foo")); - assertEquals(false,ie.matches("far")); - assertEquals(false,ie.matches("bar")); - assertEquals(false,ie.matches("boo")); - assertEquals(false,ie.matches("")); - assertEquals(false,ie.matches("xxx")); + assertEquals(false,ie.test("foo")); + assertEquals(false,ie.test("far")); + assertEquals(false,ie.test("bar")); + assertEquals(false,ie.test("boo")); + assertEquals(false,ie.test("")); + assertEquals(false,ie.test("xxx")); - assertEquals(true,ie.matches("foobar")); - assertEquals(true,ie.matches("Ant")); + assertEquals(true,ie.test("foobar")); + assertEquals(true,ie.test("Ant")); } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java index 84ecb6264806..78707bc93120 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.util; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; @@ -119,4 +120,12 @@ public void testIsFalse() throws Exception Assert.assertFalse(TypeUtil.isFalse("blargle")); Assert.assertFalse(TypeUtil.isFalse(new Object(){@Override public String toString(){return "true";}})); } + + @Test + public void testLoadedFrom() throws Exception + { + Assert.assertThat(TypeUtil.getLoadedFrom(String.class).toString(),Matchers.containsString("/rt.jar")); + Assert.assertThat(TypeUtil.getLoadedFrom(Assert.class).toString(),Matchers.containsString(".jar")); + Assert.assertThat(TypeUtil.getLoadedFrom(TypeUtil.class).toString(),Matchers.containsString("/classes/")); + } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java index 219095849743..d0e1f66f66df 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java @@ -18,12 +18,17 @@ package org.eclipse.jetty.util; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.net.URI; import java.nio.charset.StandardCharsets; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Test; @@ -286,4 +291,15 @@ public void testCanonicalPath() } + /* ------------------------------------------------------------ */ + @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"))); + } } diff --git a/jetty-webapp/src/main/config/etc/jetty-webapp.xml b/jetty-webapp/src/main/config/etc/jetty-webapp.xml new file mode 100644 index 000000000000..1f8e737e9bf9 --- /dev/null +++ b/jetty-webapp/src/main/config/etc/jetty-webapp.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-webapp/src/main/config/modules/webapp.mod b/jetty-webapp/src/main/config/modules/webapp.mod index c753f8d761e5..fe1a13d8972b 100644 --- a/jetty-webapp/src/main/config/modules/webapp.mod +++ b/jetty-webapp/src/main/config/modules/webapp.mod @@ -6,5 +6,23 @@ classpath. Without this, only Jetty specific handlers may be deployed. servlet security +[xml] +etc/jetty-webapp.xml + [lib] lib/jetty-webapp-${jetty.version}.jar + + +[ini-template] +## Add to the server wide default jars and packages protected or hidden from webapps. +## System classes are protected and cannot be overridden by a webapp. +## Server classes are hidden and cannot be seen by a webapp +## Lists of patterns are comma separated and may be either: +## + a qualified classname e.g. 'com.acme.Foo' +## + a package name e.g. 'net.example.' +## + a jar file e.g. 'file:${jetty.base}/lib/dependency.jar' +## + a directory of jars,resource or classes e.g. 'file:${jetty.base}/resources' +## + A pattern preceeded with a '-' is an exclusion, all other patterns are inclusions +## +#jetty.webapp.addSystemClasses= +#jetty.webapp.addServerClasses= diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java index a1f564e8e4d6..32ed9526aada 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java @@ -19,13 +19,30 @@ 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.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; 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 @@ * in this string should be separated by ':' (semicolon) or ',' (comma). */ -public class ClasspathPattern extends AbstractList +public class ClasspathPattern extends AbstractSet { + private static final Logger LOG = Log.getLogger(ClasspathPattern.class); + + enum Type { PACKAGE, CLASSNAME, LOCATION } + private static class Entry { - public final String _pattern; - public final String _name; - public final boolean _inclusive; - public final boolean _package; + private final String _pattern; + private final String _name; + private final boolean _inclusive; + private final Type _type; Entry(String pattern) { _pattern=pattern; _inclusive = !pattern.startsWith("-"); - _package = pattern.endsWith("."); _name = _inclusive ? pattern : pattern.substring(1).trim(); + _type = (_name.startsWith("file:"))?Type.LOCATION:(_name.endsWith(".")?Type.PACKAGE:Type.CLASSNAME); + } + + 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 @@ -67,86 +122,356 @@ public String toString() { 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 _entries = new ArrayList(); - /* ------------------------------------------------------------ */ + public static class ByPackage extends AbstractSet implements Predicate + { + private final ArrayTernaryTrie.Growing _entries = new ArrayTernaryTrie.Growing<>(false,512,512); + + @Override + public boolean test(String name) + { + return _entries.getBest(name)!=null; + } + + @Override + public Iterator 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 implements Predicate + { + private final Map _entries = new HashMap<>(); + + @Override + public boolean test(String name) + { + return _entries.containsKey(name); + } + + @Override + public Iterator 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 implements Predicate + { + 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 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 implements Predicate + { + @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 _entries = new HashMap<>(); + Set _classes = new HashSet<>(); + + IncludeExcludeSet _patterns = new IncludeExcludeSet<>(ByPackageOrName.class); + IncludeExcludeSet _locations = new IncludeExcludeSet<>(ByLocation.class); + public ClasspathPattern() { } - /* ------------------------------------------------------------ */ public ClasspathPattern(String[] patterns) { setAll(patterns); } - /* ------------------------------------------------------------ */ public ClasspathPattern(String pattern) { add(pattern); } - /* ------------------------------------------------------------ */ - @Override - public String get(int index) + public boolean include(String name) { - return _entries.get(index)._pattern; + if (name==null) + return false; + return add(new Entry(name,true)); } - - /* ------------------------------------------------------------ */ - @Override - public String set(int index, String element) + + public boolean include(String... name) { - Entry e = _entries.set(index,new Entry(element)); - return e==null?null:e._pattern; + boolean added = false; + for (String n:name) + if (n!=null) + added = add(new Entry(n,true)) || added; + return added; } - - /* ------------------------------------------------------------ */ - @Override - public void add(int index, String element) + + public boolean exclude(String name) { - _entries.add(index,new Entry(element)); + if (name==null) + return false; + return add(new Entry(name,false)); } - - /* ------------------------------------------------------------ */ - @Deprecated - public void addPattern(String element) + + public boolean exclude(String... name) { - add(element); + boolean added = false; + for (String n:name) + if (n!=null) + added = add(new Entry(n,false)) || added; + return added; } - /* ------------------------------------------------------------ */ @Override - public String remove(int index) + public boolean add(String pattern) + { + if (pattern==null) + return false; + return add(new Entry(pattern)); + } + + public boolean add(String... pattern) { - Entry e = _entries.remove(index); - return e==null?null:e._pattern; + boolean added = false; + for (String p:pattern) + if (p!=null) + added = add(new Entry(p)) || added; + return added; } - /* ------------------------------------------------------------ */ - public boolean remove(String pattern) + protected boolean add(Entry entry) { - for (int i=_entries.size();i-->0;) + 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); - return true; + File file = Resource.newResource(entry.getName()).getFile().getAbsoluteFile().getCanonicalFile(); + if (entry.isInclusive()) + _locations.include(file); + else + _locations.exclude(file); + } + catch (Exception e) + { + throw new IllegalArgumentException(e); } } - 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 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 iterator() + { + return _entries.keySet().iterator(); } - /* ------------------------------------------------------------ */ @Override public int size() { return _entries.size(); } - /* ------------------------------------------------------------ */ /** * Initialize the matcher by parsing each classpath pattern in an array * @@ -158,7 +483,6 @@ private void setAll(String[] classes) addAll(classes); } - /* ------------------------------------------------------------ */ /** * @param classes array of classpath patterns */ @@ -168,30 +492,6 @@ private void addAll(String[] 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 */ @@ -200,89 +500,75 @@ public String[] getPatterns() return toArray(new String[_entries.size()]); } - /* ------------------------------------------------------------ */ + /** - * @return List of classes excluded class exclusions and package patterns + * Match the class name against the pattern + * + * @param name name of the class to match + * @return true if class matches the pattern */ - public List getClasses() - { - List list = new ArrayList<>(); - for (Entry e:_entries) - { - if (e._inclusive && !e._package) - list.add(e._name); - } - return list; + public boolean match(String name) + { + return _patterns.test(name); } - /* ------------------------------------------------------------ */ /** * Match the class name against the pattern * - * @param name name of the class to match + * @param clazz A class to try to match * @return true if class matches the pattern */ - public boolean match(String name) + public boolean match(Class clazz) { - name = name.replace('/','.'); - - for (Entry entry : _entries) + try { - if (entry==null) - continue; - if (entry._package) - { - if (name.startsWith(entry._name) || ".".equals(entry._pattern)) - return entry._inclusive; - } - else - { - if (name.equals(entry._name)) - return entry._inclusive; - - if (name.length()>entry._name.length() && '$'==name.charAt(entry._name.length()) && name.startsWith(entry._name)) - return entry._inclusive; - } + Resource resource = TypeUtil.getLoadedFrom(clazz); + Path path = resource.getFile().toPath(); + + Boolean byName = _patterns.isIncludedAndNotExcluded(clazz.getName()); + Boolean byLocation = _locations.isIncludedAndNotExcluded(path); + + // Combine the tri-state match of both IncludeExclude Sets + boolean included = byName==TRUE || byLocation==TRUE + || (byName==null && !_patterns.hasIncludes() && byLocation==null && !_locations.hasIncludes()); + boolean excluded = byName==FALSE || byLocation==FALSE; + return included && !excluded; + } + catch (Exception e) + { + LOG.warn(e); } return false; } - public 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")) + name=name.substring(0,name.length()-6); + + // Treat path elements as packages for name matching + name=name.replace("/","."); + + Boolean byName = _patterns.isIncludedAndNotExcluded(name); + + // Try to find a file path for location matching + Boolean byLocation = null; + try { - ListIterator iter = listIterator(); - while (iter.hasNext()) - { - String cc=iter.next(); - if (afterPattern.equals(cc)) - { - for (int i=0;i iter = listIterator(); - while (iter.hasNext()) - { - String cc=iter.next(); - if (beforePattern.equals(cc)) - { - iter.previous(); - for (int i=0;i clazz); /* ------------------------------------------------------------ */ /** Is the class a Server Class. @@ -122,7 +121,7 @@ public interface Context * @param clazz The fully qualified name of the class. * @return True if the class is a server class. */ - boolean isServerClass(String clazz); + boolean isServerClass(Class clazz); /* ------------------------------------------------------------ */ /** @@ -135,6 +134,10 @@ public interface Context /* ------------------------------------------------------------ */ String getExtraClasspath(); + + boolean isServerResource(String name, URL parent_url); + + boolean isSystemResource(String name, URL webapp_url); } @@ -142,9 +145,10 @@ public interface Context /** Run an action with access to ServerClasses *

    Run the passed {@link PrivilegedExceptionAction} with the classloader * configured so as to allow server classes to be visible

    + * @param The type returned by the action * @param action The action to run * @return The return from the action - * @throws Exception + * @throws Exception if thrown by the action */ public static T runWithServerClassAccess(PrivilegedExceptionAction action) throws Exception { @@ -361,27 +365,42 @@ public PermissionCollection getPermissions(CodeSource cs) @Override public Enumeration getResources(String name) throws IOException { - boolean system_class=_context.isSystemClass(name); - boolean server_class=_context.isServerClass(name) && !Boolean.TRUE.equals(__loadServerClasses.get()); + List from_parent = new ArrayList<>(); + List from_webapp = new ArrayList<>(); + + Enumeration 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 resources; - List from_parent = toList(server_class?null:_parent.getResources(name)); - List from_webapp = toList((system_class&&!from_parent.isEmpty())?null:this.findResources(name)); - if (_context.isParentLoaderPriority()) { from_parent.addAll(from_webapp); - return Collections.enumeration(from_parent); + resources = from_parent; } - from_webapp.addAll(from_parent); - return Collections.enumeration(from_webapp); - } + else + { + from_webapp.addAll(from_parent); + resources = from_webapp; + } + + if (LOG.isDebugEnabled()) + LOG.debug("getResources {} {}",name,resources); - /* ------------------------------------------------------------ */ - private List toList(Enumeration e) - { - if (e==null) - return new ArrayList(); - return Collections.list(e); + return Collections.enumeration(resources); } /* ------------------------------------------------------------ */ @@ -395,138 +414,180 @@ private List toList(Enumeration e) @Override public URL getResource(String name) { - URL url= null; - boolean tried_parent= false; - - //If the resource is a class name with .class suffix, strip it off before comparison - //as the server and system patterns are specified without a .class suffix - String tmp = name; - if (tmp != null && tmp.endsWith(".class")) - tmp = tmp.substring(0, tmp.length()-6); - - boolean system_class=_context.isSystemClass(tmp); - boolean server_class=_context.isServerClass(tmp) && !Boolean.TRUE.equals(__loadServerClasses.get()); - - if (LOG.isDebugEnabled()) - LOG.debug("getResource({}) system={} server={} cl={}",name,system_class,server_class,this); - - if (system_class && server_class) - return null; - - ClassLoader source=null; - - if (_parent!=null &&(_context.isParentLoaderPriority() || system_class ) && !server_class) + URL resource=null; + if (_context.isParentLoaderPriority()) { - tried_parent= true; + URL parent_url=_parent.getResource(name); - if (_parent!=null) + // return if we have a url the webapp is allowed to see + if (parent_url!=null + && (Boolean.TRUE.equals(__loadServerClasses.get()) + || !_context.isServerResource(name,parent_url))) + resource = parent_url; + else { - source=_parent; - url=_parent.getResource(name); + URL webapp_url = this.findResource(name); + + // If found here then OK to use regardless of system or server classes + // If it is a system resource, we've already tried to load from parent, so + // would have returned it. + // If it is a server resource, doesn't matter as we have loaded it from the + // webapp + if (webapp_url!=null) + resource = webapp_url; } } - - if (url == null) + else { - url= this.findResource(name); - source=this; - if (url == null && name.startsWith("/")) - url= this.findResource(name.substring(1)); - } + URL webapp_url = this.findResource(name); - if (url == null && !tried_parent && !server_class ) - { - if (_parent!=null) + if (webapp_url!=null && !_context.isSystemResource(name,webapp_url)) + resource = webapp_url; + else { - tried_parent=true; - source=_parent; - url= _parent.getResource(name); + + // Couldn't find or see a webapp resource, so try a parent + URL parent_url=_parent.getResource(name); + if (parent_url!=null + && (Boolean.TRUE.equals(__loadServerClasses.get()) + || !_context.isServerResource(name,parent_url))) + resource = parent_url; + // We couldn't find a parent resource, so OK to return a webapp one if it exists + // and we just couldn't see it before + else if (webapp_url!=null) + resource = webapp_url; } } + + // Perhaps this failed due to leading / + if (resource==null && name.startsWith("/")) + resource = getResource(name.substring(1)); if (LOG.isDebugEnabled()) - LOG.debug("gotResource({})=={} from={} tried_parent={}",name,url,source,tried_parent); - - return url; + LOG.debug("getResource {} {}",name,resource); + + return resource; + } /* ------------------------------------------------------------ */ @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + LOG.setDebugEnabled(true); + WebAppContext.LOG.setDebugEnabled(true); + synchronized (getClassLoadingLock(name)) - { - Class c= findLoadedClass(name); + { ClassNotFoundException ex= null; - boolean tried_parent= false; - - boolean system_class=_context.isSystemClass(name); - boolean server_class=_context.isServerClass(name) && !Boolean.TRUE.equals(__loadServerClasses.get()); - - if (LOG.isDebugEnabled()) - LOG.debug("loadClass({}) system={} server={} cl={}",name,system_class,server_class,this); + Class parent_class = null; + Class webapp_class = null; - ClassLoader source=null; - - if (system_class && server_class) + // Has this loader loaded the class already? + webapp_class = findLoadedClass(name); + if (webapp_class != null) { - return null; + if (LOG.isDebugEnabled()) + LOG.debug("found webapp loaded {}",webapp_class); + return webapp_class; } - - if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class) + + // Should we try the parent loader first? + if (_context.isParentLoaderPriority()) { - tried_parent= true; - source=_parent; + // Try the parent loader try { - c= _parent.loadClass(name); - if (LOG.isDebugEnabled()) - LOG.debug("loaded " + c); + 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) { - ex= e; + // Save it for later + ex = e; } - } - - if (c == null) - { + + // Try the webapp loader try { - source=this; - c= this.findClass(name); + // 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) { - ex= e; + if (ex==null) + ex = e; + else + ex.addSuppressed(e); } + + throw ex; } - - if (c == null && _parent!=null && !tried_parent && !server_class ) + else { - tried_parent=true; - source=_parent; - c= _parent.loadClass(name); - } + // Not parent loader priority, so... - if (c == null && ex!=null) - { - if (LOG.isDebugEnabled()) - LOG.debug("!loadedClass({}) from={} tried_parent={}",name,this,tried_parent); - throw ex; - } + // 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; + } - if (LOG.isDebugEnabled()) - LOG.debug("loadedClass({})=={} from={} tried_parent={}",name,c,source,tried_parent); - - if (resolve) - { - resolveClass(c); - if (LOG.isDebugEnabled()) - LOG.debug("resolved({})=={} from={} tried_parent={}",name,c,source,tried_parent); - } + // 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; + } - return c; + // 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 boolean removeTransformer(ClassFileTransformer transformer) { return _transformers.remove(transformer); } - - + /* ------------------------------------------------------------ */ @Override protected Class findClass(final String name) throws ClassNotFoundException { - Class clazz=null; + if (_transformers.isEmpty()) + return super.findClass(name); + String path = name.replace('.', '/').concat(".class"); + URL url = findResource(path); + if (url==null) + throw new ClassNotFoundException(name); + return foundClass(name,url); + } + + /* ------------------------------------------------------------ */ + protected Class foundClass(final String name, URL url) throws ClassNotFoundException + { if (_transformers.isEmpty()) - clazz = super.findClass(name); - else + return super.findClass(name); + + InputStream content=null; + try { - String path = name.replace('.', '/').concat(".class"); - URL url = getResource(path); - if (url==null) - throw new ClassNotFoundException(name); + content = url.openStream(); + byte[] bytes = IO.readBytes(content); - InputStream content=null; - try - { - content = url.openStream(); - byte[] bytes = IO.readBytes(content); + if (LOG.isDebugEnabled()) + LOG.debug("foundClass({}) url={} cl={}",name,url,this); - if (LOG.isDebugEnabled()) - LOG.debug("foundClass({}) url={} cl={}",name,url,this); - - for (ClassFileTransformer transformer : _transformers) - { - byte[] tmp = transformer.transform(this,name,null,null,bytes); - if (tmp != null) - bytes = tmp; - } - - clazz=defineClass(name,bytes,0,bytes.length); - } - catch (IOException e) - { - throw new ClassNotFoundException(name,e); - } - catch (IllegalClassFormatException e) + for (ClassFileTransformer transformer : _transformers) { - throw new ClassNotFoundException(name,e); + byte[] tmp = transformer.transform(this,name,null,null,bytes); + if (tmp != null) + bytes = tmp; } - finally + + return defineClass(name,bytes,0,bytes.length); + } + catch (IOException e) + { + throw new ClassNotFoundException(name,e); + } + catch (IllegalClassFormatException e) + { + throw new ClassNotFoundException(name,e); + } + finally + { + if (content!=null) { - if (content!=null) + try { - try - { - content.close(); - } - catch (IOException e) - { - throw new ClassNotFoundException(name,e); - } + content.close(); + } + catch (IOException e) + { + throw new ClassNotFoundException(name,e); } } } - - return clazz; } + - + /* ------------------------------------------------------------ */ @Override public void close() throws IOException { @@ -639,4 +702,5 @@ public String toString() { return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode()); } + } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index c29098d49c89..3ca0e2aa7298 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -24,7 +24,6 @@ import java.net.URL; import java.net.URLClassLoader; import java.security.PermissionCollection; -import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -35,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.Callable; import javax.servlet.ServletContext; import javax.servlet.ServletRegistration.Dynamic; @@ -63,6 +61,7 @@ import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.MultiException; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -87,7 +86,7 @@ @ManagedObject("Web Application ContextHandler") public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context { - private static final Logger LOG = Log.getLogger(WebAppContext.class); + static final Logger LOG = Log.getLogger(WebAppContext.class); public static final String TEMPDIR = "javax.servlet.context.tempdir"; public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir"; @@ -131,12 +130,30 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL "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 // loaded by the web application using system classloader, // so if web application needs to load any of such classes, // it has to include them in its distribution. // TODO This centrally managed list of features that are exposed/hidden needs to be replaced // with a more automatic distributed mechanism + // TODO should be white list rather than black list public final static String[] __dftServerClasses = { "-org.eclipse.jetty.server.session.SessionData", //don't hide SessionData for de/serialization purposes @@ -666,21 +683,25 @@ public String[] getServerClasses() } /* ------------------------------------------------------------ */ - /** Add to the list of Server classes. - * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) - * or a qualified package name ending with '.' (eg com.foo.). If the class - * or package has '-' it is excluded from the server classes 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 Jetty Documentation: Classloading + /** + * @return The ClasspathPattern used to match Server (hidden) classes */ - public void addServerClass(String classOrPackage) + public ClasspathPattern getServerClasspathPattern() { if (_serverClasses == null) loadServerClasses(); - _serverClasses.add(classOrPackage); + return _serverClasses; + } + + /* ------------------------------------------------------------ */ + @Deprecated + public void addServerClass(String classOrPackageOrLocation) + { + if (_serverClasses == null) + loadServerClasses(); + + _serverClasses.add(classOrPackageOrLocation); } /* ------------------------------------------------------------ */ @@ -693,12 +714,13 @@ public void addServerClass(String classOrPackage) * @see #setServerClasses(String[]) * @see Jetty Documentation: Classloading */ + @Deprecated public void prependServerClass(String classOrPackage) { if (_serverClasses == null) loadServerClasses(); - _serverClasses.prependPattern(classOrPackage); + _serverClasses.add(classOrPackage); } /* ------------------------------------------------------------ */ @@ -714,17 +736,21 @@ public String[] getSystemClasses() return _systemClasses.getPatterns(); } - + /* ------------------------------------------------------------ */ - /** Add to the list of System classes. - * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) - * or a qualified package name ending with '.' (eg com.foo.). If the class - * or package has '-' it is excluded from the system classes 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 Jetty Documentation: Classloading + /** + * @return The ClasspathPattern used to match System (protected) classes */ + public ClasspathPattern getSystemClasspathPattern() + { + if (_systemClasses == null) + loadSystemClasses(); + + return _systemClasses; + } + + /* ------------------------------------------------------------ */ + @Deprecated public void addSystemClass(String classOrPackage) { if (_systemClasses == null) @@ -744,16 +770,17 @@ public void addSystemClass(String classOrPackage) * @see #setSystemClasses(String[]) * @see Jetty Documentation: Classloading */ + @Deprecated public void prependSystemClass(String classOrPackage) { if (_systemClasses == null) loadSystemClasses(); - _systemClasses.prependPattern(classOrPackage); + _systemClasses.add(classOrPackage); } /* ------------------------------------------------------------ */ - @Override + @Deprecated public boolean isServerClass(String name) { if (_serverClasses == null) @@ -763,7 +790,7 @@ public boolean isServerClass(String name) } /* ------------------------------------------------------------ */ - @Override + @Deprecated public boolean isSystemClass(String name) { if (_systemClasses == null) @@ -771,6 +798,58 @@ public boolean isSystemClass(String 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() @@ -784,8 +863,10 @@ protected void loadSystemClasses() if (server != null) { Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES); - if (systemClasses != null && systemClasses instanceof String[]) + if (systemClasses instanceof String[]) _systemClasses = new ClasspathPattern((String[])systemClasses); + else if (systemClasses instanceof ClasspathPattern) + _systemClasses = new ClasspathPattern(((ClasspathPattern)systemClasses).getPatterns()); } if (_systemClasses == null) @@ -793,7 +874,7 @@ protected void loadSystemClasses() } /* ------------------------------------------------------------ */ - private void loadServerClasses() + protected void loadServerClasses() { if (_serverClasses != null) { @@ -806,10 +887,10 @@ private void loadServerClasses() if (server != null) { Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES); - if (serverClasses != null && serverClasses instanceof String[]) - { + if (serverClasses instanceof String[]) _serverClasses = new ClasspathPattern((String[])serverClasses); - } + else if (serverClasses instanceof ClasspathPattern) + _serverClasses = new ClasspathPattern(((ClasspathPattern)serverClasses).getPatterns()); } if (_serverClasses == null) @@ -949,10 +1030,24 @@ public String toString() @Override public void dump(Appendable out, String indent) throws IOException { + List system_classes=null; + if (_systemClasses!=null) + { + system_classes=new ArrayList<>(_systemClasses); + Collections.sort(system_classes); + } + + List server_classes=null; + if (_serverClasses!=null) + { + server_classes=new ArrayList<>(_serverClasses); + Collections.sort(server_classes); + } + dumpBeans(out,indent, Collections.singletonList(new ClassLoaderDump(getClassLoader())), - Collections.singletonList(new DumpableCollection("Systemclasses "+this,_systemClasses)), - Collections.singletonList(new DumpableCollection("Serverclasses "+this,_serverClasses)), + Collections.singletonList(new DumpableCollection("Systemclasses "+this,system_classes)), + Collections.singletonList(new DumpableCollection("Serverclasses "+this,server_classes)), Collections.singletonList(new DumpableCollection("Configurations "+this,_configurations)), Collections.singletonList(new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet())), Collections.singletonList(new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet())), @@ -1478,7 +1573,7 @@ public void checkListener(Class listener) throws Illega { //not one of the standard servlet listeners, check our extended session listener types boolean ok = false; - for (Class l:SessionHandler.SESSION_LISTENER_TYPES) + for (Class l:SessionHandler.SESSION_LISTENER_TYPES) { if (l.isAssignableFrom(listener)) { @@ -1506,11 +1601,11 @@ public URL getResource(String path) throws MalformedURLException for (int i=resources.length;i-->0;) { if (resources[i].getName().startsWith("jar:file")) - return resources[i].getURL(); + return resources[i].getURI().toURL(); } } - return resource.getURL(); + return resource.getURI().toURL(); } /* ------------------------------------------------------------ */ @@ -1536,7 +1631,6 @@ public ServletContext getContext(String uripath) return servletContext; } } - } /* ------------------------------------------------------------ */ @@ -1544,4 +1638,53 @@ public MetaData getMetaData() { 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); + } + } diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java index 2091ffc0d563..cde8c4edfc9a 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java @@ -18,101 +18,214 @@ package org.eclipse.jetty.webapp; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.Arrays; +import org.eclipse.jetty.toolchain.test.JDK; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.resource.Resource; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import sun.security.provider.Sun; + public class ClasspathPatternTest { - private final ClasspathPattern pattern = new ClasspathPattern(); + private final ClasspathPattern _pattern = new ClasspathPattern(); @Before public void before() { - pattern.clear(); - pattern.add("org.package."); - pattern.add("-org.excluded."); - pattern.add("org.example.FooBar"); - pattern.add("-org.example.Excluded"); - pattern.addAll(Arrays.asList(new String[]{"-org.example.Nested$Minus","org.example.Nested","org.example.Nested$Something"})); + _pattern.clear(); + _pattern.add("org.package."); + _pattern.add("-org.excluded."); + _pattern.add("org.example.FooBar"); + _pattern.add("-org.example.Excluded"); + _pattern.addAll(Arrays.asList(new String[]{ + "-org.example.Nested$Minus", + "org.example.Nested", + "org.example.Nested$Something"})); + + + assertThat(_pattern,containsInAnyOrder( + "org.package.", + "-org.excluded.", + "org.example.FooBar", + "-org.example.Excluded", + "-org.example.Nested$Minus", + "org.example.Nested", + "org.example.Nested$Something" + )); } + @Test public void testClassMatch() { - assertTrue(pattern.match("org.example.FooBar")); - assertTrue(pattern.match("org.example.Nested")); + assertTrue(_pattern.match("org.example.FooBar")); + assertTrue(_pattern.match("org.example.Nested")); - assertFalse(pattern.match("org.example.Unknown")); - assertFalse(pattern.match("org.example.FooBar.Unknown")); + assertFalse(_pattern.match("org.example.Unknown")); + assertFalse(_pattern.match("org.example.FooBar.Unknown")); } @Test public void testPackageMatch() { - assertTrue(pattern.match("org.package.Something")); - assertTrue(pattern.match("org.package.other.Something")); + assertTrue(_pattern.match("org.package.Something")); + assertTrue(_pattern.match("org.package.other.Something")); - assertFalse(pattern.match("org.example.Unknown")); - assertFalse(pattern.match("org.example.FooBar.Unknown")); - assertFalse(pattern.match("org.example.FooBarElse")); + assertFalse(_pattern.match("org.example.Unknown")); + assertFalse(_pattern.match("org.example.FooBar.Unknown")); + assertFalse(_pattern.match("org.example.FooBarElse")); } @Test public void testExplicitNestedMatch() { - assertTrue(pattern.match("org.example.Nested$Something")); - assertFalse(pattern.match("org.example.Nested$Minus")); - assertTrue(pattern.match("org.example.Nested$Other")); + assertTrue(_pattern.match("org.example.Nested$Something")); + assertFalse(_pattern.match("org.example.Nested$Minus")); + assertTrue(_pattern.match("org.example.Nested$Other")); } @Test public void testImplicitNestedMatch() { - assertTrue(pattern.match("org.example.FooBar$Other")); - assertTrue(pattern.match("org.example.Nested$Other")); + assertTrue(_pattern.match("org.example.FooBar$Other")); + assertTrue(_pattern.match("org.example.Nested$Other")); } @Test - public void testAddBefore() + public void testDoubledNested() { - pattern.addBefore("-org.excluded.","org.excluded.ExceptionOne","org.excluded.ExceptionTwo"); - - assertTrue(pattern.match("org.excluded.ExceptionOne")); - assertTrue(pattern.match("org.excluded.ExceptionTwo")); + assertTrue(_pattern.match("org.example.Nested$Something$Else")); - assertFalse(pattern.match("org.example.Unknown")); + assertFalse(_pattern.match("org.example.Nested$Minus$Else")); } - + @Test - public void testAddAfter() + public void testMatchAll() { - 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")); + _pattern.clear(); + _pattern.add("."); + assertTrue(_pattern.match("org.example.Anything")); + assertTrue(_pattern.match("org.example.Anything$Else")); } + /** + * + */ + @SuppressWarnings("restriction") @Test - public void testDoubledNested() + public void testiIncludedLocations() throws Exception { - assertTrue(pattern.match("org.example.Nested$Something$Else")); + // jar from JVM classloader + Resource loc_string = TypeUtil.getLoadedFrom(String.class); + // System.err.println(loc_string); - assertFalse(pattern.match("org.example.Nested$Minus$Else")); - } + // 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 testMatchAll() + public void testExcludeLocations() throws Exception { - pattern.clear(); - pattern.add("."); - assertTrue(pattern.match("org.example.Anything")); - assertTrue(pattern.match("org.example.Anything$Else")); + // 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)); } } diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java index 373c7464b4fb..93e991f054cc 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java @@ -56,8 +56,6 @@ public void init() throws Exception this.testWebappDir = MavenTestingUtils.getProjectDirPath("src/test/webapp"); Resource webapp = new PathResource(testWebappDir); - System.err.printf("testWebappDir = %s%n", testWebappDir); - _context = new WebAppContext(); _context.setBaseResource(webapp); _context.setContextPath("/test"); @@ -66,6 +64,9 @@ public void init() throws Exception _loader.addJars(webapp.addPath("WEB-INF/lib")); _loader.addClassPath(webapp.addPath("WEB-INF/classes")); _loader.setName("test"); + + _context.loadSystemClasses(); + _context.loadServerClasses(); } public void assertCanLoadClass(String clazz) throws ClassNotFoundException @@ -250,7 +251,7 @@ public void testResources() throws Exception URL targetTestClasses = this.getClass().getClassLoader().getResource("org/acme/resource.txt"); _context.setParentLoaderPriority(false); - dump(_context); + resources =Collections.list(_loader.getResources("org/acme/resource.txt")); expected.clear(); @@ -260,12 +261,6 @@ public void testResources() throws Exception assertThat("Resources Found (Parent Loader Priority == false)",resources,ordered(expected)); -// dump(resources); -// assertEquals(3,resources.size()); -// assertEquals(0,resources.get(0).toString().indexOf("jar:file:")); -// assertEquals(-1,resources.get(1).toString().indexOf("test-classes")); -// assertEquals(0,resources.get(2).toString().indexOf("file:")); - _context.setParentLoaderPriority(true); // dump(_context); resources =Collections.list(_loader.getResources("org/acme/resource.txt")); @@ -320,49 +315,6 @@ public void testResources() throws Exception 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 resources) - { - System.err.println("--Dump--"); - for(URL url: resources) - { - System.err.printf(" \"%s\"%n",url); - } - } }