View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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  public class WebFilterAnnotation extends DiscoveredAnnotation
44  {
45      private static final Logger LOG = Log.getLogger(WebFilterAnnotation.class);
46  
47      public WebFilterAnnotation(WebAppContext context, String className)
48      {
49          super(context, className);
50      }
51      
52      public WebFilterAnnotation(WebAppContext context, String className, Resource resource)
53      {
54          super(context, className, resource);
55      }
56  
57      /**
58       * @see DiscoveredAnnotation#apply()
59       */
60      public void apply()
61      {
62          // TODO verify against rules for annotation v descriptor
63  
64          Class clazz = getTargetClass();
65          if (clazz == null)
66          {
67              LOG.warn(_className+" cannot be loaded");
68              return;
69          }
70  
71  
72          //Servlet Spec 8.1.2
73          if (!Filter.class.isAssignableFrom(clazz))
74          {
75              LOG.warn(clazz.getName()+" is not assignable from javax.servlet.Filter");
76              return;
77          }
78          MetaData metaData = _context.getMetaData();
79  
80          WebFilter filterAnnotation = (WebFilter)clazz.getAnnotation(WebFilter.class);
81  
82          if (filterAnnotation.value().length > 0 && filterAnnotation.urlPatterns().length > 0)
83          {
84              LOG.warn(clazz.getName()+" defines both @WebFilter.value and @WebFilter.urlPatterns");
85              return;
86          }
87  
88          String name = (filterAnnotation.filterName().equals("")?clazz.getName():filterAnnotation.filterName());
89          String[] urlPatterns = filterAnnotation.value();
90          if (urlPatterns.length == 0)
91              urlPatterns = filterAnnotation.urlPatterns();
92  
93          FilterHolder holder = _context.getServletHandler().getFilter(name);
94          if (holder == null)
95          {
96              //Filter with this name does not already exist, so add it
97              holder = _context.getServletHandler().newFilterHolder(Holder.Source.ANNOTATION);
98              holder.setName(name);
99  
100             holder.setHeldClass(clazz);
101             metaData.setOrigin(name+".filter.filter-class",filterAnnotation,clazz);
102 
103             holder.setDisplayName(filterAnnotation.displayName());
104             metaData.setOrigin(name+".filter.display-name",filterAnnotation,clazz);
105 
106             for (WebInitParam ip:  filterAnnotation.initParams())
107             {
108                 holder.setInitParameter(ip.name(), ip.value());
109                 metaData.setOrigin(name+".filter.init-param."+ip.name(),ip,clazz);
110             }
111 
112             FilterMapping mapping = new FilterMapping();
113             mapping.setFilterName(holder.getName());
114 
115             if (urlPatterns.length > 0)
116             {
117                 ArrayList<String> paths = new ArrayList<String>();
118                 for (String s:urlPatterns)
119                 {
120                     paths.add(Util.normalizePattern(s));
121                 }
122                 mapping.setPathSpecs(paths.toArray(new String[paths.size()]));
123             }
124 
125             if (filterAnnotation.servletNames().length > 0)
126             {
127                 ArrayList<String> names = new ArrayList<String>();
128                 for (String s : filterAnnotation.servletNames())
129                 {
130                     names.add(s);
131                 }
132                 mapping.setServletNames(names.toArray(new String[names.size()]));
133             }
134 
135             EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class);
136             for (DispatcherType d : filterAnnotation.dispatcherTypes())
137             {
138                 dispatcherSet.add(d);
139             }
140             mapping.setDispatcherTypes(dispatcherSet);
141             metaData.setOrigin(name+".filter.mappings",filterAnnotation,clazz);
142 
143             holder.setAsyncSupported(filterAnnotation.asyncSupported());
144             metaData.setOrigin(name+".filter.async-supported",filterAnnotation,clazz);
145 
146             _context.getServletHandler().addFilter(holder);
147             _context.getServletHandler().addFilterMapping(mapping);
148         }
149         else
150         {
151             //A Filter definition for the same name already exists from web.xml
152             //ServletSpec 3.0 p81 if the Filter is already defined and has mappings,
153             //they override the annotation. If it already has DispatcherType set, that
154             //also overrides the annotation. Init-params are additive, but web.xml overrides
155             //init-params of the same name.
156             for (WebInitParam ip:  filterAnnotation.initParams())
157             {
158                 //if (holder.getInitParameter(ip.name()) == null)
159                 if (metaData.getOrigin(name+".filter.init-param."+ip.name())==Origin.NotSet)
160                 {
161                     holder.setInitParameter(ip.name(), ip.value());
162                     metaData.setOrigin(name+".filter.init-param."+ip.name(),ip,clazz);
163                 }
164             }
165 
166             FilterMapping[] mappings = _context.getServletHandler().getFilterMappings();
167             boolean mappingExists = false;
168             if (mappings != null)
169             {
170                 for (FilterMapping m:mappings)
171                 {
172                     if (m.getFilterName().equals(name))
173                     {
174                         mappingExists = true;
175                         break;
176                     }
177                 }
178             }
179             //if a descriptor didn't specify at least one mapping, use the mappings from the annotation and the DispatcherTypes
180             //from the annotation
181             if (!mappingExists)
182             {
183                 FilterMapping mapping = new FilterMapping();
184                 mapping.setFilterName(holder.getName());
185 
186                 if (urlPatterns.length > 0)
187                 {
188                     ArrayList<String> paths = new ArrayList<String>();
189                     for (String s:urlPatterns)
190                     {
191                         paths.add(Util.normalizePattern(s));
192                     }
193                     mapping.setPathSpecs(paths.toArray(new String[paths.size()]));
194                 }
195                 if (filterAnnotation.servletNames().length > 0)
196                 {
197                     ArrayList<String> names = new ArrayList<String>();
198                     for (String s : filterAnnotation.servletNames())
199                     {
200                         names.add(s);
201                     }
202                     mapping.setServletNames(names.toArray(new String[names.size()]));
203                 }
204 
205                 EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class);
206                 for (DispatcherType d : filterAnnotation.dispatcherTypes())
207                 {
208                     dispatcherSet.add(d);
209                 }
210                 mapping.setDispatcherTypes(dispatcherSet);
211                 _context.getServletHandler().addFilterMapping(mapping);
212                 metaData.setOrigin(name+".filter.mappings",filterAnnotation,clazz);
213             }
214         }
215     }
216 
217 }