From 347dc956f206c3c5402d2f3d10188d8a08ba7c9d Mon Sep 17 00:00:00 2001 From: markt Date: Thu, 2 Jun 2011 15:54:26 +0000 Subject: [PATCH] Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51278 Allow ServletContainerInitializers to override settings in the global default web.xml and the host web.xml. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1130618 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/catalina/Wrapper.java | 10 ++ .../apache/catalina/core/ApplicationContext.java | 8 +- .../core/ApplicationServletRegistration.java | 12 ++- java/org/apache/catalina/core/StandardWrapper.java | 11 +++ java/org/apache/catalina/deploy/ServletDef.java | 15 +++ java/org/apache/catalina/deploy/WebXml.java | 17 +++- .../org/apache/catalina/startup/ContextConfig.java | 34 +++++-- .../apache/catalina/startup/TestContextConfig.java | 102 +++++++++++++++++++++ test/webapp-3.0/index.html | 8 ++ webapps/docs/changelog.xml | 4 + 10 files changed, 207 insertions(+), 14 deletions(-) create mode 100644 test/org/apache/catalina/startup/TestContextConfig.java create mode 100644 test/webapp-3.0/index.html diff --git a/java/org/apache/catalina/Wrapper.java b/java/org/apache/catalina/Wrapper.java index cc67b4cc1..2580def02 100644 --- a/java/org/apache/catalina/Wrapper.java +++ b/java/org/apache/catalina/Wrapper.java @@ -386,4 +386,14 @@ public interface Wrapper extends Container { * Servlet associated with this wrapper. */ public void servletSecurityAnnotationScan() throws ServletException; + + /** + * Is the Servlet overridable by a ServletContainerInitializer? + */ + public boolean isOverridable(); + + /** + * Sets the overridable attribute for this Servlet. + */ + public void setOverridable(boolean overridable); } diff --git a/java/org/apache/catalina/core/ApplicationContext.java b/java/org/apache/catalina/core/ApplicationContext.java index 22925c27d..bfd68bcc3 100644 --- a/java/org/apache/catalina/core/ApplicationContext.java +++ b/java/org/apache/catalina/core/ApplicationContext.java @@ -1102,7 +1102,7 @@ public class ApplicationContext Wrapper wrapper = (Wrapper) context.findChild(servletName); - // Assume a 'complete' FilterRegistration is one that has a class and + // Assume a 'complete' ServletRegistration is one that has a class and // a name if (wrapper == null) { wrapper = context.createWrapper(); @@ -1111,7 +1111,11 @@ public class ApplicationContext } else { if (wrapper.getName() != null && wrapper.getServletClass() != null) { - return null; + if (wrapper.isOverridable()) { + wrapper.setOverridable(false); + } else { + return null; + } } } diff --git a/java/org/apache/catalina/core/ApplicationServletRegistration.java b/java/org/apache/catalina/core/ApplicationServletRegistration.java index c4bb9fd25..707a88d52 100644 --- a/java/org/apache/catalina/core/ApplicationServletRegistration.java +++ b/java/org/apache/catalina/core/ApplicationServletRegistration.java @@ -171,8 +171,16 @@ public class ApplicationServletRegistration Set conflicts = new HashSet(); for (String urlPattern : urlPatterns) { - if (context.findServletMapping(urlPattern) != null) { - conflicts.add(urlPattern); + String wrapperName = context.findServletMapping(urlPattern); + if (wrapperName != null) { + Wrapper wrapper = (Wrapper) context.findChild(wrapperName); + if (wrapper.isOverridable()) { + // Some Wrappers (from global and host web.xml) may be + // overridden rather than generating a conflict + context.removeServletMapping(urlPattern); + } else { + conflicts.add(urlPattern); + } } } diff --git a/java/org/apache/catalina/core/StandardWrapper.java b/java/org/apache/catalina/core/StandardWrapper.java index bbd6f31ff..7b06fbc07 100644 --- a/java/org/apache/catalina/core/StandardWrapper.java +++ b/java/org/apache/catalina/core/StandardWrapper.java @@ -276,6 +276,8 @@ public class StandardWrapper extends ContainerBase protected volatile boolean servletSecurityAnnotationScanRequired = false; + private boolean overridable = false; + /** * Static class array used when the SecurityManager is turned on and * Servlet.init is invoked. @@ -294,6 +296,15 @@ public class StandardWrapper extends ContainerBase // ------------------------------------------------------------- Properties + @Override + public boolean isOverridable() { + return overridable; + } + + @Override + public void setOverridable(boolean overridable) { + this.overridable = overridable; + } /** * Return the available date/time for this servlet, in milliseconds since diff --git a/java/org/apache/catalina/deploy/ServletDef.java b/java/org/apache/catalina/deploy/ServletDef.java index 7b410b7af..44261a5e4 100644 --- a/java/org/apache/catalina/deploy/ServletDef.java +++ b/java/org/apache/catalina/deploy/ServletDef.java @@ -264,4 +264,19 @@ public class ServletDef implements Serializable { public void setEnabled(String enabled) { this.enabled = Boolean.valueOf(enabled); } + + + /** + * Can this ServletDef be overridden by an SCI? + */ + private boolean overridable = false; + + public boolean isOverridable() { + return overridable; + } + + public void setOverridable(boolean overridable) { + this.overridable = overridable; + } + } diff --git a/java/org/apache/catalina/deploy/WebXml.java b/java/org/apache/catalina/deploy/WebXml.java index 230e9fc80..99ec9910f 100644 --- a/java/org/apache/catalina/deploy/WebXml.java +++ b/java/org/apache/catalina/deploy/WebXml.java @@ -61,7 +61,18 @@ public class WebXml { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog(WebXml.class); - + + // Global defaults are overridable but Servlets and Servlet mappings need to + // be unique. Duplicates normally trigger an error. This flag indicates if + // newly added Servlet elements are marked as overridable. + private boolean overridable = false; + public boolean isOverridable() { + return overridable; + } + public void setOverridable(boolean overridable) { + this.overridable = overridable; + } + // web.xml only elements // Absolute Ordering private Set absoluteOrdering = null; @@ -305,6 +316,9 @@ public class WebXml { private Map servlets = new HashMap(); public void addServlet(ServletDef servletDef) { servlets.put(servletDef.getServletName(), servletDef); + if (overridable) { + servletDef.setOverridable(overridable); + } } public Map getServlets() { return servlets; } @@ -1268,6 +1282,7 @@ public class WebXml { wrapper.setAsyncSupported( servlet.getAsyncSupported().booleanValue()); } + wrapper.setOverridable(servlet.isOverridable()); context.addChild(wrapper); } for (Entry entry : servletMappings.entrySet()) { diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java index 4e9e55672..dba237b57 100644 --- a/java/org/apache/catalina/startup/ContextConfig.java +++ b/java/org/apache/catalina/startup/ContextConfig.java @@ -1186,6 +1186,15 @@ public class ContextConfig */ protected void webConfig() { WebXml webXml = createWebXml(); + /* Anything and everything can override the global and host defaults. + * This is implemented in two parts + * - Handle as a web fragment that gets added after everything else so + * everything else takes priority + * - Mark Servlets as overridable so SCI configuration can replace + * configuration from the defaults + */ + WebXml webXmlDefaultFragment = createWebXml(); + webXmlDefaultFragment.setOverridable(true); // Parse global web.xml if present InputSource globalWebXml = getGlobalWebXmlSource(); @@ -1193,17 +1202,19 @@ public class ContextConfig // This is unusual enough to log log.info(sm.getString("contextConfig.defaultMissing")); } else { - parseWebXml(globalWebXml, webXml, false); + parseWebXml(globalWebXml, webXmlDefaultFragment, false); } // Parse host level web.xml if present // Additive apart from welcome pages webXml.setReplaceWelcomeFiles(true); InputSource hostWebXml = getHostWebXmlSource(); - parseWebXml(hostWebXml, webXml, false); + parseWebXml(hostWebXml, webXmlDefaultFragment, false); + + Set defaults = new HashSet(); + defaults.add(webXmlDefaultFragment); // Parse context level web.xml - webXml.setReplaceWelcomeFiles(true); InputSource contextWebXml = getContextWebXmlSource(); parseWebXml(contextWebXml, webXml, false); @@ -1260,16 +1271,19 @@ public class ContextConfig ok = webXml.merge(orderedFragments); } - // Step 6.5 Convert explicitly mentioned jsps to servlets + // Step 7. Convert explicitly mentioned jsps to servlets if (!false) { convertJsps(webXml); } - - // Step 7. Apply merged web.xml to Context + + // Step 8. Apply global defaults + webXml.merge(defaults); + + // Step 9. Apply merged web.xml to Context if (ok) { webXml.configureContext(context); - // Step 7a. Make the merged web.xml available to other + // Step 9a. Make the merged web.xml available to other // components, specifically Jasper, to save those components // from having to re-generate it. // TODO Use a ServletContainerInitializer for Jasper @@ -1282,11 +1296,12 @@ public class ContextConfig } } } else { + webXml.merge(defaults); webXml.configureContext(context); } // Always need to look for static resources - // Step 8. Look for static resources packaged in JARs + // Step 10. Look for static resources packaged in JARs if (ok) { // Spec does not define an order. // Use ordered JARs followed by remaining JARs @@ -1309,7 +1324,7 @@ public class ContextConfig // Only look for ServletContainerInitializer if metadata is not // complete if (!webXml.isMetadataComplete()) { - // Step 9. Apply the ServletContainerInitializer config to the + // Step 11. Apply the ServletContainerInitializer config to the // context if (ok) { for (Map.Entry> c, ServletContext ctx) + throws ServletException { + Servlet s = new CustomDefaultServlet(); + ServletRegistration.Dynamic r = ctx.addServlet(servletName, s); + r.addMapping("/"); + } + + } + + private static class CustomDefaultServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/plain"); + resp.getWriter().print("OK - Custom default Servlet"); + } + } +} diff --git a/test/webapp-3.0/index.html b/test/webapp-3.0/index.html new file mode 100644 index 000000000..2bf0cefd9 --- /dev/null +++ b/test/webapp-3.0/index.html @@ -0,0 +1,8 @@ + + + Index page + + +

This is the index page served by the default Servlet.

+ + \ No newline at end of file diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 226f7d9d8..5fbc07daf 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -78,6 +78,10 @@ with an incomplete FORM authentication configuration. (markt) + 51278: Allow ServletContainerInitializers to override + settings in the global default web.xml and the host web.xml. (markt) + + 51310: When stopping the Server object on shutdown call destroy() after calling stop(). (markt) -- 2.11.0