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
+
+