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(nullnull).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(nullnull).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