0001: /* tjws - WebAppServlet.java
0002: * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved.
0003: * Redistribution and use in source and binary forms, with or without
0004: * modification, are permitted provided that the following conditions
0005: * are met:
0006: * 1. Redistributions of source code must retain the above copyright
0007: * notice, this list of conditions and the following disclaimer.
0008: * 2. Redistributions in binary form must reproduce the above copyright
0009: * notice, this list of conditions and the following disclaimer in the
0010: * documentation and/or other materials provided with the distribution.
0011: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0012: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0013: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0014: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
0015: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0016: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0017: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0018: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0019: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0020: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0021: *
0022: * $Id: WebAppServlet.java,v 1.52 2008/01/19 07:08:00 dmitriy Exp $
0023: * Created on Dec 14, 2004
0024: */
0025:
0026: package rogatkin.web;
0027:
0028: import java.io.File;
0029: import java.io.FileFilter;
0030: import java.io.FileInputStream;
0031: import java.io.IOException;
0032: import java.io.InputStream;
0033: import java.io.InputStreamReader;
0034: import java.io.OutputStream;
0035: import java.io.PrintWriter;
0036: import java.lang.reflect.InvocationHandler;
0037: import java.lang.reflect.InvocationTargetException;
0038: import java.lang.reflect.Method;
0039: import java.lang.reflect.Proxy;
0040: import java.net.MalformedURLException;
0041: import java.net.URL;
0042: import java.net.URLClassLoader;
0043: import java.text.DateFormat;
0044: import java.util.ArrayList;
0045: import java.util.Arrays;
0046: import java.util.Collections;
0047: import java.util.Enumeration;
0048: import java.util.EventListener;
0049: import java.util.HashMap;
0050: import java.util.Hashtable;
0051: import java.util.Iterator;
0052: import java.util.List;
0053: import java.util.Map;
0054: import java.util.Set;
0055: import java.util.TreeSet;
0056: import java.util.Vector;
0057: import java.util.regex.Pattern;
0058: import java.util.zip.GZIPOutputStream;
0059:
0060: import javax.net.ssl.SSLPeerUnverifiedException;
0061: import javax.net.ssl.SSLSession;
0062: import javax.net.ssl.SSLSocket;
0063:
0064: import javax.servlet.Filter;
0065: import javax.servlet.FilterChain;
0066: import javax.servlet.FilterConfig;
0067: import javax.servlet.RequestDispatcher;
0068: import javax.servlet.Servlet;
0069: import javax.servlet.ServletConfig;
0070: import javax.servlet.ServletContext;
0071: import javax.servlet.ServletContextAttributeEvent;
0072: import javax.servlet.ServletContextAttributeListener;
0073: import javax.servlet.ServletContextEvent;
0074: import javax.servlet.ServletContextListener;
0075: import javax.servlet.ServletException;
0076: import javax.servlet.ServletRequest;
0077: import javax.servlet.ServletRequestAttributeEvent;
0078: import javax.servlet.ServletRequestAttributeListener;
0079: import javax.servlet.ServletRequestEvent;
0080: import javax.servlet.ServletRequestListener;
0081: import javax.servlet.ServletResponse;
0082: import javax.servlet.UnavailableException;
0083: import javax.servlet.http.HttpServlet;
0084: import javax.servlet.http.HttpServletRequest;
0085: import javax.servlet.http.HttpServletRequestWrapper;
0086: import javax.servlet.http.HttpServletResponse;
0087: import javax.servlet.http.HttpServletResponseWrapper;
0088: import javax.servlet.http.HttpSession;
0089: import javax.servlet.http.HttpSessionListener;
0090: import javax.xml.XMLConstants;
0091: import javax.xml.namespace.NamespaceContext;
0092: import javax.xml.xpath.XPath;
0093: import javax.xml.xpath.XPathConstants;
0094: import javax.xml.xpath.XPathExpressionException;
0095: import javax.xml.xpath.XPathFactory;
0096:
0097: import org.w3c.dom.Node;
0098: import org.w3c.dom.NodeList;
0099: import org.xml.sax.InputSource;
0100:
0101: import Acme.Utils;
0102: import Acme.Serve.Serve;
0103:
0104: /**
0105: * @author dmitriy
0106: *
0107: *
0108: */
0109: public class WebAppServlet extends HttpServlet implements
0110: ServletContext {
0111: public static final String DEF_DEBUG = "rogatkin.webapp.debug";
0112:
0113: public static final String WAR_NAME_AS_CONTEXTPATH = "tjws.wardeploy.warname-as-context";
0114:
0115: protected static final String WEBAPPCLASSLOADER = "rogatkin.webapp.AppClassLoader";
0116:
0117: protected static final String WEBAPPINITTIMEOUT = "rogatkin.webapp.%sinit.timeout";
0118:
0119: List<ServletAccessDescr> servlets;
0120:
0121: List<FilterAccessDescriptor> filters;
0122:
0123: URL[] cpUrls;
0124:
0125: URLClassLoader ucl;
0126:
0127: File deployDir;
0128:
0129: Serve server;
0130:
0131: int sessionTimeout;
0132:
0133: int initTimeout;
0134:
0135: // / context methods
0136: protected String contextName;
0137:
0138: protected String contextPath;
0139:
0140: protected Hashtable<String, Object> attributes;
0141:
0142: protected Hashtable<String, String> contextParameters;
0143:
0144: protected List<String> welcomeFiles;
0145:
0146: protected List<ErrorPageDescr> errorPages;
0147:
0148: protected List<EventListener> listeners;
0149:
0150: protected List<HttpSessionListener> sessionListeners;
0151:
0152: protected ArrayList<ServletRequestListener> requestListeners;
0153:
0154: protected ArrayList<ServletRequestAttributeListener> attributeListeners;
0155:
0156: protected Map<String, String> mimes;
0157:
0158: private boolean applyCompression;
0159:
0160: protected static interface Openable {
0161: Object getOrigin();
0162: }
0163:
0164: protected static class MappingEntry {
0165: String servPath;
0166:
0167: Pattern pathPat;
0168:
0169: MappingEntry(String path, String pattern) {
0170: servPath = path;
0171: pathPat = Pattern.compile(pattern);
0172: }
0173:
0174: public String toString() {
0175: return String.format("Mapping of %s with regexp pat %s",
0176: servPath, pathPat);
0177: }
0178: }
0179:
0180: protected class ServletAccessDescr implements ServletConfig {
0181: String className;
0182:
0183: String name;
0184:
0185: Servlet instance;
0186:
0187: // String servPath;
0188:
0189: // String pathPat;
0190:
0191: MappingEntry[] mapping;
0192:
0193: Map<String, String> initParams;
0194:
0195: String label;
0196:
0197: boolean loadOnStart;
0198:
0199: String descr;
0200:
0201: long timeToReactivate; // if servlet suspended
0202:
0203: public java.lang.String getServletName() {
0204: return name;
0205: }
0206:
0207: public java.util.Enumeration getInitParameterNames() {
0208: return new Enumeration<String>() {
0209: Iterator<String> i;
0210: {
0211: i = initParams.keySet().iterator();
0212: }
0213:
0214: public boolean hasMoreElements() {
0215: return i.hasNext();
0216: }
0217:
0218: public String nextElement() {
0219: return i.next();
0220: }
0221: };
0222: }
0223:
0224: public ServletContext getServletContext() {
0225: return WebAppServlet.this ;
0226: }
0227:
0228: public String getInitParameter(java.lang.String name) {
0229: return initParams.get(name);
0230: }
0231:
0232: public void add(MappingEntry entry) {
0233: if (mapping == null)
0234: mapping = new MappingEntry[1];
0235: else { // can't use copyOf in 1.5
0236: MappingEntry[] copy = new MappingEntry[mapping.length + 1];
0237: System.arraycopy(mapping, 0, copy, 0, mapping.length);
0238: mapping = copy;
0239: }
0240: mapping[mapping.length - 1] = entry;
0241: }
0242:
0243: int matchPath(String path) {
0244: if (mapping == null)
0245: return -1;
0246: for (int i = 0; i < mapping.length; i++)
0247: if (mapping[i].pathPat.matcher(path).matches())
0248: return i;
0249: return -1;
0250: }
0251:
0252: public String toString() {
0253: return "Servlet " + name + " class " + className
0254: + " path/patern " + Arrays.toString(mapping)
0255: + " init" + initParams + " inst " + instance;
0256: }
0257: }
0258:
0259: static enum DispatchFilterType {
0260: FORWARD, INCLUDE, REQUEST, ERROR
0261: };
0262:
0263: protected class FilterAccessDescriptor extends ServletAccessDescr
0264: implements FilterConfig {
0265: String[] servletNames;
0266:
0267: Filter filterInstance;
0268:
0269: DispatchFilterType[] dispatchTypes;
0270:
0271: public java.lang.String getFilterName() {
0272: return name;
0273: }
0274:
0275: public void add(String name) {
0276: // note the local name shadows name as class memeber
0277: if (servletNames == null)
0278: servletNames = new String[1];
0279: else
0280: servletNames = Utils.copyOf(servletNames,
0281: servletNames.length + 1);
0282: servletNames[servletNames.length - 1] = name;
0283: }
0284:
0285: public void add(DispatchFilterType dispatcher) {
0286: if (dispatchTypes == null)
0287: dispatchTypes = new DispatchFilterType[1];
0288: else {
0289: DispatchFilterType[] copy = new DispatchFilterType[dispatchTypes.length + 1];
0290: System.arraycopy(dispatchTypes, 0, copy, 0,
0291: dispatchTypes.length);
0292: dispatchTypes = copy;
0293: }
0294: dispatchTypes[dispatchTypes.length - 1] = dispatcher;
0295: }
0296:
0297: int matchServlet(String servletName) {
0298: if (servletNames == null)
0299: return -1;
0300: for (int i = 0; i < this .servletNames.length; i++)
0301: if (servletNames[i].equals(servletName))
0302: return i;
0303: return -1;
0304: }
0305:
0306: boolean matchDispatcher(DispatchFilterType dispatcher) {
0307: if (dispatchTypes == null)
0308: if (dispatcher.equals(DispatchFilterType.REQUEST))
0309: return true;
0310: else
0311: return false;
0312: for (int i = 0; i < dispatchTypes.length; i++)
0313: if (dispatcher.equals(dispatchTypes[i]))
0314: return true;
0315: return false;
0316: }
0317:
0318: public String toString() {
0319: return String.format(
0320: "Filter for servlets %s and types %s based on %s",
0321: Arrays.toString(servletNames), Arrays
0322: .toString(dispatchTypes), super .toString());
0323: }
0324: }
0325:
0326: protected static class ErrorPageDescr {
0327: String errorPage;
0328:
0329: Class exception;
0330:
0331: int errorCode;
0332:
0333: ErrorPageDescr(String page, String exClass, String code) {
0334: if (page == null || page.length() == 0
0335: || page.charAt(0) != '/')
0336: throw new IllegalArgumentException("Error page path '"
0337: + page + "' must start with '/'");
0338: if (page.charAt(0) == '/')
0339: errorPage = page;
0340: else
0341: errorPage = "/" + page;
0342: try {
0343: exception = Class.forName(exClass);
0344: } catch (Exception e) {
0345:
0346: }
0347: try {
0348: errorCode = Integer.parseInt(code);
0349: } catch (Exception e) {
0350:
0351: }
0352: }
0353: }
0354:
0355: protected WebAppServlet(String context) {
0356: this .contextPath = "/" + context;
0357: attributes = new Hashtable<String, Object>();
0358: contextParameters = new Hashtable<String, String>();
0359: applyCompression = System.getProperty("tjws.webapp." + context
0360: + ".compressresponse") != null;
0361: if (applyCompression == false)
0362: applyCompression = System
0363: .getProperty("tjws.fileservlet.usecompression") != null;
0364: // TODO consider
0365: // _DEBUG = System.getProperty(getClass().getName() + ".debug") != null;
0366: }
0367:
0368: public static WebAppServlet create(File deployDir, String context,
0369: Serve server) throws ServletException {
0370: XPath xp = XPathFactory.newInstance().newXPath();
0371: final WebAppServlet result = new WebAppServlet(context);
0372: result.server = server;
0373: try {
0374: result.makeCP(deployDir); // /web-app
0375: Node document = (Node) xp.evaluate("/*", new InputSource(
0376: new FileInputStream(new File(deployDir,
0377: "WEB-INF/web.xml"))), XPathConstants.NODE);
0378: final String namespaceURI = document.getNamespaceURI();
0379: String prefix = namespaceURI == null ? "" : "j2ee:";
0380: xp.setNamespaceContext(new NamespaceContext() {
0381: public String getNamespaceURI(String prefix) {
0382: // System.err.printf("Resolver called with %s%n", prefix);
0383: if (prefix == null)
0384: throw new IllegalArgumentException(
0385: "Prefix is null.");
0386: if (namespaceURI == null)
0387: return XMLConstants.NULL_NS_URI;
0388: if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))
0389: return namespaceURI;
0390: if ("j2ee".equals(prefix))
0391: return namespaceURI;
0392: return XMLConstants.NULL_NS_URI;
0393: }
0394:
0395: public String getPrefix(String arg0) {
0396: throw new UnsupportedOperationException(
0397: "getPrefix(" + arg0 + ");");
0398: }
0399:
0400: public Iterator getPrefixes(String arg0) {
0401: throw new UnsupportedOperationException(
0402: "getPrefixes(" + arg0 + ");");
0403: }
0404: });
0405: document = (Node) xp.evaluate("//" + prefix + "web-app",
0406: document, XPathConstants.NODE);
0407: if ("yes".equals(System
0408: .getProperty(WAR_NAME_AS_CONTEXTPATH)) == false)
0409: result.contextName = (String) xp.evaluate(prefix
0410: + "display-name", document,
0411: XPathConstants.STRING);
0412: if (result.contextName == null
0413: || result.contextName.length() == 0)
0414: result.contextName = context;
0415: else
0416: result.contextPath = "/" + result.contextName;
0417: // context parameters
0418: NodeList nodes = (NodeList) xp
0419: .evaluate(prefix + "context-param", document,
0420: XPathConstants.NODESET);
0421: int nodesLen = nodes.getLength();
0422: for (int p = 0; p < nodesLen; p++) {
0423: result.contextParameters.put((String) xp.evaluate(
0424: prefix + "param-name", nodes.item(p),
0425: XPathConstants.STRING), (String) xp.evaluate(
0426: prefix + "param-value", nodes.item(p),
0427: XPathConstants.STRING));
0428: }
0429: // session-config <session-timeout>
0430: Number num = (Number) xp.evaluate(prefix
0431: + "session-config/" + prefix + "session-timeout",
0432: document, XPathConstants.NUMBER);
0433: if (num != null)
0434: result.sessionTimeout = num.intValue();
0435: if (result.sessionTimeout < 0)
0436: result.sessionTimeout = 0;
0437: else
0438: result.sessionTimeout *= 60;
0439: result.initTimeout = 10;
0440: String initTimeoutStr = System.getProperty(String.format(
0441: WEBAPPINITTIMEOUT, result.contextName + "."));
0442: if (initTimeoutStr == null)
0443: initTimeoutStr = System.getProperty(String.format(
0444: WEBAPPINITTIMEOUT, ""));
0445: if (initTimeoutStr != null)
0446: try {
0447: result.initTimeout = Integer
0448: .parseInt(initTimeoutStr);
0449: if (result.initTimeout < 2)
0450: result.initTimeout = 10;
0451: } catch (Exception e) {
0452:
0453: }
0454: Thread.currentThread().setContextClassLoader(result.ucl);
0455: // listeners listener-class
0456: nodes = (NodeList) xp.evaluate(prefix + "listener/"
0457: + prefix + "listener-class", document,
0458: XPathConstants.NODESET);
0459: nodesLen = nodes.getLength();
0460: if (nodesLen > 0) {
0461: result.listeners = new ArrayList<EventListener>(
0462: nodesLen);
0463: for (int i = 0; i < nodesLen; i++)
0464: try {
0465: EventListener eventListener = (EventListener) result.ucl
0466: .loadClass(
0467: nodes.item(i).getTextContent()
0468: .trim()).newInstance();
0469: if (eventListener instanceof HttpSessionListener) {
0470: if (result.sessionListeners == null)
0471: result.sessionListeners = new ArrayList<HttpSessionListener>(
0472: nodesLen);
0473: result.sessionListeners
0474: .add((HttpSessionListener) eventListener);
0475: }
0476: if (eventListener instanceof ServletRequestListener) {
0477: if (result.requestListeners == null)
0478: result.requestListeners = new ArrayList<ServletRequestListener>(
0479: nodesLen);
0480: result.requestListeners
0481: .add((ServletRequestListener) eventListener);
0482: }
0483: if (eventListener instanceof ServletRequestAttributeListener) {
0484: if (result.attributeListeners == null)
0485: result.attributeListeners = new ArrayList<ServletRequestAttributeListener>(
0486: nodesLen);
0487: result.attributeListeners
0488: .add((ServletRequestAttributeListener) eventListener);
0489: }
0490: result.listeners.add(eventListener); // because the same class can implement other listener interfaces
0491: } catch (Exception e) {
0492: result.log("Event listener "
0493: + nodes.item(i).getTextContent()
0494: + " can't be created.", e);
0495: } catch (Error e) {
0496: result.log("Event listener "
0497: + nodes.item(i).getTextContent()
0498: + " can't be created.", e);
0499: }
0500: }
0501: // restore sessions for this context
0502: // serve.sessions.restore for the current context
0503:
0504: // notify context listeners
0505: if (result.listeners != null)
0506: for (EventListener listener : result.listeners) {
0507: if (listener instanceof ServletContextListener) {
0508: final ServletContextListener contListener = (ServletContextListener) listener;
0509: contListener
0510: .contextInitialized(new ServletContextEvent(
0511: result));
0512: }
0513: }
0514: // process filters
0515: nodes = (NodeList) xp.evaluate(prefix + "filter", document,
0516: XPathConstants.NODESET);
0517: nodesLen = nodes.getLength();
0518: result.filters = new ArrayList<FilterAccessDescriptor>(
0519: nodesLen);
0520: for (int i = 0; i < nodesLen; i++) {
0521: Node n = nodes.item(i);
0522: FilterAccessDescriptor fad = result
0523: .createFilterDescriptor();
0524: fad.name = (String) xp.evaluate(prefix + "filter-name",
0525: n, XPathConstants.STRING);
0526: fad.className = (String) xp.evaluate(prefix
0527: + "filter-class", n, XPathConstants.STRING);
0528: if (fad.className == null)
0529: throw new ServletException(
0530: String
0531: .format(
0532: "Filter %s specified without or empty class.",
0533: fad.name));
0534: else
0535: fad.className = fad.className.trim();
0536: fad.label = (String) xp.evaluate(prefix
0537: + "display-name", n, XPathConstants.STRING);
0538: fad.descr = (String) xp.evaluate(
0539: prefix + "description", n,
0540: XPathConstants.STRING);
0541: NodeList params = (NodeList) xp.evaluate(prefix
0542: + "init-param", n, XPathConstants.NODESET);
0543: fad.initParams = new HashMap<String, String>(params
0544: .getLength());
0545: for (int p = 0; p < params.getLength(); p++) {
0546: fad.initParams.put((String) xp.evaluate(prefix
0547: + "param-name", params.item(p),
0548: XPathConstants.STRING), (String) xp
0549: .evaluate(prefix + "param-value", params
0550: .item(p), XPathConstants.STRING));
0551: }
0552: result.filters.add(fad);
0553: }
0554: // process filter's mapping
0555: for (FilterAccessDescriptor fad : result.filters) {
0556: nodes = (NodeList) xp.evaluate(prefix
0557: + "filter-mapping[" + prefix + "filter-name=\""
0558: + fad.name + "\"]", document,
0559: XPathConstants.NODESET);
0560: nodesLen = nodes.getLength();
0561: if (nodesLen == 0)
0562: throw new ServletException(String.format(
0563: "No mappings were found for filter %s",
0564: fad.name));
0565: for (int i = 0; i < nodesLen; i++) {
0566: Node n = nodes.item(i);
0567: NodeList clarifications = (NodeList) xp.evaluate(
0568: prefix + "url-pattern", n,
0569: XPathConstants.NODESET);
0570: int claLen = clarifications.getLength();
0571: for (int j = 0; j < claLen; j++) {
0572: String mapUrl = clarifications.item(j)
0573: .getTextContent();
0574: if (mapUrl == null || mapUrl.length() == 0)
0575: continue;
0576: fad.add(new MappingEntry(clearPath(mapUrl),
0577: buildREbyPathPatt(mapUrl)));
0578: }
0579: clarifications = (NodeList) xp.evaluate(prefix
0580: + "dispatcher", n, XPathConstants.NODESET);
0581: claLen = clarifications.getLength();
0582: for (int j = 0; j < claLen; j++) {
0583: String filterType = clarifications.item(j)
0584: .getTextContent();
0585: if (filterType == null
0586: || filterType.length() == 0)
0587: fad.add(DispatchFilterType.REQUEST);
0588: else
0589: fad.add(DispatchFilterType
0590: .valueOf(filterType));
0591: }
0592: clarifications = (NodeList) xp
0593: .evaluate(prefix + "servlet-name", n,
0594: XPathConstants.NODESET);
0595: claLen = clarifications.getLength();
0596: for (int j = 0; j < claLen; j++) {
0597: // adding servlet name
0598: fad
0599: .add(clarifications.item(j)
0600: .getTextContent());
0601: }
0602: }
0603: result.newFilterInstance(fad);
0604: }
0605: // servlets
0606: nodes = (NodeList) xp.evaluate(prefix + "servlet",
0607: document, XPathConstants.NODESET);
0608: nodesLen = nodes.getLength();
0609: result.servlets = new ArrayList<ServletAccessDescr>(
0610: nodesLen + 1); // +jsp
0611: for (int i = 0; i < nodesLen; i++) {
0612: Node n = nodes.item(i);
0613: ServletAccessDescr sad = result.createDescriptor();
0614: sad.name = (String) xp.evaluate(
0615: prefix + "servlet-name", n,
0616: XPathConstants.STRING);
0617: sad.className = (String) xp.evaluate(prefix
0618: + "servlet-class", n, XPathConstants.STRING);
0619: if (sad.className == null
0620: || sad.className.length() == 0) {
0621: String jspFile = (String) xp.evaluate(prefix
0622: + "jsp-file", n, XPathConstants.STRING);
0623: if (jspFile != null) {
0624: result
0625: .log(String
0626: .format(
0627: "Not supported servlet option jsp-file %s for %s, ignored.",
0628: jspFile, sad.name));
0629: continue;
0630: } else
0631: throw new ServletException(
0632: String
0633: .format(
0634: "Servlet %s specified without class or jsp file.",
0635: sad.name));
0636: } else
0637: sad.className = sad.className.trim();
0638: sad.label = (String) xp.evaluate(prefix
0639: + "display-name", n, XPathConstants.STRING);
0640: sad.descr = (String) xp.evaluate(
0641: prefix + "description", n,
0642: XPathConstants.STRING);
0643: String loadOnStartVal = (String) xp.evaluate(prefix
0644: + "load-on-startup", n, XPathConstants.STRING);
0645: sad.loadOnStart = loadOnStartVal != null
0646: && loadOnStartVal.length() > 0;
0647: NodeList params = (NodeList) xp.evaluate(prefix
0648: + "init-param", n, XPathConstants.NODESET);
0649: sad.initParams = new HashMap<String, String>(params
0650: .getLength());
0651: for (int p = 0; p < params.getLength(); p++) {
0652: sad.initParams.put((String) xp.evaluate(prefix
0653: + "param-name", params.item(p),
0654: XPathConstants.STRING), (String) xp
0655: .evaluate(prefix + "param-value", params
0656: .item(p), XPathConstants.STRING));
0657: }
0658: result.servlets.add(sad);
0659: }
0660: // get mappings
0661: ServletAccessDescr wasDefault = null;
0662: for (ServletAccessDescr sad : result.servlets) {
0663: nodes = (NodeList) xp.evaluate(prefix
0664: + "servlet-mapping[" + prefix
0665: + "servlet-name=\"" + sad.name + "\"]",
0666: document, XPathConstants.NODESET);
0667: nodesLen = nodes.getLength();
0668: // System.err.printf("Found %d mappings for %s%n", nodesLen, sad);
0669: if (nodesLen == 0) {
0670: // no mapping at all
0671: String urlPat = "/" + sad.name + "/*";
0672: sad.add(new MappingEntry(clearPath(urlPat),
0673: buildREbyPathPatt(urlPat)));
0674: } else
0675: for (int i = 0; i < nodesLen; i++) {
0676: NodeList maps = (NodeList) xp.evaluate(prefix
0677: + "url-pattern", nodes.item(i),
0678: XPathConstants.NODESET);
0679: int mapsLen = maps.getLength();
0680: // System.err.printf("Found %d patterns for %s%n", mapsLen, sad);
0681: if (mapsLen == 0) {
0682: // mapping with empty pattern
0683: String urlPat = "/" + sad.name + "/*";
0684: sad.add(new MappingEntry(clearPath(urlPat),
0685: buildREbyPathPatt(urlPat)));
0686: } else {
0687: for (int j = 0; j < mapsLen; j++) {
0688: String urlPat = maps.item(j)
0689: .getTextContent();
0690: if (urlPat.equals("/"))
0691: if (wasDefault != null)
0692: throw new ServletException(
0693: "More than one default servlets defined "
0694: + sad);
0695: else
0696: wasDefault = sad;
0697: sad.add(new MappingEntry(
0698: clearPath(urlPat),
0699: buildREbyPathPatt(urlPat)));
0700: }
0701: }
0702: }
0703: // System.err.printf("Servlet %s, path:%s\n", sad, sad.servPath);
0704: if (sad.loadOnStart)
0705: result.newInstance(sad);
0706: }
0707: // additional jsp mapping
0708: nodes = (NodeList) xp.evaluate(prefix + "jsp-config/"
0709: + prefix + "jsp-property-group/" + prefix
0710: + "url-pattern", document, XPathConstants.NODESET);
0711: nodesLen = nodes.getLength();
0712: if (nodesLen > 0) {
0713: List<String> jspPats = new ArrayList<String>(nodesLen);
0714: for (int i = 0; i < nodesLen; i++) {
0715: jspPats.add(nodes.item(i).getTextContent());
0716: }
0717: result.addJSPServlet(jspPats);
0718: } else
0719: result.addJSPServlet(null);
0720: if (wasDefault != null) {
0721: // re-add at the end
0722: result.servlets.remove(wasDefault);
0723: result.servlets.add(wasDefault);
0724: }
0725: // welcome files
0726: nodes = (NodeList) xp.evaluate(prefix
0727: + "welcome-file-list/" + prefix + "welcome-file",
0728: document, XPathConstants.NODESET);
0729: result.welcomeFiles = new ArrayList<String>(nodes
0730: .getLength() + 1);
0731: nodesLen = nodes.getLength();
0732: if (nodesLen > 0)
0733: for (int wfi = 0; wfi < nodesLen; wfi++)
0734: result.welcomeFiles.add(nodes.item(wfi)
0735: .getTextContent());
0736: else {
0737: result.welcomeFiles.add("index.html");
0738: result.welcomeFiles.add("index.jsp");
0739: }
0740: // error pages
0741: nodes = (NodeList) xp.evaluate(prefix + "error-page",
0742: document, XPathConstants.NODESET);
0743: nodesLen = nodes.getLength();
0744: if (nodesLen > 0) {
0745: result.errorPages = new ArrayList<ErrorPageDescr>(
0746: nodesLen);
0747: for (int i = 0; i < nodesLen; i++) {
0748: Node n = nodes.item(i);
0749: result.errorPages
0750: .add(new WebAppServlet.ErrorPageDescr(
0751: (String) xp.evaluate(prefix
0752: + "location", n,
0753: XPathConstants.STRING),
0754: (String) xp.evaluate(prefix
0755: + "exception-type", n,
0756: XPathConstants.STRING),
0757: (String) xp.evaluate(prefix
0758: + "error-code", n,
0759: XPathConstants.STRING)));
0760: }
0761: }
0762: // mime types
0763: nodes = (NodeList) xp.evaluate(prefix + "mime-mapping",
0764: document, XPathConstants.NODESET);
0765: nodesLen = nodes.getLength();
0766: if (nodesLen > 0) {
0767: result.mimes = new HashMap<String, String>(nodesLen);
0768: for (int i = 0; i < nodesLen; i++) {
0769: Node n = nodes.item(i);
0770: result.mimes.put(((String) xp.evaluate(prefix
0771: + "extension", n, XPathConstants.STRING))
0772: .toLowerCase(), (String) xp.evaluate(prefix
0773: + "mime-type", n, XPathConstants.STRING));
0774: }
0775: }
0776: } catch (IOException ioe) {
0777: throw new ServletException("A problem in reading web.xml.",
0778: ioe);
0779: } catch (XPathExpressionException xpe) {
0780: xpe.printStackTrace();
0781: throw new ServletException("A problem in parsing web.xml.",
0782: xpe);
0783: } // finally { // streams will be closed by InputSource
0784: return result;
0785: }
0786:
0787: static <D extends ServletAccessDescr> void addMultiple(
0788: NodeList list, D d) {
0789: // TODO can be solution for more compact code
0790: }
0791:
0792: static public String buildREbyPathPatt(String pathPat) {
0793: if (pathPat.equals("/"))
0794: return "/.*";
0795: if (pathPat.startsWith("*."))
0796: return pathPat.replace(".", "\\.").replace("?", ".")
0797: .replace("*", ".*").replace("|", "\\|"); // +"\\??.*";
0798: // TODO think more
0799: int wcp = pathPat.indexOf('*');
0800: //if (wcp > 0 && pathPat.charAt(wcp - 1) == '/')
0801: //pathPat = pathPat.substring(0, wcp - 1) + '*';
0802: pathPat = pathPat.replace(".", "\\.").replace("?", ".")
0803: .replace("*", ".*");
0804: if (wcp < 0)
0805: if (pathPat.endsWith("/") == false)
0806: pathPat += "/?";
0807: return pathPat;
0808: }
0809:
0810: static public String clearPath(String pathMask) {
0811: if (pathMask.equals("/"))
0812: return pathMask;
0813: if (pathMask.startsWith("*."))
0814: return "/";
0815: int wcp = pathMask.indexOf('*');
0816: if (wcp < 0)
0817: return pathMask;
0818: return pathMask.substring(0, wcp);
0819: }
0820:
0821: protected static Serve.ServeConnection toServeConnection(
0822: Object proxy) {
0823: if (proxy instanceof Openable) {
0824: Object servCon = ((Openable) proxy).getOrigin();
0825: if (servCon instanceof Serve.ServeConnection)
0826: return (Serve.ServeConnection) servCon;
0827: }
0828: return null;
0829: }
0830:
0831: public void service(ServletRequest req, ServletResponse res)
0832: throws ServletException, IOException {
0833: // new Exception("call trace").printStackTrace();
0834: // TODO check access rights
0835: Thread.currentThread().setContextClassLoader(ucl);
0836: if (req.isSecure())
0837: fillSecureAttrs(req);
0838: final HttpServletRequest hreq = (HttpServletRequest) req;
0839: if (this .requestListeners != null) {
0840: ServletRequestEvent e = new ServletRequestEvent(this , hreq);
0841: for (ServletRequestListener rlistener : requestListeners)
0842: rlistener.requestInitialized(e);
0843: }
0844: try {
0845: String path = hreq.getPathInfo();
0846: // TODO: wrap request to implement methods like getRequestDispatcher()
0847: // which supports relative path, no leading / means relative to currently called
0848: if (_DEBUG)
0849: System.err
0850: .printf(
0851: "Full req:%s, ContextPath: %s, ServletPath:%s, pathInfo:%s\n",
0852: hreq.getRequestURI(), hreq
0853: .getContextPath(), hreq
0854: .getServletPath(), path);
0855: SimpleFilterChain sfc = new SimpleFilterChain();
0856: if (path != null) {
0857: // note a limitation, servlet name can't start with /WEB-INF
0858: if (path.regionMatches(true, 0, "/WEB-INF", 0,
0859: "/WEB-INF".length())) {
0860: ((HttpServletResponse) res)
0861: .sendError(HttpServletResponse.SC_FORBIDDEN);
0862: return;
0863: }
0864: for (FilterAccessDescriptor fad : filters)
0865: if (fad.matchDispatcher(DispatchFilterType.REQUEST)
0866: && fad.matchPath(path) >= 0)
0867: sfc.add(fad);
0868: for (ServletAccessDescr sad : servlets) {
0869: if (_DEBUG)
0870: System.err.println("Trying match " + path
0871: + " to " + Arrays.toString(sad.mapping)
0872: + " = " + sad.matchPath(path));
0873: int patIndex;
0874: if ((patIndex = sad.matchPath(path)) >= 0) {
0875: if (sad.instance == null) {
0876: if (sad.loadOnStart == false)
0877: synchronized (sad) {
0878: if (sad.instance == null)
0879: newInstance(sad);
0880: }
0881: if (sad.instance == null) {
0882: sad.loadOnStart |= true; // mark unsuccessful instantiation and ban the servlet?
0883: ((HttpServletResponse) res)
0884: .sendError(
0885: HttpServletResponse.SC_GONE,
0886: "Servlet "
0887: + sad.name
0888: + " hasn't been instantiated successfully or has been unloaded.");
0889: return;
0890: }
0891: } else {
0892: if (sad.timeToReactivate > 0) {
0893: if (sad.timeToReactivate > System
0894: .currentTimeMillis()) {
0895: ((HttpServletResponse) res)
0896: .setIntHeader(
0897: "Retry-After",
0898: (int) (sad.timeToReactivate - System
0899: .currentTimeMillis()) / 1000 + 1);
0900: //((HttpServletResponse) res).setDateHeader("Retry-After", new Date(sad.timeToReactivate));
0901: ((HttpServletResponse) res)
0902: .sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
0903: return;
0904: } else
0905: sad.timeToReactivate = 0;
0906: }
0907: }
0908: for (FilterAccessDescriptor fad : filters)
0909: if (fad
0910: .matchDispatcher(DispatchFilterType.REQUEST)
0911: && fad.matchServlet(sad.name) >= 0)
0912: sfc.add(fad);
0913: // sfc.add(fad.filterInstance);
0914: // System.err.println("used:"+ sad.servPath+", wanted:"+((WebAppServlet) sad.getServletContext()).contextPath);
0915: sfc.setFilter(new WebAppContextFilter(
0916: sad.mapping[patIndex].servPath));
0917: // add servlet in chain
0918: sfc.setServlet(sad);
0919: sfc.reset();
0920: sfc.doFilter(req, res);
0921: return;
0922: }
0923: }
0924: } else {
0925: ((HttpServletResponse) res).sendRedirect(hreq
0926: .getRequestURI()
0927: + "/");
0928: return;
0929: }
0930:
0931: // no matching, process as file
0932: sfc.setFilter(new WebAppContextFilter());
0933: sfc.setServlet(new HttpServlet() {
0934: public void service(ServletRequest req,
0935: ServletResponse res) throws ServletException,
0936: IOException {
0937: String path = ((HttpServletRequest) req)
0938: .getPathTranslated();
0939: returnFileContent(path, (HttpServletRequest) req,
0940: (HttpServletResponse) res);
0941: }
0942: });
0943: sfc.reset();
0944: sfc.doFilter(req, res);
0945: } finally {
0946: if (this .requestListeners != null) {
0947: ServletRequestEvent e = new ServletRequestEvent(this ,
0948: hreq);
0949: for (ServletRequestListener rlistener : requestListeners)
0950: rlistener.requestDestroyed(e);
0951: }
0952: }
0953: }
0954:
0955: protected void fillSecureAttrs(ServletRequest req) {
0956: Serve.ServeConnection scon = toServeConnection(req);
0957: if (scon != null) {
0958: if (scon.getSocket() instanceof SSLSocket) {
0959: SSLSocket ssocket = (SSLSocket) scon.getSocket();
0960: SSLSession ssess = ssocket.getSession();
0961: String cipherSuite = ssess.getCipherSuite();
0962:
0963: req.setAttribute("javax.servlet.request.cipher_suite",
0964: cipherSuite);
0965: int cipherBits = 0;
0966: // TODO cache in session
0967: if (cipherSuite.indexOf("128") > 0)
0968: cipherBits = 128;
0969: else if (cipherSuite.indexOf("40") > 0)
0970: cipherBits = 40;
0971: else if (cipherSuite.indexOf("3DES") > 0)
0972: cipherBits = 168;
0973: else if (cipherSuite.indexOf("IDEA") > 0)
0974: cipherBits = 128;
0975: else if (cipherSuite.indexOf("DES") > 0)
0976: cipherBits = 56;
0977: req.setAttribute("javax.servlet.request.key_size",
0978: cipherBits);
0979: try {
0980: req.setAttribute(
0981: "javax.servlet.request.X509Certificate",
0982: ssess.getPeerCertificateChain());
0983: } catch (SSLPeerUnverifiedException e) {
0984: }
0985: }
0986: }
0987: }
0988:
0989: protected SimpleFilterChain buildFilterChain(String servletName,
0990: String requestPath, DispatchFilterType filterType) {
0991: SimpleFilterChain sfc = new SimpleFilterChain();
0992: // add path filters
0993: if (requestPath != null)
0994: for (FilterAccessDescriptor fad : filters)
0995: if (fad.matchDispatcher(filterType)
0996: && fad.matchPath(requestPath) >= 0)
0997: sfc.add(fad);
0998: // add name filters
0999: if (servletName != null)
1000: for (FilterAccessDescriptor fad : filters)
1001: if (fad.matchDispatcher(DispatchFilterType.REQUEST)
1002: && fad.matchServlet(servletName) >= 0)
1003: sfc.add(fad);
1004: return sfc;
1005: }
1006:
1007: protected void returnFileContent(String path,
1008: HttpServletRequest req, HttpServletResponse res)
1009: throws IOException, ServletException {
1010: // Note : can't call or forward to file servlet since it can be not installed
1011: File fpath = new File(path);
1012: if (fpath.isDirectory()) {
1013: File baseDir = fpath;
1014: for (String indexPage : welcomeFiles) {
1015: fpath = new File(baseDir, indexPage);
1016: if (fpath.exists() && fpath.isFile()) {
1017: if (indexPage.charAt(0) != '/')
1018: indexPage = "/" + indexPage;
1019: RequestDispatcher rd = req
1020: .getRequestDispatcher(indexPage);
1021: if (rd != null) {
1022: rd.forward(req, res);
1023: return;
1024: }
1025: break;
1026: }
1027: }
1028: }
1029: if (fpath.exists() == false) {
1030: res.sendError(res.SC_NOT_FOUND);
1031: return;
1032: }
1033: if (fpath.isFile() == false) {
1034: res.sendError(res.SC_FORBIDDEN);
1035: return;
1036: }
1037:
1038: String temp = getMimeType(fpath.getName());
1039: res.setContentType(temp);
1040:
1041: long lastMod = fpath.lastModified();
1042: res.setDateHeader("Last-modified", lastMod);
1043: String ifModSinceStr = req.getHeader("If-Modified-Since");
1044: long ifModSince = -1;
1045: if (ifModSinceStr != null) {
1046: int semi = ifModSinceStr.indexOf(';');
1047: if (semi != -1)
1048: ifModSinceStr = ifModSinceStr.substring(0, semi);
1049: try {
1050: ifModSince = DateFormat.getDateInstance().parse(
1051: ifModSinceStr).getTime();
1052: } catch (Exception ignore) {
1053: }
1054: }
1055: if (ifModSince != -1 && ifModSince >= lastMod) {
1056: res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
1057: return;
1058: }
1059: // TODO add range handling
1060: boolean doCompress = false;
1061: if (applyCompression && temp != null && temp.startsWith("text")) {
1062: temp = req.getHeader("Accept-Encoding");
1063: if (temp != null && temp.indexOf("gzip") >= 0) {
1064: res.setHeader("Content-Encoding", "gzip");
1065: doCompress = true;
1066: }
1067: }
1068:
1069: if ("HEAD".equals(req.getMethod())) {
1070: res.setHeader("Content-Length", Long.toString(fpath
1071: .length()));
1072: return;
1073: }
1074: OutputStream os = null;
1075: InputStream is = null;
1076: try {
1077: is = new FileInputStream(fpath);
1078: os = res.getOutputStream();
1079: if (doCompress)
1080: os = new GZIPOutputStream(os);
1081: else
1082: res.setHeader("Content-Length", Long.toString(fpath
1083: .length()));
1084: WarRoller.copyStream(is, os);
1085: if (doCompress)
1086: ((GZIPOutputStream) os).finish();
1087: } catch (IllegalStateException ise) {
1088: // assure length
1089: res.setHeader("Content-Length", Long.toString(fpath
1090: .length()));
1091: PrintWriter pw = res.getWriter();
1092: // TODO decide on encoding/charset used by the reader
1093: String charSetName = res.getCharacterEncoding();
1094: if (charSetName == null)
1095: charSetName = Utils.ISO_8859_1;
1096: Utils
1097: .copyStream(new InputStreamReader(is, charSetName),
1098: pw);
1099: // consider Writer is OK to do not close
1100: // consider underneath stream closing OK
1101: } finally {
1102: try {
1103: is.close();
1104: } catch (Exception x) {
1105: }
1106: try {
1107: if (os != null)
1108: os.close();
1109: } catch (Exception x) {
1110: }
1111: }
1112:
1113: }
1114:
1115: protected void addJSPServlet(List<String> patterns) {
1116: ServletAccessDescr sad = createDescriptor();
1117: // get class name from serve
1118: sad.initParams = new HashMap<String, String>(10);
1119: Map<String, String> arguments = (Map<String, String>) server.arguments;
1120: sad.className = arguments.get(Serve.ARG_JSP);
1121: if (sad.className == null) {
1122: sad.className = "org.gjt.jsp.JSPServlet";
1123: sad.initParams.put("repository", new File(deployDir, "~~~")
1124: .getPath());
1125: sad.initParams.put("debug", System.getProperty(getClass()
1126: .getName()
1127: + ".debug") != null ? "yes" : "no");
1128: sad.initParams.put("classloadername", WEBAPPCLASSLOADER);
1129: } else {
1130: String pnpx = sad.className + '.';
1131: int cnl = pnpx.length();
1132: String classPath = Utils.calculateClassPath(ucl);
1133: for (String ipn : arguments.keySet())
1134: if (ipn.startsWith(pnpx))
1135: sad.initParams.put(ipn.substring(cnl),
1136: arguments.get(ipn).replace("%context%",
1137: contextName).replace("%deploydir%",
1138: deployDir.getPath()).replace(
1139: "%classloader%", WEBAPPCLASSLOADER)
1140: .replace("%classpath%", classPath));
1141: }
1142: sad.descr = "JSP support servlet";
1143: sad.label = "JSP";
1144: sad.loadOnStart = false;
1145: sad.name = "jsp";
1146: String jspPat;
1147: if (patterns == null || patterns.size() == 0)
1148: jspPat = "/.*\\.jsp";
1149: else {
1150: jspPat = buildREbyPathPatt(patterns.get(0));
1151: for (int i = 1; i < patterns.size(); i++)
1152: jspPat += "|" + buildREbyPathPatt(patterns.get(i));
1153: }
1154: sad.add(new MappingEntry("/", jspPat));
1155: servlets.add(sad);
1156: }
1157:
1158: protected ServletAccessDescr createDescriptor() {
1159: return new ServletAccessDescr();
1160: }
1161:
1162: protected FilterAccessDescriptor createFilterDescriptor() {
1163: return new FilterAccessDescriptor();
1164: }
1165:
1166: protected void makeCP(File dd) throws IOException {
1167: deployDir = dd.getCanonicalFile();
1168: final List<URL> urls = new ArrayList<URL>();
1169: // add servlet classes
1170: ClassLoader cl = getClass().getClassLoader();
1171: while (cl != null) {
1172: if (cl instanceof URLClassLoader) {
1173: if (((URLClassLoader) cl)
1174: .findResource("javax/servlet/jsp/JspPage.class") != null
1175: || ((URLClassLoader) cl)
1176: .findResource("javax/servlet/http/HttpServlet.class") != null) {
1177: for (URL url : ((URLClassLoader) cl).getURLs())
1178: urls.add(url);
1179: }
1180: }
1181: cl = cl.getParent();
1182: }
1183: File classesFile = new File(deployDir, "WEB-INF/classes");
1184: if (classesFile.exists() && classesFile.isDirectory())
1185: try {
1186: urls.add(classesFile.toURL());
1187: } catch (java.net.MalformedURLException mfe) {
1188:
1189: }
1190: File libFile = new File(deployDir, "WEB-INF/lib");
1191: libFile.listFiles(new FileFilter() {
1192: public boolean accept(File file) {
1193: String name = file.getName().toLowerCase();
1194: if (name.endsWith(".jar") || name.endsWith(".zip"))
1195: try {
1196: urls.add(file.toURL());
1197: } catch (java.net.MalformedURLException mfe) {
1198:
1199: }
1200: return false;
1201: }
1202: });
1203: cpUrls = urls.toArray(new URL[urls.size()]);
1204: //ucl = URLClassLoader.newInstance(cpUrls, getClass().getClassLoader());
1205: ucl = new URLClassLoader(cpUrls, getClass().getClassLoader()) {
1206: @Override
1207: public URL getResource(String name) {
1208: URL url = super .getResource(name);
1209:
1210: if (url == null && name.startsWith("/")) {
1211: url = super .getResource(name.substring(1));
1212: }
1213: return url;
1214: }
1215: };
1216:
1217: setAttribute(WEBAPPCLASSLOADER, ucl);
1218: // System.err.println("CP "+urls+"\nLoader:"+ucl);
1219: }
1220:
1221: protected Servlet newInstance(final ServletAccessDescr descr)
1222: throws ServletException {
1223: try {
1224: // System.err.printf("new instance %s %s%n", descr.className, Arrays.toString(ucl.getURLs()));
1225: final Servlet servlet = (Servlet) ucl.loadClass(
1226: descr.className).newInstance();
1227: final ServletException[] exHolder = new ServletException[1];
1228: Thread initThread = new Thread("Init thread of "
1229: + contextName) {
1230: public void run() {
1231: try {
1232: servlet.init(descr);
1233: } catch (ServletException se) {
1234: exHolder[0] = se;
1235: }
1236: }
1237: };
1238: initThread.start();
1239: initThread.join(initTimeout * 1000);
1240: if (initThread.isAlive() == true)
1241: throw new ServletException("Init of " + contextName
1242: + " exceeded allocated time (" + initTimeout
1243: + " secs)");
1244: if (exHolder[0] != null)
1245: throw exHolder[0];
1246: descr.instance = servlet;
1247: return descr.instance;
1248: // TODO think about setting back context loader
1249: } catch (InstantiationException ie) {
1250: throw new ServletException("Servlet class "
1251: + descr.className + " can't instantiate. ", ie);
1252: } catch (IllegalAccessException iae) {
1253: throw new ServletException("Servlet class "
1254: + descr.className + " can't access. ", iae);
1255: } catch (ClassNotFoundException cnfe) {
1256: log("", cnfe);
1257: throw new ServletException("Servlet class "
1258: + descr.className + " not found. ", cnfe);
1259: } catch (Error e) {
1260: throw new ServletException(
1261: "Servlet class "
1262: + descr.className
1263: + " can't be instantiated or initialized due an error.",
1264: e);
1265: } catch (Throwable t) {
1266: if (t instanceof ThreadDeath)
1267: throw (ThreadDeath) t;
1268: throw new ServletException(
1269: "Servlet class "
1270: + descr.className
1271: + " can't be instantiated or initialized due an exception.",
1272: t);
1273: }
1274: }
1275:
1276: protected Filter newFilterInstance(FilterAccessDescriptor descr)
1277: throws ServletException {
1278: try {
1279: descr.filterInstance = (Filter) ucl.loadClass(
1280: descr.className).newInstance();
1281: descr.filterInstance.init(descr);
1282: } catch (InstantiationException ie) {
1283: throw new ServletException("Filter class "
1284: + descr.className + " can't instantiate. ", ie);
1285: } catch (IllegalAccessException iae) {
1286: throw new ServletException("Filter class "
1287: + descr.className + " can't access. ", iae);
1288: } catch (ClassNotFoundException cnfe) {
1289: throw new ServletException("Filter class "
1290: + descr.className + " not found. ", cnfe);
1291: }
1292: return descr.filterInstance;
1293: }
1294:
1295: /*
1296: * protected URL toURL(File file) throws MalformedURLException { System.err.println("file:/"+file.getAbsolutePath()+(file.isDirectory()?"/":"")); return new
1297: * URL("file:/"+file.getAbsolutePath()+(file.isDirectory()?"/":"")); }
1298: */
1299:
1300: // /////////////////////////////////////////////////////////////////////////////////
1301: // context methods
1302: public String getContextPath() {
1303: return contextPath;
1304: }
1305:
1306: public String getServletContextName() {
1307: return contextName;
1308: }
1309:
1310: public void removeAttribute(java.lang.String name) {
1311: Object value = attributes.remove(name);
1312: if (listeners != null)
1313: for (EventListener listener : listeners)
1314: if (listener instanceof ServletContextAttributeListener)
1315: ((ServletContextAttributeListener) listener)
1316: .attributeRemoved(new ServletContextAttributeEvent(
1317: this , name, value));
1318: }
1319:
1320: public void setAttribute(java.lang.String name,
1321: java.lang.Object object) {
1322: // log("Set attr:"+name+" to "+object);
1323: if (object == null) {
1324: removeAttribute(name);
1325: return;
1326: }
1327: Object oldObj = attributes.put(name, object);
1328: if (listeners != null)
1329: for (EventListener listener : listeners) {
1330: if (listener instanceof ServletContextAttributeListener)
1331: if (oldObj == null)
1332: ((ServletContextAttributeListener) listener)
1333: .attributeAdded(new ServletContextAttributeEvent(
1334: this , name, object));
1335: else
1336: ((ServletContextAttributeListener) listener)
1337: .attributeReplaced(new ServletContextAttributeEvent(
1338: this , name, object));
1339: }
1340: }
1341:
1342: public java.util.Enumeration getAttributeNames() {
1343: return attributes.keys();
1344: }
1345:
1346: public java.lang.Object getAttribute(java.lang.String name) {
1347: // log("context: "+this+" return attr:"+name+" as "+attributes.get(name));
1348: return attributes.get(name);
1349: }
1350:
1351: public java.lang.String getServerInfo() {
1352: return "TJWS/J2EE container, Copyright © 2008 Dmitriy Rogatkin";
1353: }
1354:
1355: public java.lang.String getRealPath(java.lang.String path) {
1356: path = validatePath(path);
1357: if (path == null)
1358: return deployDir.toString();
1359: else
1360: return new File(deployDir, path).toString();
1361: }
1362:
1363: public void log(java.lang.String msg) {
1364: server.log((contextName == null ? "" : contextName) + "> "
1365: + msg);
1366: }
1367:
1368: public void log(java.lang.Exception exception, java.lang.String msg) {
1369: server.log(exception, (contextName == null ? "" : contextName)
1370: + "> " + msg);
1371: }
1372:
1373: public void log(java.lang.String message,
1374: java.lang.Throwable throwable) {
1375: server.log((contextName == null ? "" : contextName) + "> "
1376: + message, throwable);
1377: }
1378:
1379: public java.util.Enumeration getServletNames() {
1380: Vector<String> result = new Vector<String>();
1381: for (ServletAccessDescr sad : servlets)
1382: result.add(sad.name);
1383: return result.elements();
1384: }
1385:
1386: public java.util.Enumeration getServlets() {
1387: Vector<Servlet> result = new Vector<Servlet>();
1388: for (ServletAccessDescr sad : servlets)
1389: result.add(sad.instance);
1390: return result.elements();
1391:
1392: }
1393:
1394: public Servlet getServlet(java.lang.String name)
1395: throws ServletException {
1396: for (ServletAccessDescr sad : servlets)
1397: if (name.equals(sad.name))
1398: return sad.instance;
1399: throw new ServletException("No servlet " + name);
1400: }
1401:
1402: public RequestDispatcher getNamedDispatcher(java.lang.String name) {
1403: for (ServletAccessDescr sad : servlets)
1404: if (name.equals(sad.name)) {
1405: if (sad.instance == null && sad.loadOnStart == false)
1406: try {
1407: newInstance(sad);
1408: } catch (ServletException se) {
1409: }
1410: if (sad.instance != null)
1411: return new SimpleDispatcher(name, sad.instance);
1412: else
1413: break;
1414: }
1415: return null;
1416: }
1417:
1418: public RequestDispatcher getRequestDispatcher(java.lang.String path) {
1419: if (_DEBUG)
1420: System.err.printf("getRequestDispatcher(%s)%n", path);
1421: if (path == null || path.length() == 0 || path.charAt(0) != '/')
1422: return null; // path must start with / for call from context
1423: // look for servlets first
1424: int sp = path.indexOf('?');
1425: if (sp < 0)
1426: sp = path.indexOf('#'); // exclude possible fragment
1427: // if (sp < 0)
1428: // sp = path.indexOf(Serve.ServeConnection.SESSION_URL_NAME);
1429: String clearPath = sp < 0 ? path : path.substring(0, sp);
1430: for (ServletAccessDescr sad : servlets) {
1431: if (_DEBUG)
1432: System.err
1433: .printf(
1434: "For dispatcher trying match %s (%s) %s = %b%n",
1435: path, clearPath, Arrays
1436: .toString(sad.mapping), sad
1437: .matchPath(clearPath));
1438: int patIndex;
1439: if ((patIndex = sad.matchPath(clearPath)) >= 0) {
1440: if (sad.instance == null && sad.loadOnStart == false)
1441: try {
1442: synchronized (sad) {
1443: if (sad.instance == null)
1444: newInstance(sad);
1445: }
1446: } catch (ServletException se) {
1447: log(
1448: String
1449: .format(
1450: "Can't instantiate an instance of %s exception %s",
1451: sad, se), se
1452: .getRootCause());
1453: }
1454: if (sad.instance != null)
1455: return new SimpleDispatcher(sad.instance,
1456: sad.mapping[patIndex].servPath, path);
1457: else
1458: return null; // servlet not working
1459: }
1460: }
1461: // no matching servlets, check for resources
1462: try {
1463: if (_DEBUG)
1464: System.err.printf("Dispatching to resource %s%n", path);
1465: if (getResource(path) == null)
1466: throw new MalformedURLException(); // check path is valid
1467: return new SimpleDispatcher(new HttpServlet() {
1468: public void service(ServletRequest req,
1469: ServletResponse res) throws ServletException,
1470: IOException {
1471: String path;
1472: if (((HttpServletRequest) req)
1473: .getAttribute("javax.servlet.include.request_uri") != null)
1474: path = req
1475: .getRealPath((String) req
1476: .getAttribute("javax.servlet.include.path_info"));
1477: else
1478: path = ((HttpServletRequest) req)
1479: .getPathTranslated();
1480: if (_DEBUG)
1481: System.err
1482: .printf(
1483: "Dispatched file servlet for %s translated %s%n",
1484: path,
1485: ((HttpServletRequest) req)
1486: .getPathTranslated());
1487: returnFileContent(path, (HttpServletRequest) req,
1488: (HttpServletResponse) res);
1489: }
1490: }, path);
1491: } catch (MalformedURLException mfe) {
1492: }
1493: return null;
1494: }
1495:
1496: public java.io.InputStream getResourceAsStream(java.lang.String path) {
1497: try {
1498: return getResource(path).openStream();
1499: } catch (NullPointerException npe) {
1500: if (_DEBUG)
1501: System.err.println("URL can't be created for :" + path);
1502: } catch (IOException ioe) {
1503: if (_DEBUG)
1504: ioe.printStackTrace();
1505: }
1506: return null;
1507: }
1508:
1509: public java.net.URL getResource(java.lang.String path)
1510: throws java.net.MalformedURLException {
1511: if (path.charAt(0) != '/')
1512: throw new MalformedURLException("Path: " + path
1513: + " has to start with '/'");
1514: int pp = path.indexOf('?');
1515: // no check for # ?
1516: try {
1517: return new File(getRealPath((pp > 0 ? path.substring(0, pp)
1518: : path))).getCanonicalFile().toURL();
1519: } catch (IOException io) {
1520: }
1521: return null;
1522: }
1523:
1524: public java.util.Set getResourcePaths(java.lang.String path) {
1525: if (path.charAt(0) != '/')
1526: throw new IllegalArgumentException(
1527: "getResourcePaths: path parameters must begin with '/'");
1528: int pp = path.indexOf('?');
1529: if (pp > 0)
1530: path = path.substring(0, pp);
1531: File dir = new File(getRealPath(path));
1532: if (dir.exists() == false || dir.isDirectory() == false)
1533: return null;
1534: Set<String> set = new TreeSet<String>();
1535: String[] els = dir.list();
1536: for (String el : els) {
1537: String fp = path + "/" + el;
1538: if (new File(getRealPath(fp)).isDirectory())
1539: fp += "/";
1540: set.add("/" + fp);
1541: }
1542: return set;
1543: }
1544:
1545: public java.lang.String getMimeType(java.lang.String file) {
1546: if (mimes != null && file != null) {
1547: int p = file.lastIndexOf('.');
1548: if (p > 0) {
1549: String result = mimes.get(file.substring(p)
1550: .toLowerCase());
1551: if (result != null)
1552: return result;
1553: }
1554: }
1555: return server.getMimeType(file);
1556: }
1557:
1558: public int getMinorVersion() {
1559: return 5;
1560: }
1561:
1562: public int getMajorVersion() {
1563: return 2;
1564: }
1565:
1566: public ServletContext getContext(java.lang.String uripath) {
1567: Servlet servlet = server.getServlet(uripath);
1568: if (servlet != null)
1569: return servlet.getServletConfig().getServletContext();
1570: return null;
1571: }
1572:
1573: public java.lang.String getInitParameter(java.lang.String name) {
1574: return contextParameters.get(name);
1575: }
1576:
1577: public java.util.Enumeration getInitParameterNames() {
1578: return contextParameters.keys();
1579: }
1580:
1581: protected void setErrorAttributes(ServletRequest req, int status,
1582: String msg, String servletName, String requestURI,
1583: Throwable t, Class eclass) {
1584: req.setAttribute("javax.servlet.error.status_code", status);
1585: req.setAttribute("javax.servlet.error.exception_type ", eclass);
1586: req.setAttribute("javax.servlet.error.message", msg);
1587: req.setAttribute("javax.servlet.error.exception", t);
1588: req.setAttribute("javax.servlet.error.request_uri", requestURI);
1589: req.setAttribute("javax.servlet.error.servlet_name",
1590: servletName);
1591: }
1592:
1593: public static String validatePath(String path) {
1594: return Utils.canonicalizePath(path);
1595: }
1596:
1597: public void destroy() {
1598: Thread.currentThread().setContextClassLoader(ucl);
1599: if (filters != null)
1600: for (FilterAccessDescriptor fad : filters)
1601: if (fad.filterInstance != null)
1602: fad.filterInstance.destroy();
1603: for (ServletAccessDescr sad : servlets)
1604: if (sad.instance != null)
1605: sad.instance.destroy();
1606: if (listeners != null)
1607: for (int i = listeners.size() - 1; i > -1; i--) {
1608: EventListener listener = listeners.get(i);
1609: if (listener instanceof ServletContextListener)
1610: ((ServletContextListener) listener)
1611: .contextDestroyed(new ServletContextEvent(
1612: this ));
1613: }
1614: Enumeration e = getAttributeNames();
1615: while (e.hasMoreElements())
1616: removeAttribute((String) e.nextElement());
1617: // log("Destroy");
1618: }
1619:
1620: protected class SimpleDispatcher implements RequestDispatcher {
1621: Servlet servlet;
1622:
1623: String servletPath;
1624:
1625: String path;
1626:
1627: String named;
1628:
1629: SimpleDispatcher(Servlet s, String p) {
1630: this (s, null, p);
1631: }
1632:
1633: SimpleDispatcher(String n, Servlet s) {
1634: this (s, null, null);
1635: named = n;
1636: }
1637:
1638: SimpleDispatcher(Servlet s, String sp, String p) {
1639: servlet = s;
1640: path = p;
1641: servletPath = sp;
1642: //if (servletPath.length() > 1 && servletPath.endsWith("/"))
1643: // servletPath = servletPath.substring(0, servletPath.length()-1);
1644: // ending '/' adjustment done on demand
1645: }
1646:
1647: // //////////////////////////////////////////////////////////////////
1648: // interface RequestDispatcher
1649:
1650: public void forward(ServletRequest request,
1651: ServletResponse response) throws ServletException,
1652: java.io.IOException {
1653: if (_DEBUG)
1654: System.err.printf("FORWARD path: %s, servlet: %s%n",
1655: path, servlet);
1656: response.reset(); // drop all previously putting data and headers
1657: SimpleFilterChain sfc = buildFilterChain(
1658: named,
1659: path,
1660: request
1661: .getAttribute("javax.servlet.error.status_code") == null ? DispatchFilterType.FORWARD
1662: : DispatchFilterType.ERROR);
1663: sfc.setServlet(servlet);
1664: sfc.reset();
1665: sfc.doFilter(new DispatchedRequest(
1666: (HttpServletRequest) request, true), response);
1667: // servlet.service(new DispatchedRequest((HttpServletRequest) request, true), response);
1668: Serve.ServeConnection scon = toServeConnection(response);
1669: if (scon != null)
1670: scon.closeStreams();
1671: }
1672:
1673: public void include(ServletRequest request,
1674: final ServletResponse response)
1675: throws ServletException, java.io.IOException {
1676: Serve.ServeConnection scon = toServeConnection(response);
1677: if (scon != null)
1678: scon.setInInclude(true);
1679: if (_DEBUG)
1680: System.err
1681: .printf(
1682: "INCLUDE path: %s, servlet: %s, servlet path %s%n",
1683: path, servlet, servletPath);
1684: try {
1685: SimpleFilterChain sfc = buildFilterChain(named, path,
1686: DispatchFilterType.INCLUDE);
1687: sfc.setServlet(servlet);
1688: sfc.reset();
1689: sfc.doFilter(new DispatchedRequest(
1690: (HttpServletRequest) request, false),
1691: new HttpServletResponseWrapper(
1692: (HttpServletResponse) response) {
1693: // TODO review match to 2.5, some calls are allowed now
1694: public void addDateHeader(
1695: java.lang.String name, long date) {
1696: }
1697:
1698: public void setDateHeader(
1699: java.lang.String name, long date) {
1700: }
1701:
1702: public void setHeader(
1703: java.lang.String name,
1704: java.lang.String value) {
1705: }
1706:
1707: public void addHeader(
1708: java.lang.String name,
1709: java.lang.String value) {
1710: }
1711:
1712: public void setIntHeader(
1713: java.lang.String name, int value) {
1714: }
1715:
1716: public void addIntHeader(
1717: java.lang.String name, int value) {
1718: }
1719:
1720: public void setStatus(int sc) {
1721: }
1722:
1723: public void setStatus(int sc,
1724: java.lang.String sm) {
1725: }
1726:
1727: public void sendRedirect(
1728: java.lang.String location)
1729: throws java.io.IOException {
1730: }
1731:
1732: public void sendError(int sc)
1733: throws java.io.IOException {
1734: }
1735:
1736: public void sendError(int sc,
1737: java.lang.String msg)
1738: throws java.io.IOException {
1739: }
1740:
1741: public void reset() {
1742: }
1743:
1744: public void setLocale(java.util.Locale loc) {
1745: }
1746:
1747: public void resetBuffer() {
1748: }
1749:
1750: public void setContentType(
1751: java.lang.String type) {
1752: }
1753:
1754: public void setContentLength(int len) {
1755: }
1756:
1757: public void setCharacterEncoding(
1758: java.lang.String charset) {
1759: }
1760: });
1761: } finally {
1762: if (scon != null)
1763: scon.setInInclude(false);
1764: }
1765: }
1766:
1767: class DispatchedRequest extends HttpServletRequestWrapper {
1768: boolean forward;
1769:
1770: DispatchedRequest(HttpServletRequest request,
1771: boolean forward) {
1772: super (request);
1773: this .forward = forward;
1774: }
1775:
1776: public java.lang.String getPathInfo() {
1777: if (forward)
1778: return getPathInfo1();
1779: return super .getPathInfo();
1780: }
1781:
1782: public java.lang.String getPathInfo1() {
1783: if (path == null)
1784: return super .getPathInfo();
1785: if (path.equals("/") || "/".equals(servletPath))
1786: return null;
1787: int qp = path.indexOf('?');
1788: int sp = servletPath == null ? -1 : path
1789: .indexOf(servletPath);
1790: if (sp >= 0) {
1791: sp += servletPath.length()
1792: - (servletPath.endsWith("/") ? 1 : 0);
1793: if (_DEBUG)
1794: System.err
1795: .printf(
1796: "FORWARD get pathinfo path %s, servlet %s, sp %d, qp %d, res %s%n",
1797: path, servletPath, sp, qp, path
1798: .substring(sp));
1799: if (qp > sp)
1800: return path.substring(sp, qp);
1801: else
1802: return path.substring(sp);
1803: }
1804: if (_DEBUG)
1805: System.err.printf("FORWARD get pathinfo ret: %s%n",
1806: path);
1807: return path;
1808: }
1809:
1810: public java.lang.String getPathTranslated() {
1811: return getRealPath(getPathInfo());
1812: }
1813:
1814: public java.lang.String getRealPath(java.lang.String path) {
1815: return WebAppServlet.this .getRealPath(path);
1816: }
1817:
1818: public String getServletPath() {
1819: if (forward)
1820: return getServletPath1();
1821: return super .getServletPath();
1822: }
1823:
1824: public String getServletPath1() {
1825: if (servletPath != null)
1826: if (servletPath.equals("/"))
1827: return path;
1828: else
1829: return servletPath.endsWith("/") ? servletPath
1830: .substring(0, servletPath.length() - 1)
1831: : servletPath;
1832: return super .getServletPath();
1833: }
1834:
1835: public String getRequestURI1() {
1836: if (path == null)
1837: if (servletPath != null)
1838: return servletPath;
1839: else
1840: return null;
1841: int qp = path.indexOf('?');
1842: if (qp > 0)
1843: return path.substring(0, qp);
1844: return path;
1845: }
1846:
1847: public String getRequestURI() {
1848: if (forward)
1849: return getRequestURI1();
1850: return super .getRequestURI();
1851: }
1852:
1853: public String getContextPath() {
1854: return contextPath;
1855: }
1856:
1857: public String getQueryString1() {
1858: if (path == null)
1859: return null;
1860: int qp = path.indexOf('?');
1861: if (qp > 0 && qp < path.length() - 1)
1862: return path.substring(qp + 1);
1863: return null;
1864: }
1865:
1866: public String getQueryString() {
1867: if (forward)
1868: return getQueryString1();
1869: return super .getQueryString();
1870: }
1871:
1872: public java.util.Enumeration getAttributeNames() {
1873: List<String> attributes = new ArrayList<String>(10);
1874: if (named == null) {
1875: if (forward) {
1876: attributes
1877: .add("javax.servlet.forward.request_uri");
1878: attributes
1879: .add("javax.servlet.forward.context_path");
1880: attributes
1881: .add("javax.servlet.forward.servlet_path");
1882: attributes
1883: .add("javax.servlet.forward.path_info");
1884: attributes
1885: .add("javax.servlet.forward.query_string");
1886: } else {
1887: attributes
1888: .add("javax.servlet.include.request_uri");
1889: attributes
1890: .add("javax.servlet.include.path_info");
1891: attributes
1892: .add("javax.servlet.include.context_path");
1893: attributes
1894: .add("javax.servlet.include.servlet_path");
1895: attributes
1896: .add("javax.servlet.include.query_string");
1897: }
1898: }
1899: Enumeration e = super .getAttributeNames();
1900: while (e.hasMoreElements())
1901: attributes.add((String) e.nextElement());
1902: return Collections.enumeration(attributes);
1903: }
1904:
1905: public Object getAttribute(String name) {
1906: if (named == null) {
1907: if (forward) {
1908: if ("javax.servlet.forward.request_uri"
1909: .equals(name))
1910: return super .getRequestURI();
1911: else if ("javax.servlet.forward.context_path"
1912: .equals(name))
1913: return super .getContextPath();
1914: else if ("javax.servlet.forward.servlet_path"
1915: .equals(name))
1916: return super .getServletPath();
1917: else if ("javax.servlet.forward.path_info"
1918: .equals(name))
1919: return super .getPathInfo();
1920: else if ("javax.servlet.forward.query_string"
1921: .equals(name))
1922: return super .getQueryString();
1923: } else {
1924: if ("javax.servlet.include.request_uri"
1925: .equals(name))
1926: return getRequestURI1();
1927: else if ("javax.servlet.include.path_info"
1928: .equals(name))
1929: return getPathInfo1();
1930: else if ("javax.servlet.include.context_path"
1931: .equals(name))
1932: return getContextPath();
1933: else if ("javax.servlet.include.query_string"
1934: .equals(name))
1935: return getQueryString1();
1936: else if ("javax.servlet.include.servlet_path"
1937: .equals(name))
1938: return getServletPath1();
1939: }
1940: }
1941: // System.err.printf("!!!return attr:%s=%s%n", name, super.getAttribute(name));
1942: return super .getAttribute(name);
1943: }
1944:
1945: // @Override
1946: // public void setAttribute(String name, Object value) {
1947: // System.err.printf("!!!Set attr %s=%s%n", name, value);
1948: // super.setAttribute(name, value);
1949: // }
1950:
1951: @Override
1952: public RequestDispatcher getRequestDispatcher(String path) {
1953: if (_DEBUG)
1954: System.err
1955: .printf(
1956: "Request %s processing requested from %s%n",
1957: path, forward ? "FORWARD"
1958: : "INCLUDE");
1959: if (path.charAt(0) != '/')
1960: path = getServletPath() + '/' + path;
1961: return WebAppServlet.this .getRequestDispatcher(path);
1962: }
1963:
1964: public String getParameter(String name) {
1965: Map<String, String[]> params = createParameters();
1966: String[] result = params.get(name);
1967: if (result != null)
1968: return result[0];
1969: return super .getParameter(name);
1970: }
1971:
1972: public Map getParameterMap() {
1973: Map result = super .getParameterMap();
1974: result.putAll(createParameters());
1975: return result;
1976: }
1977:
1978: public Enumeration getParameterNames() {
1979: Map params = getParameterMap();
1980: Hashtable result = new Hashtable();
1981: result.putAll(params);
1982: return result.keys();
1983: }
1984:
1985: public String[] getParameterValues(String name) {
1986: Map<String, String[]> params = createParameters();
1987: String[] result = params.get(name);
1988: if (result != null)
1989: return result;
1990: return super .getParameterValues(name);
1991: }
1992:
1993: protected Map<String, String[]> createParameters() {
1994: String query = getQueryString();
1995: if (query != null)
1996: return Acme.Utils.parseQueryString(query, null);
1997: return new Hashtable<String, String[]>();
1998: }
1999: }
2000: }
2001:
2002: // ////////////// Filter methods /////////////////////
2003: protected class WebAppContextFilter implements Filter {
2004: String servPathHolder;
2005:
2006: WebAppContextFilter(String servletPath) {
2007: if (servletPath != null)
2008: servPathHolder = servletPath;
2009: else
2010: throw new NullPointerException("Servlet path is null");
2011: }
2012:
2013: WebAppContextFilter() {
2014: this ("/");
2015: }
2016:
2017: public void init(FilterConfig filterConfig)
2018: throws ServletException {
2019: }
2020:
2021: public void doFilter(final ServletRequest request,
2022: ServletResponse response, FilterChain chain)
2023: throws java.io.IOException, ServletException {
2024: final HttpServletRequest hreq = (HttpServletRequest) request;
2025: final HttpServletResponse hres = (HttpServletResponse) response;
2026: chain
2027: .doFilter(
2028: (HttpServletRequest) Proxy
2029: .newProxyInstance(
2030: javax.servlet.http.HttpServletRequest.class
2031: .getClassLoader(),
2032: new Class[] {
2033: javax.servlet.http.HttpServletRequest.class,
2034: Openable.class },
2035: new InvocationHandler() {
2036: public Object invoke(
2037: Object proxy,
2038: Method method,
2039: Object[] args)
2040: throws Throwable {
2041: String mn = method
2042: .getName();
2043: if (mn
2044: .equals("getServletPath")) {
2045: if (_DEBUG)
2046: System.err
2047: .println("getServletPath() "
2048: + extractPath(
2049: hreq
2050: .getRequestURI(),
2051: contextPath,
2052: servPathHolder,
2053: false));
2054: return extractPath(
2055: hreq
2056: .getRequestURI(),
2057: contextPath,
2058: servPathHolder,
2059: false);
2060: } else if (mn
2061: .equals("getPathInfo")) {
2062: if (_DEBUG)
2063: System.err
2064: .println("getPathInfo() "
2065: + extractPath(
2066: hreq
2067: .getRequestURI(),
2068: contextPath,
2069: servPathHolder,
2070: true));
2071: return extractPath(
2072: hreq
2073: .getRequestURI(),
2074: contextPath,
2075: servPathHolder,
2076: true);
2077: } else if (mn
2078: .equals("getRealPath")) {
2079: if (_DEBUG)
2080: System.err
2081: .println("Path:"
2082: + args[0]);
2083: return getRealPath((String) args[0]);
2084: } else if (mn
2085: .equals("getPathTranslated")) {
2086: return getRealPath(hreq
2087: .getPathInfo());
2088: } else if (mn
2089: .equals("getRequestDispatcher")) {
2090: String url = (String) args[0];
2091: if (url
2092: .charAt(0) != '/')
2093: url = extractPath(
2094: hreq
2095: .getRequestURI(),
2096: contextPath,
2097: servPathHolder,
2098: false)
2099: + '/'
2100: + url;
2101: // System.err.printf("req.getDispatcher(%s), %s%n", url, extractPath(hreq.getRequestURI(), contextPath, servPathHolder, false));
2102: return getRequestDispatcher(url);
2103: } else if (mn
2104: .equals("getContextPath")) {
2105: return contextPath;
2106: } else if (mn
2107: .equals("getSession")) {
2108: // System.err.println("getsession");
2109: HttpSession session = (HttpSession) method
2110: .invoke(
2111: hreq,
2112: args);
2113: // TODO some overhead is here, context and listeners will be overloaded each time
2114: // time of accessing session while it's new
2115: if (session instanceof Serve.AcmeSession
2116: && (session
2117: .getServletContext() == null || session
2118: .isNew())) {
2119: // System.err.println("set listeners & context");
2120: ((Serve.AcmeSession) session)
2121: .setListeners(WebAppServlet.this .sessionListeners);
2122: ((Serve.AcmeSession) session)
2123: .setServletContext(WebAppServlet.this );
2124: if (sessionTimeout > 0)
2125: session
2126: .setMaxInactiveInterval(sessionTimeout);
2127: }
2128: return session;
2129: } else if (attributeListeners != null) {
2130: if (mn
2131: .equals("setAttribute")) {
2132: Object av = hreq
2133: .getAttribute((String) args[0]);
2134: hreq
2135: .setAttribute(
2136: (String) args[0],
2137: args[1]);
2138: if (av == null) {
2139: ServletRequestAttributeEvent e = new ServletRequestAttributeEvent(
2140: WebAppServlet.this ,
2141: hreq,
2142: (String) args[0],
2143: args[1]);
2144: for (ServletRequestAttributeListener sarl : attributeListeners)
2145: sarl
2146: .attributeAdded(e);
2147: } else {
2148: ServletRequestAttributeEvent e = new ServletRequestAttributeEvent(
2149: WebAppServlet.this ,
2150: hreq,
2151: (String) args[0],
2152: av);
2153: for (ServletRequestAttributeListener sarl : attributeListeners)
2154: sarl
2155: .attributeReplaced(e);
2156: }
2157: return null;
2158: } else if (mn
2159: .equals("removeAttribute")) {
2160: Object av = hreq
2161: .getAttribute((String) args[0]);
2162: hreq
2163: .removeAttribute((String) args[0]);
2164: ServletRequestAttributeEvent e = new ServletRequestAttributeEvent(
2165: WebAppServlet.this ,
2166: hreq,
2167: (String) args[0],
2168: av);
2169: for (ServletRequestAttributeListener sarl : attributeListeners)
2170: sarl
2171: .attributeRemoved(e);
2172: return null;
2173: } else if (mn
2174: .equals("getOrigin")) {
2175: Object origin = hreq;
2176: while (origin instanceof Openable)
2177: origin = ((Openable) origin)
2178: .getOrigin();
2179: return origin;
2180: }
2181: }
2182: try {
2183: return method
2184: .invoke(
2185: hreq,
2186: args);
2187: } catch (InvocationTargetException ite) {
2188: throw ite
2189: .getTargetException();
2190: }
2191: }
2192: }), // response);
2193: (HttpServletResponse) Proxy
2194: .newProxyInstance(
2195: javax.servlet.http.HttpServletResponse.class
2196: .getClassLoader(),
2197: new Class[] {
2198: javax.servlet.http.HttpServletResponse.class,
2199: Openable.class },
2200: new InvocationHandler() {
2201: public Object invoke(
2202: Object proxy,
2203: Method method,
2204: Object[] args)
2205: throws Throwable {
2206: String mn = method
2207: .getName();
2208: if (mn
2209: .equals("sendError")) {
2210: if (errorPages != null)
2211: for (ErrorPageDescr epd : errorPages)
2212: if (epd.errorCode == ((Integer) args[0])
2213: .intValue()) {
2214: setErrorAttributes(
2215: hreq,
2216: (Integer) args[0],
2217: args.length > 1 ? (String) args[1]
2218: : "",
2219: getServletName(),
2220: hreq
2221: .getRequestURI(),
2222: null,
2223: null);
2224: // System.err.printf("Forwarding to %s for %d%n",epd.errorPage, args[0]);
2225: getRequestDispatcher(
2226: epd.errorPage)
2227: .forward(
2228: hreq,
2229: hres);
2230: return null;
2231: }
2232: } else if (mn
2233: .equals("getOrigin")) {
2234: Object origin = hres;
2235: while (origin instanceof Openable)
2236: origin = ((Openable) origin)
2237: .getOrigin();
2238: return origin;
2239:
2240: } // else if (mn.equals("sendRedirect")) {
2241: // System.err.printf("Redirect to:%s%n",args[0]);
2242: // }
2243: return method
2244: .invoke(
2245: hres,
2246: args);
2247: }
2248: }));
2249: }
2250:
2251: public void destroy() {
2252: // destroy context filter
2253: }
2254: }
2255:
2256: static public String extractPath(String uri, String context,
2257: String servlet, boolean info) {
2258: if (_DEBUG)
2259: System.err
2260: .printf(
2261: "Extract path URI: %s, context: %s, servlet: %s, action %b\n",
2262: uri, context, servlet, info);
2263: int sp = uri.indexOf(servlet, context.length());
2264: if (sp < 0) {
2265: sp = context.length();
2266: /*
2267: * if (_DEBUG) System.err.printf("servlet pos: -1 %n"); if (info) return null; // invalid URI or too short return uri.substring(context.length());
2268: */
2269: }
2270: int pp = uri.indexOf('?', sp);
2271: int ip = servlet.endsWith("/") ? sp + servlet.length() - 1
2272: : uri.indexOf('/', sp + servlet.length());
2273: if (_DEBUG)
2274: System.err.printf(
2275: "servlet pos %d, info pos: %d, param pos: %d %n",
2276: sp, ip, pp);
2277: if (info == false) {
2278: if (servlet.equals("/") || ip < 0)
2279: if (pp > 0)
2280: return uri.substring(sp, pp);
2281: else
2282: return uri.substring(sp);
2283: if (pp < 0)
2284: return uri.substring(sp, ip);
2285:
2286: return uri.substring(sp, pp);
2287: }
2288: if (servlet.equals("/") || ip < 0 || (pp > 0 && ip > pp))
2289: return null;
2290: if (pp < 0)
2291: return uri.substring(ip);
2292: return uri.substring(ip, pp);
2293: }
2294:
2295: protected class SimpleFilterChain implements FilterChain {
2296: List<FilterAccessDescriptor> filters;
2297:
2298: Iterator<FilterAccessDescriptor> iterator;
2299:
2300: Servlet servlet;
2301:
2302: Filter filter;
2303:
2304: Filter nextFilter;
2305:
2306: ServletAccessDescr sad;
2307:
2308: SimpleFilterChain() {
2309: filters = new ArrayList<FilterAccessDescriptor>();
2310: }
2311:
2312: public void setFilter(Filter filter) {
2313: this .filter = filter;
2314: }
2315:
2316: public void doFilter(ServletRequest request,
2317: ServletResponse response) throws java.io.IOException,
2318: ServletException {
2319:
2320: if (nextFilter != null) {
2321: nextFilter = null;
2322: filter.doFilter(request, response, this );
2323: } else if (iterator.hasNext()) {
2324: FilterAccessDescriptor fad = iterator.next();
2325: try {
2326: fad.filterInstance
2327: .doFilter(request, response, this );
2328: } catch (UnavailableException ue) {
2329: if (ue.isPermanent()) {
2330: synchronized (fad) {
2331: if (fad.filterInstance != null) {
2332: fad.filterInstance.destroy();
2333: fad.filterInstance = null;
2334: }
2335: }
2336: } else {
2337: fad.timeToReactivate = System
2338: .currentTimeMillis()
2339: + ue.getUnavailableSeconds() * 1000l;
2340: }
2341: doFilter(request, response);
2342: // iterator.remove();
2343: }
2344: } else
2345: // TODO figure out error handler needed for filters, it should also handle UnavailableException
2346: // call sevlet
2347: try {
2348: servlet.service(request, response);
2349: } catch (IOException ioe) {
2350: if (handleError(ioe, request, response) == false)
2351: throw ioe;
2352: } catch (UnavailableException ue) {
2353: // log("Servlet " + servlet + " asked to be unavailable", ue);
2354: if (sad != null) {
2355: if (ue.isPermanent()) {
2356: synchronized (sad) {
2357: if (sad.instance != null) {
2358: sad.instance.destroy();
2359: sad.instance = null;
2360: }
2361: }
2362: } else {
2363: sad.timeToReactivate = System
2364: .currentTimeMillis()
2365: + ue.getUnavailableSeconds()
2366: * 1000l;
2367: }
2368: }
2369: ((HttpServletResponse) response).sendError(
2370: HttpServletResponse.SC_SERVICE_UNAVAILABLE,
2371: ue.getMessage());
2372: // allowing custom handling?
2373: // eating an exception to avoid removing entire webapp servlet throw ue;
2374: } catch (ServletException se) {
2375: if (handleError(se, request, response) == false)
2376: throw se;
2377: } catch (Throwable re) {
2378: if (re instanceof ThreadDeath)
2379: throw (ThreadDeath) re;
2380: if (handleError(re, request, response) == false)
2381: throw new RuntimeException(re);
2382: }
2383: }
2384:
2385: protected boolean handleError(Throwable t,
2386: ServletRequest request, ServletResponse response)
2387: throws java.io.IOException, ServletException {
2388: if (errorPages != null) {
2389: Class eclass = t.getClass();
2390: for (ErrorPageDescr epd : errorPages) {
2391: if (epd.exception != null
2392: && eclass.equals(epd.exception)) {
2393: log("forward to " + epd.errorPage, t);
2394: ((HttpServletResponse) response)
2395: .sendRedirect(epd.errorPage);
2396: setErrorAttributes(request, -1, t.getMessage(),
2397: getServletName(),
2398: ((HttpServletRequest) request)
2399: .getRequestURI(), t, t
2400: .getClass());
2401: getRequestDispatcher(epd.errorPage).forward(
2402: request, response);
2403: return true;
2404: }
2405: }
2406: Class[] peclasses = eclass.getClasses();
2407: for (Class peclass : peclasses)
2408: for (ErrorPageDescr epd : errorPages) {
2409: if (epd.exception != null
2410: && peclass.equals(epd.exception)) {
2411: log("forward to " + epd.errorPage, t);
2412: ((HttpServletResponse) response)
2413: .sendRedirect(epd.errorPage);
2414: setErrorAttributes(request, -1, t
2415: .getMessage(), getServletName(),
2416: ((HttpServletRequest) request)
2417: .getRequestURI(), t, t
2418: .getClass());
2419: getRequestDispatcher(epd.errorPage)
2420: .forward(request, response);
2421: return true;
2422: }
2423: }
2424:
2425: }
2426: return false;
2427: }
2428:
2429: protected void reset() {
2430: iterator = filters.iterator();
2431: nextFilter = filter;
2432: }
2433:
2434: protected void add(FilterAccessDescriptor fad) {
2435: if (fad.timeToReactivate > 0
2436: && fad.timeToReactivate > System
2437: .currentTimeMillis())
2438: return;
2439: if (filters.contains(fad) == false)
2440: filters.add(fad);
2441: }
2442:
2443: protected void setServlet(Servlet servlet) {
2444: this .servlet = servlet;
2445: }
2446:
2447: protected void setServlet(ServletAccessDescr sad) {
2448: this .servlet = sad.instance;
2449: this .sad = sad;
2450: }
2451: }
2452:
2453: private final static boolean _DEBUG = false;
2454:
2455: private final static boolean __DEBUG = "yes".equals(System
2456: .getProperty(DEF_DEBUG));
2457: }
|