blob: 513a233e6aa33324f3cb9b7107b83a18ae11dae0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.core;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.ObjectName;
import javax.naming.NamingException;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.security.SecurityUtil;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.InstanceManager;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.log.SystemLogHandler;
import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.modeler.Util;
import org.apache.tomcat.util.res.StringManager;
/**
* Implementation of a <code>javax.servlet.FilterConfig</code> useful in
* managing the filter instances instantiated when a web application
* is first started.
*
* @author Craig R. McClanahan
*/
public final class ApplicationFilterConfig implements FilterConfig, Serializable {
private static final long serialVersionUID = 1L;
static final StringManager sm =
StringManager.getManager(Constants.Package);
private final Log log = LogFactory.getLog(ApplicationFilterConfig.class); // must not be static
/**
* Empty String collection to serve as the basis for empty enumerations.
*/
private static final List<String> emptyString = Collections.emptyList();
// ----------------------------------------------------------- Constructors
/**
* Construct a new ApplicationFilterConfig for the specified filter
* definition.
*
* @param context The context with which we are associated
* @param filterDef Filter definition for which a FilterConfig is to be
* constructed
*
* @exception ClassCastException if the specified class does not implement
* the <code>javax.servlet.Filter</code> interface
* @exception ClassNotFoundException if the filter class cannot be found
* @exception IllegalAccessException if the filter class cannot be
* publicly instantiated
* @exception InstantiationException if an exception occurs while
* instantiating the filter object
* @exception ServletException if thrown by the filter's init() method
* @throws NamingException
* @throws InvocationTargetException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws IllegalArgumentException
*/
ApplicationFilterConfig(Context context, FilterDef filterDef)
throws ClassCastException, ClassNotFoundException, IllegalAccessException,
InstantiationException, ServletException, InvocationTargetException, NamingException,
IllegalArgumentException, NoSuchMethodException, SecurityException {
super();
this.context = context;
this.filterDef = filterDef;
// Allocate a new filter instance if necessary
if (filterDef.getFilter() == null) {
getFilter();
} else {
this.filter = filterDef.getFilter();
getInstanceManager().newInstance(filter);
initFilter();
}
}
// ----------------------------------------------------- Instance Variables
/**
* The Context with which we are associated.
*/
private final transient Context context;
/**
* The application Filter we are configured for.
*/
private transient Filter filter = null;
/**
* The <code>FilterDef</code> that defines our associated Filter.
*/
private final FilterDef filterDef;
/**
* the InstanceManager used to create and destroy filter instances.
*/
private transient InstanceManager instanceManager;
/**
* JMX registration name
*/
private ObjectName oname;
// --------------------------------------------------- FilterConfig Methods
/**
* Return the name of the filter we are configuring.
*/
@Override
public String getFilterName() {
return (filterDef.getFilterName());
}
/**
* Return the class of the filter we are configuring.
*/
public String getFilterClass() {
return filterDef.getFilterClass();
}
/**
* Return a <code>String</code> containing the value of the named
* initialization parameter, or <code>null</code> if the parameter
* does not exist.
*
* @param name Name of the requested initialization parameter
*/
@Override
public String getInitParameter(String name) {
Map<String,String> map = filterDef.getParameterMap();
if (map == null) {
return (null);
}
return map.get(name);
}
/**
* Return an <code>Enumeration</code> of the names of the initialization
* parameters for this Filter.
*/
@Override
public Enumeration<String> getInitParameterNames() {
Map<String,String> map = filterDef.getParameterMap();
if (map == null) {
return Collections.enumeration(emptyString);
}
return Collections.enumeration(map.keySet());
}
/**
* Return the ServletContext of our associated web application.
*/
@Override
public ServletContext getServletContext() {
return this.context.getServletContext();
}
/**
* Return a String representation of this object.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ApplicationFilterConfig[");
sb.append("name=");
sb.append(filterDef.getFilterName());
sb.append(", filterClass=");
sb.append(filterDef.getFilterClass());
sb.append("]");
return (sb.toString());
}
// --------------------------------------------------------- Public Methods
public Map<String, String> getFilterInitParameterMap() {
return Collections.unmodifiableMap(filterDef.getParameterMap());
}
// -------------------------------------------------------- Package Methods
/**
* Return the application Filter we are configured for.
*
* @exception ClassCastException if the specified class does not implement
* the <code>javax.servlet.Filter</code> interface
* @exception ClassNotFoundException if the filter class cannot be found
* @exception IllegalAccessException if the filter class cannot be
* publicly instantiated
* @exception InstantiationException if an exception occurs while
* instantiating the filter object
* @exception ServletException if thrown by the filter's init() method
* @throws NamingException
* @throws InvocationTargetException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws IllegalArgumentException
*/
Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException,
InstantiationException, ServletException, InvocationTargetException, NamingException,
IllegalArgumentException, NoSuchMethodException, SecurityException {
// Return the existing filter instance, if any
if (this.filter != null)
return (this.filter);
// Identify the class loader we will be using
String filterClass = filterDef.getFilterClass();
this.filter = (Filter) getInstanceManager().newInstance(filterClass);
initFilter();
return (this.filter);
}
private void initFilter() throws ServletException {
if (context instanceof StandardContext &&
context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
filter.init(this);
} finally {
String capturedlog = SystemLogHandler.stopCapture();
if (capturedlog != null && capturedlog.length() > 0) {
getServletContext().log(capturedlog);
}
}
} else {
filter.init(this);
}
// Expose filter via JMX
registerJMX();
}
/**
* Return the filter definition we are configured for.
*/
FilterDef getFilterDef() {
return (this.filterDef);
}
/**
* Release the Filter instance associated with this FilterConfig,
* if there is one.
*/
void release() {
unregisterJMX();
if (this.filter != null) {
try {
if (Globals.IS_SECURITY_ENABLED) {
try {
SecurityUtil.doAsPrivilege("destroy", filter);
} finally {
SecurityUtil.remove(filter);
}
} else {
filter.destroy();
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
context.getLogger().error(sm.getString(
"applicationFilterConfig.release",
filterDef.getFilterName(),
filterDef.getFilterClass()), t);
}
if (!context.getIgnoreAnnotations()) {
try {
((StandardContext) context).getInstanceManager().destroyInstance(this.filter);
} catch (Exception e) {
Throwable t = ExceptionUtils
.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
context.getLogger().error(
sm.getString("applicationFilterConfig.preDestroy",
filterDef.getFilterName(), filterDef.getFilterClass()), t);
}
}
}
this.filter = null;
}
// -------------------------------------------------------- Private Methods
private InstanceManager getInstanceManager() {
if (instanceManager == null) {
if (context instanceof StandardContext) {
instanceManager = ((StandardContext)context).getInstanceManager();
} else {
instanceManager = new DefaultInstanceManager(null,
new HashMap<String, Map<String, String>>(),
context,
getClass().getClassLoader());
}
}
return instanceManager;
}
private void registerJMX() {
String parentName = context.getName();
if (!parentName.startsWith("/")) {
parentName = "/" + parentName;
}
String hostName = context.getParent().getName();
hostName = (hostName == null) ? "DEFAULT" : hostName;
// domain == engine name
String domain = context.getParent().getParent().getName();
String webMod = "//" + hostName + parentName;
String onameStr = null;
String filterName = filterDef.getFilterName();
if (Util.objectNameValueNeedsQuote(filterName)) {
filterName = ObjectName.quote(filterName);
}
if (context instanceof StandardContext) {
StandardContext standardContext = (StandardContext) context;
onameStr = domain + ":j2eeType=Filter,WebModule=" + webMod +
",name=" + filterName + ",J2EEApplication=" +
standardContext.getJ2EEApplication() + ",J2EEServer=" +
standardContext.getJ2EEServer();
} else {
onameStr = domain + ":j2eeType=Filter,name=" + filterName +
",WebModule=" + webMod;
}
try {
oname = new ObjectName(onameStr);
Registry.getRegistry(null, null).registerComponent(this, oname,
null);
} catch (Exception ex) {
log.info(sm.getString("applicationFilterConfig.jmxRegisterFail",
getFilterClass(), getFilterName()), ex);
}
}
private void unregisterJMX() {
// unregister this component
if (oname != null) {
try {
Registry.getRegistry(null, null).unregisterComponent(oname);
if (log.isDebugEnabled())
log.debug(sm.getString(
"applicationFilterConfig.jmxUnregister",
getFilterClass(), getFilterName()));
} catch(Exception ex) {
log.error(sm.getString(
"applicationFilterConfig.jmxUnregisterFail",
getFilterClass(), getFilterName()), ex);
}
}
}
}