1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19 package org.apache.catalina.core;
20
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.Serializable;
25 import java.lang.reflect.InvocationTargetException;
26 import java.util.ArrayList;
27 import java.util.Enumeration;
28 import java.util.Map;
29 import java.util.Properties;
30
31 import javax.naming.NamingException;
32 import javax.servlet.Filter;
33 import javax.servlet.FilterConfig;
34 import javax.servlet.ServletContext;
35 import javax.servlet.ServletException;
36
37 import org.apache.AnnotationProcessor;
38 import org.apache.catalina.Context;
39 import org.apache.catalina.Globals;
40 import org.apache.catalina.deploy.FilterDef;
41 import org.apache.catalina.security.SecurityUtil;
42 import org.apache.catalina.util.Enumerator;
43 import org.apache.catalina.util.StringManager;
44 import org.apache.tomcat.util.log.SystemLogHandler;
45
46
47 /**
48 * Implementation of a <code>javax.servlet.FilterConfig</code> useful in
49 * managing the filter instances instantiated when a web application
50 * is first started.
51 *
52 * @author Craig R. McClanahan
53 * @version $Revision: 505593 $ $Date: 2007-02-10 01:54:56 +0100 (sam., 10 févr. 2007) $
54 */
55
56 final class ApplicationFilterConfig implements FilterConfig, Serializable {
57
58
59 protected static StringManager sm =
60 StringManager.getManager(Constants.Package);
61
62 // ----------------------------------------------------------- Constructors
63
64
65 /**
66 * Construct a new ApplicationFilterConfig for the specified filter
67 * definition.
68 *
69 * @param context The context with which we are associated
70 * @param filterDef Filter definition for which a FilterConfig is to be
71 * constructed
72 *
73 * @exception ClassCastException if the specified class does not implement
74 * the <code>javax.servlet.Filter</code> interface
75 * @exception ClassNotFoundException if the filter class cannot be found
76 * @exception IllegalAccessException if the filter class cannot be
77 * publicly instantiated
78 * @exception InstantiationException if an exception occurs while
79 * instantiating the filter object
80 * @exception ServletException if thrown by the filter's init() method
81 * @throws NamingException
82 * @throws InvocationTargetException
83 */
84 public ApplicationFilterConfig(Context context, FilterDef filterDef)
85 throws ClassCastException, ClassNotFoundException,
86 IllegalAccessException, InstantiationException,
87 ServletException, InvocationTargetException, NamingException {
88
89 super();
90
91 if (restrictedFilters == null) {
92 restrictedFilters = new Properties();
93 try {
94 InputStream is =
95 this.getClass().getClassLoader().getResourceAsStream
96 ("org/apache/catalina/core/RestrictedFilters.properties");
97 if (is != null) {
98 restrictedFilters.load(is);
99 } else {
100 context.getLogger().error(sm.getString("applicationFilterConfig.restrictedFiltersResources"));
101 }
102 } catch (IOException e) {
103 context.getLogger().error(sm.getString("applicationFilterConfig.restrictedServletsResources"), e);
104 }
105 }
106
107 this.context = context;
108 setFilterDef(filterDef);
109
110 }
111
112
113 // ----------------------------------------------------- Instance Variables
114
115
116 /**
117 * The Context with which we are associated.
118 */
119 private Context context = null;
120
121
122 /**
123 * The application Filter we are configured for.
124 */
125 private transient Filter filter = null;
126
127
128 /**
129 * The <code>FilterDef</code> that defines our associated Filter.
130 */
131 private FilterDef filterDef = null;
132
133
134 /**
135 * Restricted filters (which can only be loaded by a privileged webapp).
136 */
137 protected static Properties restrictedFilters = null;
138
139
140 // --------------------------------------------------- FilterConfig Methods
141
142
143 /**
144 * Return the name of the filter we are configuring.
145 */
146 public String getFilterName() {
147
148 return (filterDef.getFilterName());
149
150 }
151
152
153 /**
154 * Return a <code>String</code> containing the value of the named
155 * initialization parameter, or <code>null</code> if the parameter
156 * does not exist.
157 *
158 * @param name Name of the requested initialization parameter
159 */
160 public String getInitParameter(String name) {
161
162 Map map = filterDef.getParameterMap();
163 if (map == null)
164 return (null);
165 else
166 return ((String) map.get(name));
167
168 }
169
170
171 /**
172 * Return an <code>Enumeration</code> of the names of the initialization
173 * parameters for this Filter.
174 */
175 public Enumeration getInitParameterNames() {
176
177 Map map = filterDef.getParameterMap();
178 if (map == null)
179 return (new Enumerator(new ArrayList()));
180 else
181 return (new Enumerator(map.keySet()));
182
183 }
184
185
186 /**
187 * Return the ServletContext of our associated web application.
188 */
189 public ServletContext getServletContext() {
190
191 return (this.context.getServletContext());
192
193 }
194
195
196 /**
197 * Return a String representation of this object.
198 */
199 public String toString() {
200
201 StringBuffer sb = new StringBuffer("ApplicationFilterConfig[");
202 sb.append("name=");
203 sb.append(filterDef.getFilterName());
204 sb.append(", filterClass=");
205 sb.append(filterDef.getFilterClass());
206 sb.append("]");
207 return (sb.toString());
208
209 }
210
211
212 // -------------------------------------------------------- Package Methods
213
214
215 /**
216 * Return the application Filter we are configured for.
217 *
218 * @exception ClassCastException if the specified class does not implement
219 * the <code>javax.servlet.Filter</code> interface
220 * @exception ClassNotFoundException if the filter class cannot be found
221 * @exception IllegalAccessException if the filter class cannot be
222 * publicly instantiated
223 * @exception InstantiationException if an exception occurs while
224 * instantiating the filter object
225 * @exception ServletException if thrown by the filter's init() method
226 * @throws NamingException
227 * @throws InvocationTargetException
228 */
229 Filter getFilter() throws ClassCastException, ClassNotFoundException,
230 IllegalAccessException, InstantiationException, ServletException,
231 InvocationTargetException, NamingException {
232
233 // Return the existing filter instance, if any
234 if (this.filter != null)
235 return (this.filter);
236
237 // Identify the class loader we will be using
238 String filterClass = filterDef.getFilterClass();
239 ClassLoader classLoader = null;
240 if (filterClass.startsWith("org.apache.catalina."))
241 classLoader = this.getClass().getClassLoader();
242 else
243 classLoader = context.getLoader().getClassLoader();
244
245 ClassLoader oldCtxClassLoader =
246 Thread.currentThread().getContextClassLoader();
247
248 // Instantiate a new instance of this filter and return it
249 Class clazz = classLoader.loadClass(filterClass);
250 if (!isFilterAllowed(clazz)) {
251 throw new SecurityException
252 (sm.getString("applicationFilterConfig.privilegedFilter",
253 filterClass));
254 }
255 this.filter = (Filter) clazz.newInstance();
256 if (!context.getIgnoreAnnotations()) {
257 if (context instanceof StandardContext) {
258 AnnotationProcessor processor = ((StandardContext)context).getAnnotationProcessor();
259 processor.processAnnotations(this.filter);
260 processor.postConstruct(this.filter);
261 }
262 }
263 if (context instanceof StandardContext &&
264 ((StandardContext) context).getSwallowOutput()) {
265 try {
266 SystemLogHandler.startCapture();
267 filter.init(this);
268 } finally {
269 String log = SystemLogHandler.stopCapture();
270 if (log != null && log.length() > 0) {
271 getServletContext().log(log);
272 }
273 }
274 } else {
275 filter.init(this);
276 }
277 return (this.filter);
278
279
280 }
281
282
283 /**
284 * Return the filter definition we are configured for.
285 */
286 FilterDef getFilterDef() {
287
288 return (this.filterDef);
289
290 }
291
292
293 /**
294 * Return <code>true</code> if loading this filter is allowed.
295 */
296 protected boolean isFilterAllowed(Class filterClass) {
297
298 // Privileged webapps may load all servlets without restriction
299 if (context.getPrivileged()) {
300 return true;
301 }
302
303 Class clazz = filterClass;
304 while (clazz != null && !clazz.getName().equals("javax.servlet.Filter")) {
305 if ("restricted".equals(restrictedFilters.getProperty(clazz.getName()))) {
306 return (false);
307 }
308 clazz = clazz.getSuperclass();
309 }
310
311 return (true);
312
313 }
314
315
316 /**
317 * Release the Filter instance associated with this FilterConfig,
318 * if there is one.
319 */
320 void release() {
321
322 if (this.filter != null)
323 {
324 if (Globals.IS_SECURITY_ENABLED) {
325 try {
326 SecurityUtil.doAsPrivilege("destroy", filter);
327 } catch(java.lang.Exception ex){
328 context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
329 }
330 SecurityUtil.remove(filter);
331 } else {
332 filter.destroy();
333 }
334 if (!context.getIgnoreAnnotations()) {
335 try {
336 ((StandardContext)context).getAnnotationProcessor().preDestroy(this.filter);
337 } catch (Exception e) {
338 context.getLogger().error("ApplicationFilterConfig.preDestroy", e);
339 }
340 }
341 }
342 this.filter = null;
343
344 }
345
346
347 /**
348 * Set the filter definition we are configured for. This has the side
349 * effect of instantiating an instance of the corresponding filter class.
350 *
351 * @param filterDef The new filter definition
352 *
353 * @exception ClassCastException if the specified class does not implement
354 * the <code>javax.servlet.Filter</code> interface
355 * @exception ClassNotFoundException if the filter class cannot be found
356 * @exception IllegalAccessException if the filter class cannot be
357 * publicly instantiated
358 * @exception InstantiationException if an exception occurs while
359 * instantiating the filter object
360 * @exception ServletException if thrown by the filter's init() method
361 * @throws NamingException
362 * @throws InvocationTargetException
363 */
364 void setFilterDef(FilterDef filterDef)
365 throws ClassCastException, ClassNotFoundException,
366 IllegalAccessException, InstantiationException,
367 ServletException, InvocationTargetException, NamingException {
368
369 this.filterDef = filterDef;
370 if (filterDef == null) {
371
372 // Release any previously allocated filter instance
373 if (this.filter != null){
374 if( Globals.IS_SECURITY_ENABLED) {
375 try{
376 SecurityUtil.doAsPrivilege("destroy", filter);
377 } catch(java.lang.Exception ex){
378 context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
379 }
380 SecurityUtil.remove(filter);
381 } else {
382 filter.destroy();
383 }
384 if (!context.getIgnoreAnnotations()) {
385 try {
386 ((StandardContext)context).getAnnotationProcessor().preDestroy(this.filter);
387 } catch (Exception e) {
388 context.getLogger().error("ApplicationFilterConfig.preDestroy", e);
389 }
390 }
391 }
392 this.filter = null;
393
394 } else {
395
396 // Allocate a new filter instance
397 Filter filter = getFilter();
398
399 }
400
401 }
402
403
404 // -------------------------------------------------------- Private Methods
405
406
407 }