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.Collections;
28 import java.util.Enumeration;
29 import java.util.Map;
30 import java.util.Properties;
31
32 import javax.management.ObjectName;
33 import javax.naming.NamingException;
34 import javax.servlet.Filter;
35 import javax.servlet.FilterConfig;
36 import javax.servlet.ServletContext;
37 import javax.servlet.ServletException;
38
39 import org.apache.AnnotationProcessor;
40 import org.apache.catalina.Context;
41 import org.apache.catalina.Globals;
42 import org.apache.catalina.deploy.FilterDef;
43 import org.apache.catalina.security.SecurityUtil;
44 import org.apache.catalina.util.Enumerator;
45 import org.apache.catalina.util.StringManager;
46 import org.apache.juli.logging.LogFactory;
47 import org.apache.tomcat.util.log.SystemLogHandler;
48 import org.apache.tomcat.util.modeler.Registry;
49
50
51 /**
52 * Implementation of a <code>javax.servlet.FilterConfig</code> useful in
53 * managing the filter instances instantiated when a web application
54 * is first started.
55 *
56 * @author Craig R. McClanahan
57 * @version $Revision: 812133 $ $Date: 2009-09-07 15:37:06 +0200 (Mon, 07 Sep 2009) $
58 */
59
60 public final class ApplicationFilterConfig implements FilterConfig, Serializable {
61
62
63 protected static StringManager sm =
64 StringManager.getManager(Constants.Package);
65
66 private static org.apache.juli.logging.Log log =
67 LogFactory.getLog(ApplicationFilterConfig.class);
68
69 // ----------------------------------------------------------- Constructors
70
71
72 /**
73 * Construct a new ApplicationFilterConfig for the specified filter
74 * definition.
75 *
76 * @param context The context with which we are associated
77 * @param filterDef Filter definition for which a FilterConfig is to be
78 * constructed
79 *
80 * @exception ClassCastException if the specified class does not implement
81 * the <code>javax.servlet.Filter</code> interface
82 * @exception ClassNotFoundException if the filter class cannot be found
83 * @exception IllegalAccessException if the filter class cannot be
84 * publicly instantiated
85 * @exception InstantiationException if an exception occurs while
86 * instantiating the filter object
87 * @exception ServletException if thrown by the filter's init() method
88 * @throws NamingException
89 * @throws InvocationTargetException
90 */
91 ApplicationFilterConfig(Context context, FilterDef filterDef)
92 throws ClassCastException, ClassNotFoundException,
93 IllegalAccessException, InstantiationException,
94 ServletException, InvocationTargetException, NamingException {
95
96 super();
97
98 if (restrictedFilters == null) {
99 restrictedFilters = new Properties();
100 try {
101 InputStream is =
102 this.getClass().getClassLoader().getResourceAsStream
103 ("org/apache/catalina/core/RestrictedFilters.properties");
104 if (is != null) {
105 restrictedFilters.load(is);
106 } else {
107 context.getLogger().error(sm.getString("applicationFilterConfig.restrictedFiltersResources"));
108 }
109 } catch (IOException e) {
110 context.getLogger().error(sm.getString("applicationFilterConfig.restrictedServletsResources"), e);
111 }
112 }
113
114 this.context = context;
115 setFilterDef(filterDef);
116
117 }
118
119
120 // ----------------------------------------------------- Instance Variables
121
122
123 /**
124 * The Context with which we are associated.
125 */
126 private Context context = null;
127
128
129 /**
130 * The application Filter we are configured for.
131 */
132 private transient Filter filter = null;
133
134
135 /**
136 * The <code>FilterDef</code> that defines our associated Filter.
137 */
138 private FilterDef filterDef = null;
139
140
141 /**
142 * Restricted filters (which can only be loaded by a privileged webapp).
143 */
144 protected static Properties restrictedFilters = null;
145
146 /**
147 * JMX registration name
148 */
149 private ObjectName oname;
150
151 // --------------------------------------------------- FilterConfig Methods
152
153
154 /**
155 * Return the name of the filter we are configuring.
156 */
157 public String getFilterName() {
158 return (filterDef.getFilterName());
159 }
160
161 /**
162 * Return the class of the filter we are configuring.
163 */
164 public String getFilterClass() {
165 return filterDef.getFilterClass();
166 }
167
168 /**
169 * Return a <code>String</code> containing the value of the named
170 * initialization parameter, or <code>null</code> if the parameter
171 * does not exist.
172 *
173 * @param name Name of the requested initialization parameter
174 */
175 public String getInitParameter(String name) {
176
177 Map map = filterDef.getParameterMap();
178 if (map == null)
179 return (null);
180 else
181 return ((String) map.get(name));
182
183 }
184
185
186 /**
187 * Return an <code>Enumeration</code> of the names of the initialization
188 * parameters for this Filter.
189 */
190 public Enumeration getInitParameterNames() {
191
192 Map map = filterDef.getParameterMap();
193 if (map == null)
194 return (new Enumerator(new ArrayList()));
195 else
196 return (new Enumerator(map.keySet()));
197
198 }
199
200
201 /**
202 * Return the ServletContext of our associated web application.
203 */
204 public ServletContext getServletContext() {
205
206 return (this.context.getServletContext());
207
208 }
209
210
211 /**
212 * Return a String representation of this object.
213 */
214 public String toString() {
215
216 StringBuffer sb = new StringBuffer("ApplicationFilterConfig[");
217 sb.append("name=");
218 sb.append(filterDef.getFilterName());
219 sb.append(", filterClass=");
220 sb.append(filterDef.getFilterClass());
221 sb.append("]");
222 return (sb.toString());
223
224 }
225
226 // --------------------------------------------------------- Public Methods
227
228 public Map<String, String> getFilterInitParameterMap() {
229 return Collections.unmodifiableMap(filterDef.getParameterMap());
230 }
231
232 // -------------------------------------------------------- Package Methods
233
234
235 /**
236 * Return the application Filter we are configured for.
237 *
238 * @exception ClassCastException if the specified class does not implement
239 * the <code>javax.servlet.Filter</code> interface
240 * @exception ClassNotFoundException if the filter class cannot be found
241 * @exception IllegalAccessException if the filter class cannot be
242 * publicly instantiated
243 * @exception InstantiationException if an exception occurs while
244 * instantiating the filter object
245 * @exception ServletException if thrown by the filter's init() method
246 * @throws NamingException
247 * @throws InvocationTargetException
248 */
249 Filter getFilter() throws ClassCastException, ClassNotFoundException,
250 IllegalAccessException, InstantiationException, ServletException,
251 InvocationTargetException, NamingException {
252
253 // Return the existing filter instance, if any
254 if (this.filter != null)
255 return (this.filter);
256
257 // Identify the class loader we will be using
258 String filterClass = filterDef.getFilterClass();
259 ClassLoader classLoader = null;
260 if (filterClass.startsWith("org.apache.catalina."))
261 classLoader = this.getClass().getClassLoader();
262 else
263 classLoader = context.getLoader().getClassLoader();
264
265 ClassLoader oldCtxClassLoader =
266 Thread.currentThread().getContextClassLoader();
267
268 // Instantiate a new instance of this filter and return it
269 Class clazz = classLoader.loadClass(filterClass);
270 if (!isFilterAllowed(clazz)) {
271 throw new SecurityException
272 (sm.getString("applicationFilterConfig.privilegedFilter",
273 filterClass));
274 }
275 this.filter = (Filter) clazz.newInstance();
276 if (!context.getIgnoreAnnotations()) {
277 if (context instanceof StandardContext) {
278 AnnotationProcessor processor = ((StandardContext)context).getAnnotationProcessor();
279 processor.processAnnotations(this.filter);
280 processor.postConstruct(this.filter);
281 }
282 }
283 if (context instanceof StandardContext &&
284 ((StandardContext) context).getSwallowOutput()) {
285 try {
286 SystemLogHandler.startCapture();
287 filter.init(this);
288 } finally {
289 String log = SystemLogHandler.stopCapture();
290 if (log != null && log.length() > 0) {
291 getServletContext().log(log);
292 }
293 }
294 } else {
295 filter.init(this);
296 }
297
298 // Expose filter via JMX
299 registerJMX();
300
301 return (this.filter);
302
303 }
304
305
306 /**
307 * Return the filter definition we are configured for.
308 */
309 FilterDef getFilterDef() {
310
311 return (this.filterDef);
312
313 }
314
315
316 /**
317 * Return <code>true</code> if loading this filter is allowed.
318 */
319 protected boolean isFilterAllowed(Class filterClass) {
320
321 // Privileged webapps may load all servlets without restriction
322 if (context.getPrivileged()) {
323 return true;
324 }
325
326 Class clazz = filterClass;
327 while (clazz != null && !clazz.getName().equals("javax.servlet.Filter")) {
328 if ("restricted".equals(restrictedFilters.getProperty(clazz.getName()))) {
329 return (false);
330 }
331 clazz = clazz.getSuperclass();
332 }
333
334 return (true);
335
336 }
337
338
339 /**
340 * Release the Filter instance associated with this FilterConfig,
341 * if there is one.
342 */
343 void release() {
344
345 unregisterJMX();
346
347 if (this.filter != null)
348 {
349 if (Globals.IS_SECURITY_ENABLED) {
350 try {
351 SecurityUtil.doAsPrivilege("destroy", filter);
352 } catch(java.lang.Exception ex){
353 context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
354 }
355 SecurityUtil.remove(filter);
356 } else {
357 filter.destroy();
358 }
359 if (!context.getIgnoreAnnotations()) {
360 try {
361 ((StandardContext)context).getAnnotationProcessor().preDestroy(this.filter);
362 } catch (Exception e) {
363 context.getLogger().error("ApplicationFilterConfig.preDestroy", e);
364 }
365 }
366 }
367 this.filter = null;
368
369 }
370
371
372 /**
373 * Set the filter definition we are configured for. This has the side
374 * effect of instantiating an instance of the corresponding filter class.
375 *
376 * @param filterDef The new filter definition
377 *
378 * @exception ClassCastException if the specified class does not implement
379 * the <code>javax.servlet.Filter</code> interface
380 * @exception ClassNotFoundException if the filter class cannot be found
381 * @exception IllegalAccessException if the filter class cannot be
382 * publicly instantiated
383 * @exception InstantiationException if an exception occurs while
384 * instantiating the filter object
385 * @exception ServletException if thrown by the filter's init() method
386 * @throws NamingException
387 * @throws InvocationTargetException
388 */
389 void setFilterDef(FilterDef filterDef)
390 throws ClassCastException, ClassNotFoundException,
391 IllegalAccessException, InstantiationException,
392 ServletException, InvocationTargetException, NamingException {
393
394 this.filterDef = filterDef;
395 if (filterDef == null) {
396
397 // Release any previously allocated filter instance
398 if (this.filter != null){
399 if (Globals.IS_SECURITY_ENABLED) {
400 try{
401 SecurityUtil.doAsPrivilege("destroy", filter);
402 } catch(java.lang.Exception ex){
403 context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
404 }
405 SecurityUtil.remove(filter);
406 } else {
407 filter.destroy();
408 }
409 if (!context.getIgnoreAnnotations()) {
410 try {
411 ((StandardContext)context).getAnnotationProcessor().preDestroy(this.filter);
412 } catch (Exception e) {
413 context.getLogger().error("ApplicationFilterConfig.preDestroy", e);
414 }
415 }
416 }
417 this.filter = null;
418
419 } else {
420
421 // Allocate a new filter instance
422 Filter filter = getFilter();
423
424 }
425
426 }
427
428
429 // -------------------------------------------------------- Private Methods
430
431
432 private void registerJMX() {
433 String parentName = context.getName();
434 parentName = ("".equals(parentName)) ? "/" : parentName;
435
436 String hostName = context.getParent().getName();
437 hostName = (hostName == null) ? "DEFAULT" : hostName;
438
439 // domain == engine name
440 String domain = context.getParent().getParent().getName();
441
442 String webMod = "//" + hostName + parentName;
443 String onameStr = null;
444 if (context instanceof StandardContext) {
445 StandardContext standardContext = (StandardContext) context;
446 onameStr = domain + ":j2eeType=Filter,name=" +
447 filterDef.getFilterName() + ",WebModule=" + webMod +
448 ",J2EEApplication=" +
449 standardContext.getJ2EEApplication() + ",J2EEServer=" +
450 standardContext.getJ2EEServer();
451 } else {
452 onameStr = domain + ":j2eeType=Filter,name=" +
453 filterDef.getFilterName() + ",WebModule=" + webMod;
454 }
455 try {
456 oname = new ObjectName(onameStr);
457 Registry.getRegistry(null, null).registerComponent(this, oname,
458 null);
459 } catch (Exception ex) {
460 log.info(sm.getString("applicationFilterConfig.jmxRegisterFail",
461 getFilterClass(), getFilterName()), ex);
462 }
463 }
464
465 private void unregisterJMX() {
466 // unregister this component
467 if (oname != null) {
468 try {
469 Registry.getRegistry(null, null).unregisterComponent(oname);
470 if (log.isDebugEnabled())
471 log.debug(sm.getString(
472 "applicationFilterConfig.jmxUnregister",
473 getFilterClass(), getFilterName()));
474 } catch(Exception ex) {
475 log.error(sm.getString(
476 "applicationFilterConfig.jmxUnregisterFail",
477 getFilterClass(), getFilterName()), ex);
478 }
479 }
480
481 }
482 }