/* * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net> * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone; import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.Hashtable; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.UnavailableException; import org.w3c.dom.Node; /** * Corresponds to a filter object in the web app. Holds one instance only. * * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a> */ public class FilterConfiguration implements javax.servlet.FilterConfig { final String ELEM_NAME = "filter-name"; final String ELEM_DISPLAY_NAME = "display-name"; final String ELEM_CLASS = "filter-class"; final String ELEM_DESCRIPTION = "description"; final String ELEM_INIT_PARAM = "init-param"; final String ELEM_INIT_PARAM_NAME = "param-name"; final String ELEM_INIT_PARAM_VALUE = "param-value"; private String filterName; private String classFile; private Filter instance; private Map initParameters; private ServletContext context; private ClassLoader loader; private boolean unavailableException; private Object filterSemaphore = new Boolean(true); protected FilterConfiguration(ServletContext context, ClassLoader loader) { this.context = context; this.loader = loader; this.initParameters = new Hashtable(); } /** * Constructor */ public FilterConfiguration(ServletContext context, ClassLoader loader, Node elm) { this(context, loader); // Parse the web.xml file entry for (int n = 0; n < elm.getChildNodes().getLength(); n++) { Node child = elm.getChildNodes().item(n); if (child.getNodeType() != Node.ELEMENT_NODE) continue; String nodeName = child.getNodeName(); // Construct the servlet instances if (nodeName.equals(ELEM_NAME)) this.filterName = WebAppConfiguration.getTextFromNode(child); else if (nodeName.equals(ELEM_CLASS)) this.classFile = WebAppConfiguration.getTextFromNode(child); else if (nodeName.equals(ELEM_INIT_PARAM)) { String paramName = null; String paramValue = null; for (int k = 0; k < child.getChildNodes().getLength(); k++) { Node paramNode = child.getChildNodes().item(k); if (paramNode.getNodeType() != Node.ELEMENT_NODE) continue; else if (paramNode.getNodeName().equals( ELEM_INIT_PARAM_NAME)) paramName = WebAppConfiguration.getTextFromNode(paramNode); else if (paramNode.getNodeName().equals( ELEM_INIT_PARAM_VALUE)) paramValue = WebAppConfiguration.getTextFromNode(paramNode); } if ((paramName != null) && (paramValue != null)) this.initParameters.put(paramName, paramValue); } } Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "FilterConfiguration.DeployedInstance", new String[] { this.filterName, this.classFile }); } public String getFilterName() { return this.filterName; } public String getInitParameter(String paramName) { return (String) this.initParameters.get(paramName); } public Enumeration getInitParameterNames() { return Collections.enumeration(this.initParameters.keySet()); } public ServletContext getServletContext() { return this.context; } /** * Implements the first-time-init of an instance, and wraps it in a * dispatcher. */ public Filter getFilter() throws ServletException { synchronized (this.filterSemaphore) { if (isUnavailable()) throw new WinstoneException(Launcher.RESOURCES .getString("FilterConfiguration.FilterUnavailable")); else if (this.instance == null) try { ClassLoader cl = Thread.currentThread() .getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); Class filterClass = Class.forName(classFile, true, this.loader); this.instance = (Filter) filterClass.newInstance(); Logger.log(Logger.DEBUG, Launcher.RESOURCES, "FilterConfiguration.init", this.filterName); // Initialise with the correct classloader this.instance.init(this); Thread.currentThread().setContextClassLoader(cl); } catch (ClassNotFoundException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "FilterConfiguration.ClassLoadError", this.classFile, err); } catch (IllegalAccessException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "FilterConfiguration.ClassLoadError", this.classFile, err); } catch (InstantiationException err) { Logger.log(Logger.ERROR, Launcher.RESOURCES, "FilterConfiguration.ClassLoadError", this.classFile, err); } catch (ServletException err) { this.instance = null; if (err instanceof UnavailableException) setUnavailable(); throw err; // throw new WinstoneException(resources // .getString("FilterConfiguration.InitError"), err); } } return this.instance; } /** * Called when it's time for the container to shut this servlet down. */ public void destroy() { synchronized (this.filterSemaphore) { setUnavailable(); } } public String toString() { return Launcher.RESOURCES.getString("FilterConfiguration.Description", new String[] { this.filterName, this.classFile }); } public boolean isUnavailable() { return this.unavailableException; } protected void setUnavailable() { this.unavailableException = true; if (this.instance != null) { Logger.log(Logger.DEBUG, Launcher.RESOURCES, "FilterConfiguration.destroy", this.filterName); ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); this.instance.destroy(); Thread.currentThread().setContextClassLoader(cl); this.instance = null; } } public void execute(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.loader); try { getFilter().doFilter(request, response, chain); } catch (UnavailableException err) { setUnavailable(); throw new ServletException(Launcher.RESOURCES .getString("RequestDispatcher.FilterError"), err); } finally { Thread.currentThread().setContextClassLoader(cl); } } }