View Javadoc

1   // ========================================================================
2   // Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.annotations;
15  
16  import java.util.ArrayList;
17  import java.util.EnumSet;
18  
19  import javax.servlet.DispatcherType;
20  import javax.servlet.Filter;
21  import javax.servlet.annotation.WebFilter;
22  import javax.servlet.annotation.WebInitParam;
23  
24  import org.eclipse.jetty.servlet.FilterHolder;
25  import org.eclipse.jetty.servlet.FilterMapping;
26  import org.eclipse.jetty.servlet.Holder;
27  import org.eclipse.jetty.util.log.Log;
28  import org.eclipse.jetty.webapp.DiscoveredAnnotation;
29  import org.eclipse.jetty.webapp.MetaData;
30  import org.eclipse.jetty.webapp.WebAppContext;
31  import org.eclipse.jetty.webapp.Origin;
32  
33  /**
34   * WebFilterAnnotation
35   *
36   *
37   */
38  public class WebFilterAnnotation extends DiscoveredAnnotation
39  {
40  
41      /**
42       * @param context
43       * @param className
44       */
45      public WebFilterAnnotation(WebAppContext context, String className)
46      {
47          super(context, className);
48      }
49  
50      /** 
51       * @see org.eclipse.jetty.annotations.ClassAnnotation#apply()
52       */
53      public void apply()
54      {
55          // TODO verify against rules for annotation v descriptor
56          
57          Class clazz = getTargetClass();
58          if (clazz == null)
59          {
60              Log.warn(_className+" cannot be loaded");
61              return;
62          }
63          
64          
65          //Servlet Spec 8.1.2
66          if (!Filter.class.isAssignableFrom(clazz))
67          {
68              Log.warn(clazz.getName()+" is not assignable from javax.servlet.Filter");
69              return;
70          }
71          MetaData metaData = _context.getMetaData();
72          
73          WebFilter filterAnnotation = (WebFilter)clazz.getAnnotation(WebFilter.class);
74  
75          if (filterAnnotation.value().length > 0 && filterAnnotation.urlPatterns().length > 0)
76          {
77              Log.warn(clazz.getName()+" defines both @WebFilter.value and @WebFilter.urlPatterns");
78              return;
79          }
80  
81          String name = (filterAnnotation.filterName().equals("")?clazz.getName():filterAnnotation.filterName());
82          String[] urlPatterns = filterAnnotation.value();
83          if (urlPatterns.length == 0)
84              urlPatterns = filterAnnotation.urlPatterns();
85          
86          FilterHolder holder = _context.getServletHandler().getFilter(name);
87          if (holder == null)
88          {
89              //Filter with this name does not already exist, so add it
90              holder = _context.getServletHandler().newFilterHolder(Holder.Source.ANNOTATION);
91              holder.setName(name);
92              
93              holder.setHeldClass(clazz);
94              metaData.setOrigin(name+".filter.filter-class");
95   
96              holder.setDisplayName(filterAnnotation.displayName()); 
97              metaData.setOrigin(name+".filter.display-name");
98  
99              for (WebInitParam ip:  filterAnnotation.initParams())
100             {
101                 holder.setInitParameter(ip.name(), ip.value());
102                 metaData.setOrigin(name+".filter.init-param."+ip.name());
103             }
104 
105             FilterMapping mapping = new FilterMapping();
106             mapping.setFilterName(holder.getName());
107 
108             if (urlPatterns.length > 0)
109             {
110                 ArrayList paths = new ArrayList();
111                 for (String s:urlPatterns)
112                 {
113                     paths.add(Util.normalizePattern(s));
114                 }
115                 mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()]));
116             }
117 
118             if (filterAnnotation.servletNames().length > 0)
119             {
120                 ArrayList<String> names = new ArrayList<String>();
121                 for (String s : filterAnnotation.servletNames())
122                 {
123                     names.add(s);
124                 }
125                 mapping.setServletNames((String[])names.toArray(new String[names.size()]));
126             }
127 
128             EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class);           
129             for (DispatcherType d : filterAnnotation.dispatcherTypes())
130             {
131                 dispatcherSet.add(d);
132             }
133             mapping.setDispatcherTypes(dispatcherSet);
134             metaData.setOrigin(name+".filter.mappings");
135 
136             holder.setAsyncSupported(filterAnnotation.asyncSupported());
137             metaData.setOrigin(name+".filter.async-supported");
138 
139             _context.getServletHandler().addFilter(holder);
140             _context.getServletHandler().addFilterMapping(mapping);
141         }
142         else
143         {
144             //A Filter definition for the same name already exists from web.xml
145             //ServletSpec 3.0 p81 if the Filter is already defined and has mappings,
146             //they override the annotation. If it already has DispatcherType set, that
147             //also overrides the annotation. Init-params are additive, but web.xml overrides
148             //init-params of the same name.
149             for (WebInitParam ip:  filterAnnotation.initParams())
150             {
151                 //if (holder.getInitParameter(ip.name()) == null)
152                 if (metaData.getOrigin(name+".filter.init-param."+ip.name())==Origin.NotSet)
153                 {
154                     holder.setInitParameter(ip.name(), ip.value());
155                     metaData.setOrigin(name+".filter.init-param."+ip.name());
156                 }
157             }
158             
159             FilterMapping[] mappings = _context.getServletHandler().getFilterMappings();
160             boolean mappingExists = false;
161             if (mappings != null)
162             {
163                 for (FilterMapping m:mappings)
164                 {
165                     if (m.getFilterName().equals(name))
166                     {
167                         mappingExists = true;
168                         break;
169                     }
170                 }
171             }
172             //if a descriptor didn't specify at least one mapping, use the mappings from the annotation and the DispatcherTypes
173             //from the annotation
174             if (!mappingExists)
175             {
176                 FilterMapping mapping = new FilterMapping();
177                 mapping.setFilterName(holder.getName());
178 
179                 if (urlPatterns.length > 0)
180                 {
181                     ArrayList paths = new ArrayList();
182                     for (String s:urlPatterns)
183                     {
184                         paths.add(Util.normalizePattern(s));
185                     }
186                     mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()]));
187                 }
188                 if (filterAnnotation.servletNames().length > 0)
189                 {
190                     ArrayList<String> names = new ArrayList<String>();
191                     for (String s : filterAnnotation.servletNames())
192                     {
193                         names.add(s);
194                     }
195                     mapping.setServletNames((String[])names.toArray(new String[names.size()]));
196                 }
197                 
198                 EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class);           
199                 for (DispatcherType d : filterAnnotation.dispatcherTypes())
200                 {
201                     dispatcherSet.add(d);
202                 }
203                 mapping.setDispatcherTypes(dispatcherSet);
204                 _context.getServletHandler().addFilterMapping(mapping);   
205                 metaData.setOrigin(name+".filter.mappings");
206             }
207         }
208     }
209 
210 }