View Javadoc

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