001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone;
008:
009: import java.io.IOException;
010: import java.util.Collections;
011: import java.util.Enumeration;
012: import java.util.Hashtable;
013: import java.util.Map;
014:
015: import javax.servlet.Filter;
016: import javax.servlet.FilterChain;
017: import javax.servlet.ServletContext;
018: import javax.servlet.ServletException;
019: import javax.servlet.ServletRequest;
020: import javax.servlet.ServletResponse;
021: import javax.servlet.UnavailableException;
022:
023: import org.w3c.dom.Node;
024:
025: /**
026: * Corresponds to a filter object in the web app. Holds one instance only.
027: *
028: * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
029: */
030: public class FilterConfiguration implements javax.servlet.FilterConfig {
031: final String ELEM_NAME = "filter-name";
032: final String ELEM_DISPLAY_NAME = "display-name";
033: final String ELEM_CLASS = "filter-class";
034: final String ELEM_DESCRIPTION = "description";
035: final String ELEM_INIT_PARAM = "init-param";
036: final String ELEM_INIT_PARAM_NAME = "param-name";
037: final String ELEM_INIT_PARAM_VALUE = "param-value";
038:
039: private String filterName;
040: private String classFile;
041: private Filter instance;
042: private Map initParameters;
043: private ServletContext context;
044: private ClassLoader loader;
045: private boolean unavailableException;
046: private Object filterSemaphore = new Boolean(true);
047:
048: protected FilterConfiguration(ServletContext context,
049: ClassLoader loader) {
050: this .context = context;
051: this .loader = loader;
052: this .initParameters = new Hashtable();
053: }
054:
055: /**
056: * Constructor
057: */
058: public FilterConfiguration(ServletContext context,
059: ClassLoader loader, Node elm) {
060: this (context, loader);
061:
062: // Parse the web.xml file entry
063: for (int n = 0; n < elm.getChildNodes().getLength(); n++) {
064: Node child = elm.getChildNodes().item(n);
065: if (child.getNodeType() != Node.ELEMENT_NODE)
066: continue;
067: String nodeName = child.getNodeName();
068:
069: // Construct the servlet instances
070: if (nodeName.equals(ELEM_NAME))
071: this .filterName = WebAppConfiguration
072: .getTextFromNode(child);
073: else if (nodeName.equals(ELEM_CLASS))
074: this .classFile = WebAppConfiguration
075: .getTextFromNode(child);
076: else if (nodeName.equals(ELEM_INIT_PARAM)) {
077: String paramName = null;
078: String paramValue = null;
079: for (int k = 0; k < child.getChildNodes().getLength(); k++) {
080: Node paramNode = child.getChildNodes().item(k);
081: if (paramNode.getNodeType() != Node.ELEMENT_NODE)
082: continue;
083: else if (paramNode.getNodeName().equals(
084: ELEM_INIT_PARAM_NAME))
085: paramName = WebAppConfiguration
086: .getTextFromNode(paramNode);
087: else if (paramNode.getNodeName().equals(
088: ELEM_INIT_PARAM_VALUE))
089: paramValue = WebAppConfiguration
090: .getTextFromNode(paramNode);
091: }
092: if ((paramName != null) && (paramValue != null))
093: this .initParameters.put(paramName, paramValue);
094: }
095: }
096: Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
097: "FilterConfiguration.DeployedInstance", new String[] {
098: this .filterName, this .classFile });
099: }
100:
101: public String getFilterName() {
102: return this .filterName;
103: }
104:
105: public String getInitParameter(String paramName) {
106: return (String) this .initParameters.get(paramName);
107: }
108:
109: public Enumeration getInitParameterNames() {
110: return Collections.enumeration(this .initParameters.keySet());
111: }
112:
113: public ServletContext getServletContext() {
114: return this .context;
115: }
116:
117: /**
118: * Implements the first-time-init of an instance, and wraps it in a
119: * dispatcher.
120: */
121: public Filter getFilter() throws ServletException {
122: synchronized (this .filterSemaphore) {
123: if (isUnavailable())
124: throw new WinstoneException(
125: Launcher.RESOURCES
126: .getString("FilterConfiguration.FilterUnavailable"));
127: else if (this .instance == null)
128: try {
129: ClassLoader cl = Thread.currentThread()
130: .getContextClassLoader();
131: Thread.currentThread().setContextClassLoader(
132: this .loader);
133:
134: Class filterClass = Class.forName(classFile, true,
135: this .loader);
136: this .instance = (Filter) filterClass.newInstance();
137: Logger
138: .log(Logger.DEBUG, Launcher.RESOURCES,
139: "FilterConfiguration.init",
140: this .filterName);
141:
142: // Initialise with the correct classloader
143: this .instance.init(this );
144: Thread.currentThread().setContextClassLoader(cl);
145: } catch (ClassNotFoundException err) {
146: Logger.log(Logger.ERROR, Launcher.RESOURCES,
147: "FilterConfiguration.ClassLoadError",
148: this .classFile, err);
149: } catch (IllegalAccessException err) {
150: Logger.log(Logger.ERROR, Launcher.RESOURCES,
151: "FilterConfiguration.ClassLoadError",
152: this .classFile, err);
153: } catch (InstantiationException err) {
154: Logger.log(Logger.ERROR, Launcher.RESOURCES,
155: "FilterConfiguration.ClassLoadError",
156: this .classFile, err);
157: } catch (ServletException err) {
158: this .instance = null;
159: if (err instanceof UnavailableException)
160: setUnavailable();
161: throw err;
162: // throw new WinstoneException(resources
163: // .getString("FilterConfiguration.InitError"), err);
164: }
165: }
166: return this .instance;
167: }
168:
169: /**
170: * Called when it's time for the container to shut this servlet down.
171: */
172: public void destroy() {
173: synchronized (this .filterSemaphore) {
174: setUnavailable();
175: }
176: }
177:
178: public String toString() {
179: return Launcher.RESOURCES.getString(
180: "FilterConfiguration.Description", new String[] {
181: this .filterName, this .classFile });
182: }
183:
184: public boolean isUnavailable() {
185: return this .unavailableException;
186: }
187:
188: protected void setUnavailable() {
189: this .unavailableException = true;
190: if (this .instance != null) {
191: Logger.log(Logger.DEBUG, Launcher.RESOURCES,
192: "FilterConfiguration.destroy", this .filterName);
193: ClassLoader cl = Thread.currentThread()
194: .getContextClassLoader();
195: Thread.currentThread().setContextClassLoader(this .loader);
196: this .instance.destroy();
197: Thread.currentThread().setContextClassLoader(cl);
198: this .instance = null;
199: }
200: }
201:
202: public void execute(ServletRequest request,
203: ServletResponse response, FilterChain chain)
204: throws ServletException, IOException {
205: ClassLoader cl = Thread.currentThread().getContextClassLoader();
206: Thread.currentThread().setContextClassLoader(this .loader);
207: try {
208: getFilter().doFilter(request, response, chain);
209: } catch (UnavailableException err) {
210: setUnavailable();
211: throw new ServletException(Launcher.RESOURCES
212: .getString("RequestDispatcher.FilterError"), err);
213: } finally {
214: Thread.currentThread().setContextClassLoader(cl);
215: }
216: }
217: }
|