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 a65c06fca16..721ffa223d6 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 @@ -344,8 +344,6 @@ public class AnnotationConfiguration extends AbstractConfiguration { context.getObjectFactory().addDecorator(new AnnotationDecorator(context)); - //Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any - if (!context.getMetaData().isMetaDataComplete()) { //If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java index f4d77cd06db..d8cdded1035 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.annotations; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import java.io.File; import java.net.URL; @@ -38,6 +40,76 @@ import org.junit.Test; */ public class TestAnnotationConfiguration { + + public class TestableAnnotationConfiguration extends AnnotationConfiguration + { + public void assertAnnotationDiscovery (boolean b) + { + + if (!b) + assertTrue(_discoverableAnnotationHandlers.isEmpty()); + else + assertFalse(_discoverableAnnotationHandlers.isEmpty()); + } + } + + + @Test + public void testAnnotationScanControl() throws Exception + { + File web25 = MavenTestingUtils.getTestResourceFile("web25.xml"); + File web31 = MavenTestingUtils.getTestResourceFile("web31.xml"); + File web31false = MavenTestingUtils.getTestResourceFile("web31false.xml"); + + + //check that a 2.5 webapp won't discover annotations + TestableAnnotationConfiguration config25 = new TestableAnnotationConfiguration(); + WebAppContext context25 = new WebAppContext(); + context25.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE); + context25.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); + context25.getMetaData().setWebXml(Resource.newResource(web25)); + context25.getServletContext().setEffectiveMajorVersion(2); + context25.getServletContext().setEffectiveMinorVersion(5); + config25.configure(context25); + config25.assertAnnotationDiscovery(false); + + //check that a 2.5 webapp with configurationDiscovered will discover annotations + TestableAnnotationConfiguration config25b = new TestableAnnotationConfiguration(); + WebAppContext context25b = new WebAppContext(); + context25b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE); + context25b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); + context25b.setConfigurationDiscovered(true); + context25b.getMetaData().setWebXml(Resource.newResource(web25)); + context25b.getServletContext().setEffectiveMajorVersion(2); + context25b.getServletContext().setEffectiveMinorVersion(5); + config25b.configure(context25b); + config25b.assertAnnotationDiscovery(true); + + //check that a 3.x webapp with metadata true won't discover annotations + TestableAnnotationConfiguration config31 = new TestableAnnotationConfiguration(); + WebAppContext context31 = new WebAppContext(); + context31.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE); + context31.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); + context31.getMetaData().setWebXml(Resource.newResource(web31)); + context31.getServletContext().setEffectiveMajorVersion(3); + context31.getServletContext().setEffectiveMinorVersion(1); + config31.configure(context31); + config31.assertAnnotationDiscovery(false); + + //check that a 3.x webapp with metadata false will discover annotations + TestableAnnotationConfiguration config31b = new TestableAnnotationConfiguration(); + WebAppContext context31b = new WebAppContext(); + context31b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE); + context31b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); + context31b.getMetaData().setWebXml(Resource.newResource(web31false)); + context31b.getServletContext().setEffectiveMajorVersion(3); + context31b.getServletContext().setEffectiveMinorVersion(1); + config31b.configure(context31b); + config31b.assertAnnotationDiscovery(true); + } + + + @Test public void testGetFragmentFromJar() throws Exception { diff --git a/jetty-annotations/src/test/resources/web25.xml b/jetty-annotations/src/test/resources/web25.xml new file mode 100644 index 00000000000..da2e65b6007 --- /dev/null +++ b/jetty-annotations/src/test/resources/web25.xml @@ -0,0 +1,10 @@ + + + + Test 2.5 WebApp + + diff --git a/jetty-annotations/src/test/resources/web31.xml b/jetty-annotations/src/test/resources/web31.xml new file mode 100644 index 00000000000..e44571a8a20 --- /dev/null +++ b/jetty-annotations/src/test/resources/web31.xml @@ -0,0 +1,11 @@ + + + + Test 31 WebApp + + diff --git a/jetty-annotations/src/test/resources/web31false.xml b/jetty-annotations/src/test/resources/web31false.xml new file mode 100644 index 00000000000..a2307a7560b --- /dev/null +++ b/jetty-annotations/src/test/resources/web31false.xml @@ -0,0 +1,11 @@ + + + + Test 31 WebApp + + diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java index e747068dd95..e0426d1f346 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java @@ -31,16 +31,12 @@ import org.eclipse.jetty.util.resource.Resource; public class FragmentConfiguration extends AbstractConfiguration { public final static String FRAGMENT_RESOURCES="org.eclipse.jetty.webFragments"; - + @Override public void preConfigure(WebAppContext context) throws Exception { - if (!context.isConfigurationDiscovered()) - return; - - //find all web-fragment.xmls - findWebFragments(context, context.getMetaData()); - + //add all discovered web-fragment.xmls + addWebFragments(context, context.getMetaData()); } @@ -49,16 +45,33 @@ public class FragmentConfiguration extends AbstractConfiguration { context.setAttribute(FRAGMENT_RESOURCES, null); } - + /* ------------------------------------------------------------------------------- */ /** - * Look for any web-fragment.xml fragments in META-INF of jars in WEB-INF/lib + * Add in fragment descriptors that have already been discovered by MetaInfConfiguration + * + * @param context the web app context to look in + * @param metaData the metadata to populate with fragments + * + * @throws Exception if unable to find web fragments + * @deprecated + */ + public void findWebFragments (final WebAppContext context, final MetaData metaData) + throws Exception + { + addWebFragments(context, metaData); + } + + /* ------------------------------------------------------------------------------- */ + /** + * Add in fragment descriptors that have already been discovered by MetaInfConfiguration + * * @param context the web app context to look in * @param metaData the metadata to populate with fragments * * @throws Exception if unable to find web fragments */ - public void findWebFragments (final WebAppContext context, final MetaData metaData) throws Exception + public void addWebFragments (final WebAppContext context, final MetaData metaData) throws Exception { @SuppressWarnings("unchecked") Map frags = (Map)context.getAttribute(FRAGMENT_RESOURCES); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java index 7ac3ff613aa..ea973624719 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java @@ -24,11 +24,14 @@ import java.io.IOException; import java.net.JarURLConnection; import java.net.URI; import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -69,14 +72,19 @@ public class MetaInfConfiguration extends AbstractConfiguration public static final String METAINF_TLDS = "org.eclipse.jetty.tlds"; public static final String METAINF_FRAGMENTS = FragmentConfiguration.FRAGMENT_RESOURCES; public static final String METAINF_RESOURCES = WebInfConfiguration.RESOURCE_DIRS; - + public static final List __allScanTypes = (List) Arrays.asList(METAINF_TLDS, METAINF_RESOURCES, METAINF_FRAGMENTS); + + @Override public void preConfigure(final WebAppContext context) throws Exception - { + { boolean useContainerCache = DEFAULT_USE_CONTAINER_METAINF_CACHE; - Boolean attr = (Boolean)context.getServer().getAttribute(USE_CONTAINER_METAINF_CACHE); - if (attr != null) - useContainerCache = attr.booleanValue(); + if (context.getServer() != null) + { + Boolean attr = (Boolean)context.getServer().getAttribute(USE_CONTAINER_METAINF_CACHE); + if (attr != null) + useContainerCache = attr.booleanValue(); + } if (LOG.isDebugEnabled()) LOG.debug("{} = {}", USE_CONTAINER_METAINF_CACHE, useContainerCache); @@ -89,9 +97,28 @@ public class MetaInfConfiguration extends AbstractConfiguration context.setAttribute(METAINF_RESOURCES, new HashSet()); if (context.getAttribute(METAINF_FRAGMENTS) == null) context.setAttribute(METAINF_FRAGMENTS, new HashMap()); - - scanJars(context, context.getMetaData().getContainerResources(), useContainerCache); - scanJars(context, context.getMetaData().getWebInfJars(), false); + + //always scan everything from the container's classpath + scanJars(context, context.getMetaData().getContainerResources(), useContainerCache, __allScanTypes); + //only look for fragments if web.xml is not metadata complete, or it version 3.0 or greater + List scanTypes = new ArrayList<>(__allScanTypes); + if (context.getMetaData().isMetaDataComplete() || (context.getServletContext().getEffectiveMajorVersion() < 3) && !context.isConfigurationDiscovered()) + scanTypes.remove(METAINF_FRAGMENTS); + scanJars(context, context.getMetaData().getWebInfJars(), false, scanTypes); + } + + /** + * For backwards compatibility. This method will always scan for all types of data. + * + * @param context the context for the scan + * @param jars the jars to scan + * @param useCaches if true, the scanned info is cached + * @throws Exception + */ + public void scanJars (final WebAppContext context, Collection jars, boolean useCaches) + throws Exception + { + scanJars(context, jars, useCaches, __allScanTypes); } /** @@ -102,9 +129,10 @@ public class MetaInfConfiguration extends AbstractConfiguration * @param context the context for the scan * @param jars the jars resources to scan * @param useCaches if true, cache the info discovered + * @param scanTypes the type of things to look for in the jars * @throws Exception if unable to scan the jars */ - public void scanJars (final WebAppContext context, Collection jars, boolean useCaches) + public void scanJars (final WebAppContext context, Collection jars, boolean useCaches, List scanTypes ) throws Exception { ConcurrentHashMap metaInfResourceCache = null; @@ -131,16 +159,18 @@ public class MetaInfConfiguration extends AbstractConfiguration context.getServer().setAttribute(CACHED_CONTAINER_TLDS, metaInfTldCache); } } - + //Scan jars for META-INF information if (jars != null) { for (Resource r : jars) - { - - scanForResources(context, r, metaInfResourceCache); - scanForFragment(context, r, metaInfFragmentCache); - scanForTlds(context, r, metaInfTldCache); + { + if (scanTypes.contains(METAINF_RESOURCES)) + scanForResources(context, r, metaInfResourceCache); + if (scanTypes.contains(METAINF_FRAGMENTS)) + scanForFragment(context, r, metaInfFragmentCache); + if (scanTypes.contains(METAINF_TLDS)) + scanForTlds(context, r, metaInfTldCache); } } } 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 81932e43280..070c670bd1c 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 @@ -185,7 +185,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL private Map _resourceAliases; private boolean _ownClassLoader=false; - private boolean _configurationDiscovered=true; + private boolean _configurationDiscovered=false; private boolean _allowDuplicateFragmentNames = false; private boolean _throwUnavailableOnStartupException = false; diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/MetaInfConfigurationTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/MetaInfConfigurationTest.java new file mode 100644 index 00000000000..42be205ff68 --- /dev/null +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/MetaInfConfigurationTest.java @@ -0,0 +1,140 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 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.webapp; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.resource.Resource; +import org.junit.Test; + +/** + * MetaInfConfigurationTest + * + * + */ +public class MetaInfConfigurationTest +{ + + public class TestableMetaInfConfiguration extends MetaInfConfiguration + { + List _expectedContainerScanTypes; + List _expectedWebAppScanTypes; + int _invocationCount = 0; + + public TestableMetaInfConfiguration(List expectedContainerScanTypes, List expectedWebAppScanTypes) + { + _expectedContainerScanTypes = expectedContainerScanTypes; + _expectedWebAppScanTypes = expectedWebAppScanTypes; + } + + + /** + * @see org.eclipse.jetty.webapp.MetaInfConfiguration#scanJars(org.eclipse.jetty.webapp.WebAppContext, java.util.Collection, boolean, java.util.List) + */ + @Override + public void scanJars(WebAppContext context, Collection jars, boolean useCaches, List scanTypes) throws Exception + { + assertNotNull(scanTypes); + List expectedScanTypes = null; + switch (_invocationCount) + { + case 0: + { + expectedScanTypes = _expectedContainerScanTypes; + break; + } + case 1: + { + expectedScanTypes = _expectedWebAppScanTypes; + break; + } + default: + { + fail("Too many invocations"); + } + } + + ++_invocationCount; + + assertNotNull(expectedScanTypes); + assertTrue(expectedScanTypes.containsAll(scanTypes)); + assertEquals(expectedScanTypes.size(), scanTypes.size()); + } + + } + + + @Test + public void testScanTypes() + throws Exception + { + File web25 = MavenTestingUtils.getTestResourceFile("web25.xml"); + File web31 = MavenTestingUtils.getTestResourceFile("web31.xml"); + File web31false = MavenTestingUtils.getTestResourceFile("web31false.xml"); + + //test a 2.5 webapp will not look for fragments by default + MetaInfConfiguration meta25 = new TestableMetaInfConfiguration(MetaInfConfiguration.__allScanTypes, + Arrays.asList(MetaInfConfiguration.METAINF_TLDS, MetaInfConfiguration.METAINF_RESOURCES)); + WebAppContext context25 = new WebAppContext(); + context25.getMetaData().setWebXml(Resource.newResource(web25)); + context25.getServletContext().setEffectiveMajorVersion(2); + context25.getServletContext().setEffectiveMinorVersion(5); + meta25.preConfigure(context25); + + //test a 2.5 webapp will look for fragments if configurationDiscovered==true + MetaInfConfiguration meta25b = new TestableMetaInfConfiguration(MetaInfConfiguration.__allScanTypes, + MetaInfConfiguration.__allScanTypes); + WebAppContext context25b = new WebAppContext(); + context25b.setConfigurationDiscovered(true); + context25b.getMetaData().setWebXml(Resource.newResource(web25)); + context25b.getServletContext().setEffectiveMajorVersion(2); + context25b.getServletContext().setEffectiveMinorVersion(5); + meta25b.preConfigure(context25b); + + //test a 3.x metadata-complete webapp will not look for fragments + MetaInfConfiguration meta31 = new TestableMetaInfConfiguration(MetaInfConfiguration.__allScanTypes, + Arrays.asList(MetaInfConfiguration.METAINF_TLDS, MetaInfConfiguration.METAINF_RESOURCES)); + WebAppContext context31 = new WebAppContext(); + context31.getMetaData().setWebXml(Resource.newResource(web31)); + context31.getServletContext().setEffectiveMajorVersion(3); + context31.getServletContext().setEffectiveMinorVersion(1); + meta31.preConfigure(context31); + + //test a 3.x non metadata-complete webapp will look for fragments + MetaInfConfiguration meta31false = new TestableMetaInfConfiguration(MetaInfConfiguration.__allScanTypes, + MetaInfConfiguration.__allScanTypes); + WebAppContext context31false = new WebAppContext(); + context31false.setConfigurationDiscovered(true); + context31false.getMetaData().setWebXml(Resource.newResource(web31false)); + context31false.getServletContext().setEffectiveMajorVersion(3); + context31false.getServletContext().setEffectiveMinorVersion(1); + meta31false.preConfigure(context31false); + } + +} diff --git a/jetty-webapp/src/test/resources/web25.xml b/jetty-webapp/src/test/resources/web25.xml new file mode 100644 index 00000000000..da2e65b6007 --- /dev/null +++ b/jetty-webapp/src/test/resources/web25.xml @@ -0,0 +1,10 @@ + + + + Test 2.5 WebApp + + diff --git a/jetty-webapp/src/test/resources/web31.xml b/jetty-webapp/src/test/resources/web31.xml new file mode 100644 index 00000000000..e44571a8a20 --- /dev/null +++ b/jetty-webapp/src/test/resources/web31.xml @@ -0,0 +1,11 @@ + + + + Test 31 WebApp + + diff --git a/jetty-webapp/src/test/resources/web31false.xml b/jetty-webapp/src/test/resources/web31false.xml new file mode 100644 index 00000000000..a2307a7560b --- /dev/null +++ b/jetty-webapp/src/test/resources/web31false.xml @@ -0,0 +1,11 @@ + + + + Test 31 WebApp + +