- Add support for multiple servlet and filter mappings.
authorremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 4 Apr 2006 22:34:09 +0000 (22:34 +0000)
committerremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 4 Apr 2006 22:34:09 +0000 (22:34 +0000)
- Fix a bug I found by accident where application listeners are not reinitialized when reloading.
- That's all folks, all the useful Servlet 2.5 features are done. Now the annotations ... (sigh)
- Reuse the ignoreAnnotations field name from the patch submitted by Fabien Carrion.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@391432 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/Context.java
java/org/apache/catalina/core/ApplicationFilterFactory.java
java/org/apache/catalina/core/StandardContext.java
java/org/apache/catalina/deploy/FilterMap.java
java/org/apache/catalina/startup/WebRuleSet.java
java/org/apache/tomcat/util/digester/CallMethodRule.java

index 25a31b2..778d2ae 100644 (file)
@@ -259,6 +259,21 @@ public interface Context extends Container {
 \r
 \r
     /**\r
+     * Return the boolean on the annotations parsing.\r
+     */\r
+    public boolean getIgnoreAnnotations();\r
+    \r
+    \r
+    /**\r
+     * Set the boolean on the annotations parsing for this web \r
+     * application.\r
+     * \r
+     * @param ignoreAnnotations The boolean on the annotations parsing\r
+     */\r
+    public void setIgnoreAnnotations(boolean ignoreAnnotations);\r
+    \r
+    \r
+    /**\r
      * Return the login configuration descriptor for this web application.\r
      */\r
     public LoginConfig getLoginConfig();\r
index 0ff2ca9..bbe23f0 100644 (file)
@@ -212,7 +212,30 @@ public final class ApplicationFilterFactory {
             return (false);\r
 \r
         // Match on context relative request path\r
-        String testPath = filterMap.getURLPattern();\r
+        String[] testPaths = filterMap.getURLPatterns();\r
+        \r
+        for (int i = 0; i < testPaths.length; i++) {\r
+            if (matchFiltersURL(testPaths[i], requestPath)) {\r
+                return (true);\r
+            }\r
+        }\r
+        \r
+        // No match\r
+        return (false);\r
+        \r
+    }\r
+    \r
+\r
+    /**\r
+     * Return <code>true</code> if the context-relative request path\r
+     * matches the requirements of the specified filter mapping;\r
+     * otherwise, return <code>false</code>.\r
+     *\r
+     * @param testPath URL mapping being checked\r
+     * @param requestPath Context-relative request path of this request\r
+     */\r
+    private boolean matchFiltersURL(String testPath, String requestPath) {\r
+        \r
         if (testPath == null)\r
             return (false);\r
 \r
@@ -268,11 +291,13 @@ public final class ApplicationFilterFactory {
         if (servletName == null) {\r
             return (false);\r
         } else {\r
-            if (servletName.equals(filterMap.getServletName())) {\r
-                return (true);\r
-            } else {\r
-                return false;\r
+            String[] servletNames = filterMap.getServletNames();\r
+            for (int i = 0; i < servletNames.length; i++) {\r
+                if (servletName.equals(servletNames[i])) {\r
+                    return (true);\r
+                }\r
             }\r
+            return false;\r
         }\r
 \r
     }\r
index b4875b1..bf33c18 100644 (file)
@@ -301,7 +301,7 @@ public class StandardContext
     private boolean delegate = false;\r
 \r
 \r
-     /**\r
+    /**\r
      * The display name of this web application.\r
      */\r
     private String displayName = null;\r
@@ -360,6 +360,12 @@ public class StandardContext
 \r
 \r
     /**\r
+     * Ignore annotations.\r
+     */\r
+    private boolean ignoreAnnotations = false;\r
+\r
+\r
+    /**\r
      * The set of classnames of InstanceListeners that will be added\r
      * to each newly created Wrapper by <code>createWrapper()</code>.\r
      */\r
@@ -1301,6 +1307,28 @@ public class StandardContext
 \r
 \r
     /**\r
+     * Return the boolean on the annotations parsing.\r
+     */\r
+    public boolean getIgnoreAnnotations() {\r
+        return this.ignoreAnnotations;\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Set the boolean on the annotations parsing for this web \r
+     * application.\r
+     * \r
+     * @param ignoreAnnotations The boolean on the annotations parsing\r
+     */\r
+    public void setIgnoreAnnotations(boolean ignoreAnnotations) {\r
+        boolean oldIgnoreAnnotations = this.ignoreAnnotations;\r
+        this.ignoreAnnotations = ignoreAnnotations;\r
+        support.firePropertyChange("ignoreAnnotations", Boolean.valueOf(oldIgnoreAnnotations),\r
+                Boolean.valueOf(this.ignoreAnnotations));\r
+    }\r
+    \r
+    \r
+    /**\r
      * Return the login configuration descriptor for this web application.\r
      */\r
     public LoginConfig getLoginConfig() {\r
@@ -2061,23 +2089,29 @@ public class StandardContext
 \r
         // Validate the proposed filter mapping\r
         String filterName = filterMap.getFilterName();\r
-        String servletName = filterMap.getServletName();\r
-        String urlPattern = filterMap.getURLPattern();\r
+        String[] servletNames = filterMap.getServletNames();\r
+        String[] urlPatterns = filterMap.getURLPatterns();\r
         if (findFilterDef(filterName) == null)\r
             throw new IllegalArgumentException\r
                 (sm.getString("standardContext.filterMap.name", filterName));\r
-        if ((servletName == null) && (urlPattern == null))\r
+        if ((servletNames.length == 0) && (urlPatterns.length == 0))\r
             throw new IllegalArgumentException\r
                 (sm.getString("standardContext.filterMap.either"));\r
-        if ((servletName != null) && (urlPattern != null))\r
+        // FIXME: Older spec revisions may still check this\r
+        /*\r
+        if ((servletNames.length != 0) && (urlPatterns.length != 0))\r
             throw new IllegalArgumentException\r
                 (sm.getString("standardContext.filterMap.either"));\r
+        */\r
         // Because filter-pattern is new in 2.3, no need to adjust\r
         // for 2.2 backwards compatibility\r
-        if ((urlPattern != null) && !validateURLPattern(urlPattern))\r
-            throw new IllegalArgumentException\r
-                (sm.getString("standardContext.filterMap.pattern",\r
-                              urlPattern));\r
+        for (int i = 0; i < urlPatterns.length; i++) {\r
+            if (!validateURLPattern(urlPatterns[i])) {\r
+                throw new IllegalArgumentException\r
+                    (sm.getString("standardContext.filterMap.pattern",\r
+                            urlPatterns[i]));\r
+            }\r
+        }\r
 \r
         // Add this filter mapping to our registered set\r
         synchronized (filterMaps) {\r
@@ -4446,7 +4480,7 @@ public class StandardContext
         lifecycle.fireLifecycleEvent(DESTROY_EVENT, null);\r
 \r
         instanceListeners = new String[0];\r
-        applicationListeners = new String[0];\r
+\r
     }\r
     \r
     private void resetContext() throws Exception, MBeanRegistrationException {\r
@@ -4460,6 +4494,10 @@ public class StandardContext
         // Bugzilla 32867\r
         distributable = false;\r
 \r
+        applicationListeners = new String[0];\r
+        applicationEventListenersObjects = new Object[0];\r
+        applicationLifecycleListenersObjects = new Object[0];\r
+        \r
         if(log.isDebugEnabled())\r
             log.debug("resetContext " + oname + " " + mserver);\r
     }\r
index c4d2cd7..2b285e3 100644 (file)
@@ -79,14 +79,17 @@ public class FilterMap implements Serializable {
     /**\r
      * The servlet name this mapping matches.\r
      */\r
-    private String servletName = null;\r
+    private String[] servletNames = new String[0];\r
 \r
-    public String getServletName() {\r
-        return (this.servletName);\r
+    public String[] getServletNames() {\r
+        return (this.servletNames);\r
     }\r
 \r
-    public void setServletName(String servletName) {\r
-        this.servletName = servletName;\r
+    public void addServletName(String servletName) {\r
+        String[] results = new String[servletNames.length + 1];\r
+        System.arraycopy(servletNames, 0, results, 0, servletNames.length);\r
+        results[servletNames.length] = servletName;\r
+        servletNames = results;\r
     }\r
 \r
     \r
@@ -103,17 +106,20 @@ public class FilterMap implements Serializable {
     /**\r
      * The URL pattern this mapping matches.\r
      */\r
-    private String urlPattern = null;\r
+    private String[] urlPatterns = new String[0];\r
 \r
-    public String getURLPattern() {\r
-        return (this.urlPattern);\r
+    public String[] getURLPatterns() {\r
+        return (this.urlPatterns);\r
     }\r
 \r
-    public void setURLPattern(String urlPattern) {\r
+    public void addURLPattern(String urlPattern) {\r
         if ("*".equals(urlPattern)) {\r
             this.allMatch = true;\r
         } else {\r
-            this.urlPattern = RequestUtil.URLDecode(urlPattern);\r
+            String[] results = new String[urlPatterns.length + 1];\r
+            System.arraycopy(urlPatterns, 0, results, 0, urlPatterns.length);\r
+            results[urlPatterns.length] = RequestUtil.URLDecode(urlPattern);\r
+            urlPatterns = results;\r
         }\r
     }\r
     \r
@@ -211,13 +217,13 @@ public class FilterMap implements Serializable {
         StringBuffer sb = new StringBuffer("FilterMap[");\r
         sb.append("filterName=");\r
         sb.append(this.filterName);\r
-        if (servletName != null) {\r
+        for (int i = 0; i < servletNames.length; i++) {\r
             sb.append(", servletName=");\r
-            sb.append(servletName);\r
+            sb.append(servletNames[i]);\r
         }\r
-        if (urlPattern != null) {\r
+        for (int i = 0; i < urlPatterns.length; i++) {\r
             sb.append(", urlPattern=");\r
-            sb.append(urlPattern);\r
+            sb.append(urlPatterns[i]);\r
         }\r
         sb.append("]");\r
         return (sb.toString());\r
index 5a98b34..2518eb7 100644 (file)
@@ -19,9 +19,14 @@ package org.apache.catalina.startup;
 \r
 \r
 import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+\r
 import org.apache.catalina.Context;\r
 import org.apache.catalina.Wrapper;\r
 import org.apache.catalina.deploy.SecurityConstraint;\r
+import org.apache.tomcat.util.IntrospectionUtils;\r
+import org.apache.tomcat.util.digester.CallMethodRule;\r
+import org.apache.tomcat.util.digester.CallParamRule;\r
 import org.apache.tomcat.util.digester.Digester;\r
 import org.apache.tomcat.util.digester.Rule;\r
 import org.apache.tomcat.util.digester.RuleSetBase;\r
@@ -115,6 +120,8 @@ public class WebRuleSet extends RuleSetBase {
         \r
         digester.addRule(prefix + "web-app",\r
                          new SetPublicIdRule("setPublicId"));\r
+        digester.addRule(prefix + "web-app",\r
+                         new IgnoreAnnotationsRule());\r
 \r
         digester.addCallMethod(prefix + "web-app/context-param",\r
                                "addParameter", 2);\r
@@ -222,15 +229,15 @@ public class WebRuleSet extends RuleSetBase {
         digester.addObjectCreate(prefix + "web-app/filter-mapping",\r
                                  "org.apache.catalina.deploy.FilterMap");\r
         digester.addSetNext(prefix + "web-app/filter-mapping",\r
-                            "addFilterMap",\r
-                            "org.apache.catalina.deploy.FilterMap");\r
+                                 "addFilterMap",\r
+                                 "org.apache.catalina.deploy.FilterMap");\r
 \r
         digester.addCallMethod(prefix + "web-app/filter-mapping/filter-name",\r
                                "setFilterName", 0);\r
         digester.addCallMethod(prefix + "web-app/filter-mapping/servlet-name",\r
-                               "setServletName", 0);\r
+                               "addServletName", 0);\r
         digester.addCallMethod(prefix + "web-app/filter-mapping/url-pattern",\r
-                               "setURLPattern", 0);\r
+                               "addURLPattern", 0);\r
 \r
         digester.addCallMethod(prefix + "web-app/filter-mapping/dispatcher",\r
                                "setDispatcher", 0);\r
@@ -392,10 +399,10 @@ public class WebRuleSet extends RuleSetBase {
         digester.addCallMethod(prefix + "web-app/servlet/servlet-name",\r
                               "setName", 0);\r
 \r
-        digester.addCallMethod(prefix + "web-app/servlet-mapping",\r
-                               "addServletMapping", 2);\r
+        digester.addRule(prefix + "web-app/servlet-mapping",\r
+                               new CallMethodMultiRule("addServletMapping", 2, 0));\r
         digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1);\r
-        digester.addCallParam(prefix + "web-app/servlet-mapping/url-pattern", 0);\r
+        digester.addRule(prefix + "web-app/servlet-mapping/url-pattern", new CallParamMultiRule(0));\r
 \r
         digester.addRule(prefix + "web-app/session-config",\r
                          sessionConfig);\r
@@ -614,3 +621,139 @@ final class WrapperCreateRule extends Rule {
     }\r
 \r
 }\r
+\r
+\r
+/**\r
+ * A Rule that can be used to call multiple times a method as many times as needed\r
+ * (used for addServletMapping).\r
+ */\r
+final class CallParamMultiRule extends CallParamRule {\r
+\r
+    public CallParamMultiRule(int paramIndex) {\r
+        super(paramIndex);\r
+    }\r
+\r
+    public void end(String namespace, String name) {\r
+        if (bodyTextStack != null && !bodyTextStack.empty()) {\r
+            // what we do now is push one parameter onto the top set of parameters\r
+            Object parameters[] = (Object[]) digester.peekParams();\r
+            ArrayList params = (ArrayList) parameters[paramIndex];\r
+            if (params == null) {\r
+                params = new ArrayList();\r
+                parameters[paramIndex] = params;\r
+            }\r
+            params.add(bodyTextStack.pop());\r
+        }\r
+    }\r
+\r
+}\r
+\r
+\r
+/**\r
+ * A Rule that can be used to call multiple times a method as many times as needed\r
+ * (used for addServletMapping).\r
+ */\r
+final class CallMethodMultiRule extends CallMethodRule {\r
+\r
+    protected int multiParamIndex = 0;\r
+    \r
+    public CallMethodMultiRule(String methodName, int paramCount, int multiParamIndex) {\r
+        super(methodName, paramCount);\r
+        this.multiParamIndex = multiParamIndex;\r
+    }\r
+\r
+    public void end() throws Exception {\r
+\r
+        // Retrieve or construct the parameter values array\r
+        Object parameters[] = null;\r
+        if (paramCount > 0) {\r
+            parameters = (Object[]) digester.popParams();\r
+        } else {\r
+            super.end();\r
+        }\r
+        \r
+        ArrayList multiParams = (ArrayList) parameters[multiParamIndex];\r
+        \r
+        // Construct the parameter values array we will need\r
+        // We only do the conversion if the param value is a String and\r
+        // the specified paramType is not String. \r
+        Object paramValues[] = new Object[paramTypes.length];\r
+        for (int i = 0; i < paramTypes.length; i++) {\r
+            if (i != multiParamIndex) {\r
+                // convert nulls and convert stringy parameters \r
+                // for non-stringy param types\r
+                if(parameters[i] == null || (parameters[i] instanceof String \r
+                        && !String.class.isAssignableFrom(paramTypes[i]))) {\r
+                    paramValues[i] =\r
+                        IntrospectionUtils.convert((String) parameters[i], paramTypes[i]);\r
+                } else {\r
+                    paramValues[i] = parameters[i];\r
+                }\r
+            }\r
+        }\r
+\r
+        // Determine the target object for the method call\r
+        Object target;\r
+        if (targetOffset >= 0) {\r
+            target = digester.peek(targetOffset);\r
+        } else {\r
+            target = digester.peek(digester.getCount() + targetOffset);\r
+        }\r
+\r
+        if (target == null) {\r
+            StringBuffer sb = new StringBuffer();\r
+            sb.append("[CallMethodRule]{");\r
+            sb.append("");\r
+            sb.append("} Call target is null (");\r
+            sb.append("targetOffset=");\r
+            sb.append(targetOffset);\r
+            sb.append(",stackdepth=");\r
+            sb.append(digester.getCount());\r
+            sb.append(")");\r
+            throw new org.xml.sax.SAXException(sb.toString());\r
+        }\r
+        \r
+        for (int j = 0; j < multiParams.size(); j++) {\r
+            Object param = multiParams.get(j);\r
+            if(param == null || (param instanceof String \r
+                    && !String.class.isAssignableFrom(paramTypes[multiParamIndex]))) {\r
+                paramValues[multiParamIndex] =\r
+                    IntrospectionUtils.convert((String) param, paramTypes[multiParamIndex]);\r
+            } else {\r
+                paramValues[multiParamIndex] = param;\r
+            }\r
+            Object result = IntrospectionUtils.callMethodN(target, methodName,\r
+                    paramValues, paramTypes);   \r
+        }\r
+        \r
+    }\r
+\r
+}\r
+\r
+\r
+\r
+/**\r
+ * A Rule that check if the annotations have to be loaded.\r
+ * \r
+ */\r
+\r
+final class IgnoreAnnotationsRule extends Rule {\r
+\r
+    public IgnoreAnnotationsRule() {\r
+    }\r
+\r
+    public void begin(String namespace, String name, Attributes attributes)\r
+        throws Exception {\r
+        Context context = (Context) digester.peek(digester.getCount() - 1);\r
+        String value = attributes.getValue("metadata-complete");\r
+        if ("true".equals(value)) {\r
+            context.setIgnoreAnnotations(true);\r
+        }\r
+        if (digester.getLogger().isDebugEnabled()) {\r
+            digester.getLogger().debug\r
+                (context.getClass().getName() + ".setIgnoreAnnotations( " +\r
+                    context.getIgnoreAnnotations() + ")");\r
+        }\r
+    }\r
+\r
+}\r
index 251d48a..2bb0590 100644 (file)
@@ -355,7 +355,7 @@ public class CallMethodRule extends Rule {
      * top of the digester object stack. The default value of zero\r
      * means the target object is the one on top of the stack.\r
      */\r
-    private int targetOffset = 0;\r
+    protected int targetOffset = 0;\r
 \r
     /**\r
      * The method name to call on the parent object.\r
@@ -380,7 +380,7 @@ public class CallMethodRule extends Rule {
      * The names of the classes of the parameters to be collected.\r
      * This attribute allows creation of the classes to be postponed until the digester is set.\r
      */\r
-    private String paramClassNames[] = null;\r
+    protected String paramClassNames[] = null;\r
     \r
     /**\r
      * Should <code>MethodUtils.invokeExactMethod</code> be used for reflection.\r