From: pero Date: Fri, 30 Apr 2010 11:23:41 +0000 (+0000) Subject: web.xml or fragment must merge with annotations s. Servlet Spec 3.0 8.2.3 X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=4248ff083ca3cb14bc6dcebe1f9dcd03f5cefb0f;p=tomcat7.0 web.xml or fragment must merge with annotations s. Servlet Spec 3.0 8.2.3 git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@939638 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java index 27b9307a4..af9ecf1bd 100644 --- a/java/org/apache/catalina/startup/ContextConfig.java +++ b/java/org/apache/catalina/startup/ContextConfig.java @@ -1970,8 +1970,6 @@ public class ContextConfig .getValue()); } } - } else { - // Ignore } } if (!isWebXMLservletDef && urlPatterns != null) { @@ -1987,20 +1985,43 @@ public class ContextConfig } + /** + * process filter annotation and merge with existing one! + * FIXME: refactoring method to long and has redundant subroutines with processAnnotationWebServlet! + * @param className + * @param ae + * @param fragment + */ protected void processAnnotationWebFilter(String className, AnnotationEntry ae, WebXml fragment) { - if (fragment.getFilters().containsKey(className)) { - // Skip this annotation. Entry in web.xml takes priority - return; + String filterName = null; + // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81 + ElementValuePair[] evps = ae.getElementValuePairs(); + for (ElementValuePair evp : evps) { + String name = evp.getNameString(); + if ("filterName".equals(name)) { + filterName = evp.getValue().stringifyValue(); + break; + } } - boolean urlPatternsSet = false; - FilterDef filterDef = new FilterDef(); + if (filterName == null) { + // classname is default filterName as annotation has no name! + filterName = className; + } + FilterDef filterDef = fragment.getFilters().get(filterName); FilterMap filterMap = new FilterMap(); - filterDef.setFilterName(className); - filterDef.setFilterClass(className); + + boolean isWebXMLfilterDef = filterDef != null; + if (!isWebXMLfilterDef) { + filterDef = new FilterDef(); + filterDef.setFilterName(filterName); + filterDef.setFilterClass(className); + } + + boolean urlPatternsSet = false; + boolean dispatchTypesSet = false; String[] urlPatterns = null; - ElementValuePair[] evps = ae.getElementValuePairs(); for (ElementValuePair evp : evps) { String name = evp.getNameString(); if ("value".equals(name) || "urlPatterns".equals(name)) { @@ -2008,49 +2029,101 @@ public class ContextConfig throw new IllegalArgumentException(sm.getString( "contextConfig.urlPatternValue", className)); } - urlPatternsSet = true; urlPatterns = processAnnotationsStringArray(evp.getValue()); + urlPatternsSet = urlPatterns != null && urlPatterns.length > 0; for (String urlPattern : urlPatterns) { filterMap.addURLPattern(urlPattern); } - } else if ("filterName".equals(name)) { - filterDef.setFilterName(evp.getValue().stringifyValue()); } else if ("servletNames".equals(name)) { - String[] servletNames = - processAnnotationsStringArray(evp.getValue()); + String[] servletNames = processAnnotationsStringArray(evp + .getValue()); for (String servletName : servletNames) { filterMap.addServletName(servletName); } } else if ("dispatcherTypes".equals(name)) { - String[] dispatcherTypes = - processAnnotationsStringArray(evp.getValue()); + String[] dispatcherTypes = processAnnotationsStringArray(evp + .getValue()); + dispatchTypesSet = dispatcherTypes != null + && dispatcherTypes.length > 0; for (String dispatcherType : dispatcherTypes) { filterMap.setDispatcher(dispatcherType); } } else if ("description".equals(name)) { - filterDef.setDescription(evp.getValue().stringifyValue()); + if (filterDef.getDescription() == null) { + filterDef.setDescription(evp.getValue().stringifyValue()); + } } else if ("displayName".equals(name)) { - filterDef.setDisplayName(evp.getValue().stringifyValue()); + if (filterDef.getDisplayName() == null) { + filterDef.setDisplayName(evp.getValue().stringifyValue()); + } } else if ("largeIcon".equals(name)) { - filterDef.setLargeIcon(evp.getValue().stringifyValue()); + if (filterDef.getLargeIcon() == null) { + filterDef.setLargeIcon(evp.getValue().stringifyValue()); + } } else if ("smallIcon".equals(name)) { - filterDef.setSmallIcon(evp.getValue().stringifyValue()); + if (filterDef.getSmallIcon() == null) { + filterDef.setSmallIcon(evp.getValue().stringifyValue()); + } } else if ("asyncSupported".equals(name)) { - filterDef.setAsyncSupported(evp.getValue().stringifyValue()); + if (filterDef.getAsyncSupported() == null) { + filterDef + .setAsyncSupported(evp.getValue().stringifyValue()); + } } else if ("initParams".equals(name)) { - Map initParams = - processAnnotationWebInitParams(evp.getValue()); - for (Map.Entry entry : initParams.entrySet()) { - filterDef.addInitParameter(entry.getKey(), - entry.getValue()); + Map initParams = processAnnotationWebInitParams(evp + .getValue()); + if (isWebXMLfilterDef) { + Map webXMLInitParams = filterDef + .getParameterMap(); + for (Map.Entry entry : initParams + .entrySet()) { + if (webXMLInitParams.get(entry.getKey()) == null) { + filterDef.addInitParameter(entry.getKey(), entry + .getValue()); + } + } + } else { + for (Map.Entry entry : initParams + .entrySet()) { + filterDef.addInitParameter(entry.getKey(), entry + .getValue()); + } + } + + } + } + if (!isWebXMLfilterDef) { + fragment.addFilter(filterDef); + filterMap.setFilterName(filterName); + fragment.addFilterMapping(filterMap); + } + if (urlPatternsSet || dispatchTypesSet) { + Set fmap = fragment.getFilterMappings(); + FilterMap descMap = null; + for (FilterMap map : fmap) { + if (filterName.equals(map.getFilterName())) { + descMap = map; + break; + } + } + if (descMap != null) { + String[] urlsPatterns = descMap.getURLPatterns(); + if (urlPatternsSet + && (urlsPatterns == null || urlsPatterns.length == 0)) { + for (String urlPattern : filterMap.getURLPatterns()) { + descMap.addURLPattern(urlPattern); + } + } + String[] dispatcherNames = descMap.getDispatcherNames(); + if (dispatchTypesSet + && (dispatcherNames == null || dispatcherNames.length == 0)) { + for (String dis : filterMap.getDispatcherNames()) { + descMap.setDispatcher(dis); + } } - } else { - // Ignore } } - fragment.addFilter(filterDef); - filterMap.setFilterName(filterDef.getFilterName()); - fragment.addFilterMapping(filterMap); + } protected String[] processAnnotationsStringArray(ElementValue ev) { diff --git a/test/org/apache/catalina/startup/DuplicateMappingParamFilter.java b/test/org/apache/catalina/startup/DuplicateMappingParamFilter.java new file mode 100644 index 000000000..1d15e6be7 --- /dev/null +++ b/test/org/apache/catalina/startup/DuplicateMappingParamFilter.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.startup; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; + +/** + * Test Mock with wrong Annotation! + * + * @author Peter Rossbach + * @version $Id$ + * + */ +@WebFilter(value = "/param", filterName="paramDFilter", + urlPatterns = { "/param1" , "/param2" }) +public class DuplicateMappingParamFilter implements Filter { + + + public void init(FilterConfig filterConfig) throws ServletException { + } + + public void doFilter(ServletRequest req, ServletResponse res, + FilterChain chain) throws ServletException, IOException { + chain.doFilter(req, res); + } + + public void destroy() { + // destroy + } +} + diff --git a/test/org/apache/catalina/startup/DuplicateMappingParamServlet.java b/test/org/apache/catalina/startup/DuplicateMappingParamServlet.java index 9407bde20..eba4f8708 100644 --- a/test/org/apache/catalina/startup/DuplicateMappingParamServlet.java +++ b/test/org/apache/catalina/startup/DuplicateMappingParamServlet.java @@ -27,9 +27,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** + * Test Mock with wrong Annotation! * * @author Peter Rossbach - * @version $Id$ + * @version $Id: DuplicateMappingParamServlet.java 939221 2010-04-29 07:30:29Z + * kkolinko $ */ @WebServlet(value = "/annotation/overwrite", urlPatterns = { "/param2" }, name = "param", initParams = { @WebInitParam(name = "foo", value = "Hello"), diff --git a/test/org/apache/catalina/startup/ParamFilter.java b/test/org/apache/catalina/startup/ParamFilter.java new file mode 100644 index 000000000..8f37cdcbf --- /dev/null +++ b/test/org/apache/catalina/startup/ParamFilter.java @@ -0,0 +1,56 @@ +package org.apache.catalina.startup; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import javax.servlet.annotation.WebInitParam; + +/** + * Test Mock to check Filter Annotations + * @author Peter Rossbach + * @version $Id$ + */ +@WebFilter(value = "/param", filterName = "paramFilter", dispatcherTypes = { + DispatcherType.ERROR, DispatcherType.ASYNC }, initParams = { @WebInitParam(name = "message", value = "Servlet says: ") }) +public class ParamFilter implements Filter { + + private FilterConfig _filterConfig; + + public void init(FilterConfig filterConfig) throws ServletException { + _filterConfig = filterConfig; + } + + public void doFilter(ServletRequest req, ServletResponse res, + FilterChain chain) throws ServletException, IOException { + PrintWriter out = res.getWriter(); + out.print(_filterConfig.getInitParameter("message")); + chain.doFilter(req, res); + } + + public void destroy() { + // destroy + } +} diff --git a/test/org/apache/catalina/startup/TestContextConfigAnnotation.java b/test/org/apache/catalina/startup/TestContextConfigAnnotation.java index 7af538e64..07d490f1e 100644 --- a/test/org/apache/catalina/startup/TestContextConfigAnnotation.java +++ b/test/org/apache/catalina/startup/TestContextConfigAnnotation.java @@ -17,9 +17,14 @@ package org.apache.catalina.startup; import java.io.File; +import java.util.Set; + +import javax.servlet.DispatcherType; import junit.framework.TestCase; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.deploy.ServletDef; import org.apache.catalina.deploy.WebXml; @@ -35,7 +40,7 @@ public class TestContextConfigAnnotation extends TestCase { public void testAnnotation() throws Exception { WebXml webxml = new WebXml(); ContextConfig config = new ContextConfig(); - File pFile = paramServletClassResource("org/apache/catalina/startup/ParamServlet"); + File pFile = paramClassResource("org/apache/catalina/startup/ParamServlet"); assertTrue(pFile.exists()); config.processAnnotationsFile(pFile, webxml); ServletDef servletDef = webxml.getServlets().get("param"); @@ -72,7 +77,7 @@ public class TestContextConfigAnnotation extends TestCase { webxml.addServlet(servletDef); webxml.addServletMapping("/param", "param"); ContextConfig config = new ContextConfig(); - File pFile = paramServletClassResource("org/apache/catalina/startup/ParamServlet"); + File pFile = paramClassResource("org/apache/catalina/startup/ParamServlet"); assertTrue(pFile.exists()); config.processAnnotationsFile(pFile, webxml); @@ -81,7 +86,7 @@ public class TestContextConfigAnnotation extends TestCase { assertEquals("tomcat", servletDef.getParameterMap().get("foo")); assertEquals("param", webxml.getServletMappings().get("/param")); // annotation mapping not added s. Servlet Spec 3.0 (Nov 2009) - // 8.2.3.3.vi page 81 + // 8.2.3.3.iv page 81 assertNull(webxml.getServletMappings().get("/annotation/overwrite")); assertEquals("Description", servletDef.getDescription()); @@ -97,7 +102,7 @@ public class TestContextConfigAnnotation extends TestCase { public void testNoMapping() throws Exception { WebXml webxml = new WebXml(); ContextConfig config = new ContextConfig(); - File pFile = paramServletClassResource("org/apache/catalina/startup/NoMappingParamServlet"); + File pFile = paramClassResource("org/apache/catalina/startup/NoMappingParamServlet"); assertTrue(pFile.exists()); config.processAnnotationsFile(pFile, webxml); ServletDef servletDef = webxml.getServlets().get("param1"); @@ -121,7 +126,7 @@ public class TestContextConfigAnnotation extends TestCase { webxml.addServlet(servletDef); webxml.addServletMapping("/param", "param1"); ContextConfig config = new ContextConfig(); - File pFile = paramServletClassResource("org/apache/catalina/startup/NoMappingParamServlet"); + File pFile = paramClassResource("org/apache/catalina/startup/NoMappingParamServlet"); assertTrue(pFile.exists()); config.processAnnotationsFile(pFile, webxml); assertEquals("tomcat", servletDef.getParameterMap().get("foo")); @@ -134,7 +139,7 @@ public class TestContextConfigAnnotation extends TestCase { public void testDuplicateMapping() throws Exception { WebXml webxml = new WebXml(); ContextConfig config = new ContextConfig(); - File pFile = paramServletClassResource("org/apache/catalina/startup/DuplicateMappingParamServlet"); + File pFile = paramClassResource("org/apache/catalina/startup/DuplicateMappingParamServlet"); assertTrue(pFile.exists()); try { config.processAnnotationsFile(pFile, webxml); @@ -146,13 +151,92 @@ public class TestContextConfigAnnotation extends TestCase { assertNull(servletDef); } + public void testFilterMapping() throws Exception { + WebXml webxml = new WebXml(); + ContextConfig config = new ContextConfig(); + File sFile = paramClassResource("org/apache/catalina/startup/ParamServlet"); + config.processAnnotationsFile(sFile, webxml); + File fFile = paramClassResource("org/apache/catalina/startup/ParamFilter"); + config.processAnnotationsFile(fFile, webxml); + FilterDef fdef = webxml.getFilters().get("paramFilter"); + assertNotNull(fdef); + assertEquals("Servlet says: ",fdef.getParameterMap().get("message")); + } + + public void testOverwriteFilterMapping() throws Exception { + WebXml webxml = new WebXml(); + FilterDef filterDef = new FilterDef(); + filterDef.setFilterName("paramFilter"); + filterDef.setFilterClass("org.apache.catalina.startup.ParamFilter"); + filterDef.addInitParameter("message", "tomcat"); + filterDef.setDescription("Description"); + filterDef.setDisplayName("DisplayName"); + filterDef.setLargeIcon("LargeIcon"); + filterDef.setSmallIcon("SmallIcon"); + filterDef.setAsyncSupported("true"); + + + webxml.addFilter(filterDef); + FilterMap filterMap = new FilterMap(); + filterMap.addURLPattern("/param1"); + filterMap.setFilterName("paramFilter"); + webxml.addFilterMapping(filterMap); + + ContextConfig config = new ContextConfig(); + File sFile = paramClassResource("org/apache/catalina/startup/ParamServlet"); + config.processAnnotationsFile(sFile, webxml); + File fFile = paramClassResource("org/apache/catalina/startup/ParamFilter"); + config.processAnnotationsFile(fFile, webxml); + FilterDef fdef = webxml.getFilters().get("paramFilter"); + assertNotNull(fdef); + assertEquals(filterDef,fdef); + assertEquals("tomcat",fdef.getParameterMap().get("message")); + Set filterMappings = webxml.getFilterMappings(); + assertTrue(filterMappings.contains(filterMap)); + // annotation mapping not added s. Servlet Spec 3.0 (Nov 2009) + // 8.2.3.3.vi page 81 + String[] urlPatterns = filterMap.getURLPatterns(); + assertNotNull(urlPatterns); + assertEquals(1,urlPatterns.length); + assertEquals("/param1",urlPatterns[0]); + + // check simple Parameter + assertEquals("Description", fdef.getDescription()); + assertEquals("DisplayName", fdef.getDisplayName()); + assertEquals("LargeIcon", fdef.getLargeIcon()); + assertEquals("SmallIcon", fdef.getSmallIcon()); + // FIXME: Strange why servletDef is Boolean and FilterDef is String? + assertEquals("true", fdef.getAsyncSupported()); + + String[] dis = filterMap.getDispatcherNames(); + assertEquals(2, dis.length); + assertEquals(DispatcherType.ERROR.toString(),dis[0]); + assertEquals(DispatcherType.ASYNC.toString(),dis[1]); + + } + + public void testDuplicateFilterMapping() throws Exception { + WebXml webxml = new WebXml(); + ContextConfig config = new ContextConfig(); + File pFile = paramClassResource("org/apache/catalina/startup/DuplicateMappingParamFilter"); + assertTrue(pFile.exists()); + try { + config.processAnnotationsFile(pFile, webxml); + fail(); + } catch (IllegalArgumentException ex) { + // ingore + } + FilterDef filterDef = webxml.getFilters().get("paramD"); + assertNull(filterDef); + } + /** * Find newest class resource at eclipse and ant standard class output dirs! * * @param className * @return File Resource */ - private File paramServletClassResource(String className) { + private File paramClassResource(String className) { File antFile = new File("output/testclasses/" + className + ".class"); File eclipseFile = new File(".settings/output/" + className + ".class"); if (antFile.exists()) {