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