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 package org.apache.catalina.core;
18
19
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.Serializable;
23 import java.util.Collections;
24 import java.util.Enumeration;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.management.ObjectName;
29 import javax.naming.NamingException;
30 import javax.servlet.Filter;
31 import javax.servlet.FilterConfig;
32 import javax.servlet.ServletContext;
33 import javax.servlet.ServletException;
34
35 import org.apache.catalina.Context;
36 import org.apache.catalina.Globals;
37 import org.apache.catalina.security.SecurityUtil;
38 import org.apache.juli.logging.Log;
39 import org.apache.juli.logging.LogFactory;
40 import org.apache.tomcat.util.ExceptionUtils;
41 import org.apache.tomcat.util.descriptor.web.FilterDef;
42 import org.apache.tomcat.util.log.SystemLogHandler;
43 import org.apache.tomcat.util.modeler.Registry;
44 import org.apache.tomcat.util.modeler.Util;
45 import org.apache.tomcat.util.res.StringManager;
46
47
48 /**
49 * Implementation of a <code>javax.servlet.FilterConfig</code> useful in
50 * managing the filter instances instantiated when a web application
51 * is first started.
52 *
53 * @author Craig R. McClanahan
54 */
55 public final class ApplicationFilterConfig implements FilterConfig, Serializable {
56
57 private static final long serialVersionUID = 1L;
58
59 static final StringManager sm =
60 StringManager.getManager(Constants.Package);
61
62 private transient Log log = LogFactory.getLog(ApplicationFilterConfig.class); // must not be static
63
64 /**
65 * Empty String collection to serve as the basis for empty enumerations.
66 */
67 private static final List<String> emptyString = Collections.emptyList();
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 SecurityException
90 * @throws IllegalArgumentException
91 */
92 ApplicationFilterConfig(Context context, FilterDef filterDef)
93 throws ClassCastException, ReflectiveOperationException, ServletException,
94 NamingException, IllegalArgumentException, SecurityException {
95
96 super();
97
98 this.context = context;
99 this.filterDef = filterDef;
100 // Allocate a new filter instance if necessary
101 if (filterDef.getFilter() == null) {
102 getFilter();
103 } else {
104 this.filter = filterDef.getFilter();
105 context.getInstanceManager().newInstance(filter);
106 initFilter();
107 }
108 }
109
110
111 // ----------------------------------------------------- Instance Variables
112
113
114 /**
115 * The Context with which we are associated.
116 */
117 private final transient Context context;
118
119
120 /**
121 * The application Filter we are configured for.
122 */
123 private transient Filter filter = null;
124
125
126 /**
127 * The <code>FilterDef</code> that defines our associated Filter.
128 */
129 private final FilterDef filterDef;
130
131 /**
132 * JMX registration name
133 */
134 private ObjectName oname;
135
136 // --------------------------------------------------- FilterConfig Methods
137
138
139 /**
140 * Return the name of the filter we are configuring.
141 */
142 @Override
143 public String getFilterName() {
144 return filterDef.getFilterName();
145 }
146
147 /**
148 * @return The class of the filter we are configuring.
149 */
150 public String getFilterClass() {
151 return filterDef.getFilterClass();
152 }
153
154 /**
155 * Return a <code>String</code> containing the value of the named
156 * initialization parameter, or <code>null</code> if the parameter
157 * does not exist.
158 *
159 * @param name Name of the requested initialization parameter
160 */
161 @Override
162 public String getInitParameter(String name) {
163
164 Map<String,String> map = filterDef.getParameterMap();
165 if (map == null) {
166 return null;
167 }
168
169 return map.get(name);
170
171 }
172
173
174 /**
175 * Return an <code>Enumeration</code> of the names of the initialization
176 * parameters for this Filter.
177 */
178 @Override
179 public Enumeration<String> getInitParameterNames() {
180 Map<String,String> map = filterDef.getParameterMap();
181
182 if (map == null) {
183 return Collections.enumeration(emptyString);
184 }
185
186 return Collections.enumeration(map.keySet());
187 }
188
189
190 /**
191 * Return the ServletContext of our associated web application.
192 */
193 @Override
194 public ServletContext getServletContext() {
195
196 return this.context.getServletContext();
197
198 }
199
200
201 /**
202 * Return a String representation of this object.
203 */
204 @Override
205 public String toString() {
206 StringBuilder sb = new StringBuilder("ApplicationFilterConfig[");
207 sb.append("name=");
208 sb.append(filterDef.getFilterName());
209 sb.append(", filterClass=");
210 sb.append(filterDef.getFilterClass());
211 sb.append("]");
212 return sb.toString();
213 }
214
215 // --------------------------------------------------------- Public Methods
216
217 public Map<String, String> getFilterInitParameterMap() {
218 return Collections.unmodifiableMap(filterDef.getParameterMap());
219 }
220
221 // -------------------------------------------------------- Package Methods
222
223
224 /**
225 * Return the application Filter we are configured for.
226 *
227 * @exception ClassCastException if the specified class does not implement
228 * the <code>javax.servlet.Filter</code> interface
229 * @exception ClassNotFoundException if the filter class cannot be found
230 * @exception IllegalAccessException if the filter class cannot be
231 * publicly instantiated
232 * @exception InstantiationException if an exception occurs while
233 * instantiating the filter object
234 * @exception ServletException if thrown by the filter's init() method
235 * @throws NamingException
236 * @throws ReflectiveOperationException
237 * @throws SecurityException
238 * @throws IllegalArgumentException
239 */
240 Filter getFilter() throws ClassCastException, ReflectiveOperationException, ServletException,
241 NamingException, IllegalArgumentException, SecurityException {
242
243 // Return the existing filter instance, if any
244 if (this.filter != null)
245 return this.filter;
246
247 // Identify the class loader we will be using
248 String filterClass = filterDef.getFilterClass();
249 this.filter = (Filter) context.getInstanceManager().newInstance(filterClass);
250
251 initFilter();
252
253 return this.filter;
254
255 }
256
257 private void initFilter() throws ServletException {
258 if (context instanceof StandardContext &&
259 context.getSwallowOutput()) {
260 try {
261 SystemLogHandler.startCapture();
262 filter.init(this);
263 } finally {
264 String capturedlog = SystemLogHandler.stopCapture();
265 if (capturedlog != null && capturedlog.length() > 0) {
266 getServletContext().log(capturedlog);
267 }
268 }
269 } else {
270 filter.init(this);
271 }
272
273 // Expose filter via JMX
274 registerJMX();
275 }
276
277 /**
278 * Return the filter definition we are configured for.
279 */
280 FilterDef getFilterDef() {
281 return this.filterDef;
282 }
283
284 /**
285 * Release the Filter instance associated with this FilterConfig,
286 * if there is one.
287 */
288 void release() {
289
290 unregisterJMX();
291
292 if (this.filter != null) {
293 try {
294 if (Globals.IS_SECURITY_ENABLED) {
295 try {
296 SecurityUtil.doAsPrivilege("destroy", filter);
297 } finally {
298 SecurityUtil.remove(filter);
299 }
300 } else {
301 filter.destroy();
302 }
303 } catch (Throwable t) {
304 ExceptionUtils.handleThrowable(t);
305 context.getLogger().error(sm.getString(
306 "applicationFilterConfig.release",
307 filterDef.getFilterName(),
308 filterDef.getFilterClass()), t);
309 }
310 if (!context.getIgnoreAnnotations()) {
311 try {
312 context.getInstanceManager().destroyInstance(this.filter);
313 } catch (Exception e) {
314 Throwable t = ExceptionUtils
315 .unwrapInvocationTargetException(e);
316 ExceptionUtils.handleThrowable(t);
317 context.getLogger().error(
318 sm.getString("applicationFilterConfig.preDestroy",
319 filterDef.getFilterName(), filterDef.getFilterClass()), t);
320 }
321 }
322 }
323 this.filter = null;
324
325 }
326
327
328 // -------------------------------------------------------- Private Methods
329
330 private void registerJMX() {
331 String parentName = context.getName();
332 if (!parentName.startsWith("/")) {
333 parentName = "/" + parentName;
334 }
335
336 String hostName = context.getParent().getName();
337 hostName = (hostName == null) ? "DEFAULT" : hostName;
338
339 // domain == engine name
340 String domain = context.getParent().getParent().getName();
341
342 String webMod = "//" + hostName + parentName;
343 String onameStr = null;
344 String filterName = filterDef.getFilterName();
345 if (Util.objectNameValueNeedsQuote(filterName)) {
346 filterName = ObjectName.quote(filterName);
347 }
348 if (context instanceof StandardContext) {
349 StandardContext standardContext = (StandardContext) context;
350 onameStr = domain + ":j2eeType=Filter,WebModule=" + webMod +
351 ",name=" + filterName + ",J2EEApplication=" +
352 standardContext.getJ2EEApplication() + ",J2EEServer=" +
353 standardContext.getJ2EEServer();
354 } else {
355 onameStr = domain + ":j2eeType=Filter,name=" + filterName +
356 ",WebModule=" + webMod;
357 }
358 try {
359 oname = new ObjectName(onameStr);
360 Registry.getRegistry(null, null).registerComponent(this, oname, null);
361 } catch (Exception ex) {
362 log.warn(sm.getString("applicationFilterConfig.jmxRegisterFail",
363 getFilterClass(), getFilterName()), ex);
364 }
365 }
366
367
368 private void unregisterJMX() {
369 // unregister this component
370 if (oname != null) {
371 try {
372 Registry.getRegistry(null, null).unregisterComponent(oname);
373 if (log.isDebugEnabled())
374 log.debug(sm.getString("applicationFilterConfig.jmxUnregister",
375 getFilterClass(), getFilterName()));
376 } catch(Exception ex) {
377 log.warn(sm.getString("applicationFilterConfig.jmxUnregisterFail",
378 getFilterClass(), getFilterName()), ex);
379 }
380 }
381 }
382
383
384 /*
385 * Log objects are not Serializable.
386 */
387 private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
388 ois.defaultReadObject();
389 log = LogFactory.getLog(ApplicationFilterConfig.class);
390 }
391
392 }
393