0001: // ========================================================================
0002: // Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
0003: // ------------------------------------------------------------------------
0004: // Licensed under the Apache License, Version 2.0 (the "License");
0005: // you may not use this file except in compliance with the License.
0006: // You may obtain a copy of the License at
0007: // http://www.apache.org/licenses/LICENSE-2.0
0008: // Unless required by applicable law or agreed to in writing, software
0009: // distributed under the License is distributed on an "AS IS" BASIS,
0010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0011: // See the License for the specific language governing permissions and
0012: // limitations under the License.
0013: // ========================================================================
0014:
0015: package org.mortbay.jetty.servlet;
0016:
0017: import java.io.IOException;
0018: import java.util.ArrayList;
0019: import java.util.Arrays;
0020: import java.util.HashMap;
0021: import java.util.List;
0022: import java.util.Map;
0023:
0024: import javax.servlet.Filter;
0025: import javax.servlet.FilterChain;
0026: import javax.servlet.RequestDispatcher;
0027: import javax.servlet.Servlet;
0028: import javax.servlet.ServletContext;
0029: import javax.servlet.ServletException;
0030: import javax.servlet.ServletRequest;
0031: import javax.servlet.ServletResponse;
0032: import javax.servlet.UnavailableException;
0033: import javax.servlet.http.HttpServletRequest;
0034: import javax.servlet.http.HttpServletResponse;
0035:
0036: import org.mortbay.jetty.EofException;
0037: import org.mortbay.jetty.HttpConnection;
0038: import org.mortbay.jetty.HttpException;
0039: import org.mortbay.jetty.Request;
0040: import org.mortbay.jetty.RetryRequest;
0041: import org.mortbay.jetty.Server;
0042: import org.mortbay.jetty.handler.AbstractHandler;
0043: import org.mortbay.jetty.handler.ContextHandler;
0044: import org.mortbay.log.Log;
0045: import org.mortbay.util.LazyList;
0046: import org.mortbay.util.MultiException;
0047: import org.mortbay.util.MultiMap;
0048: import org.mortbay.util.URIUtil;
0049:
0050: /* --------------------------------------------------------------------- */
0051: /** Servlet HttpHandler.
0052: * This handler maps requests to servlets that implement the
0053: * javax.servlet.http.HttpServlet API.
0054: * <P>
0055: * This handler does not implement the full J2EE features and is intended to
0056: * be used when a full web application is not required. Specifically filters
0057: * and request wrapping are not supported.
0058: *
0059: * Unless run as part of a {@link Context} or derivative, the {@link #initialize()}
0060: * method must be called manually after start().
0061: *
0062: * @see org.mortbay.jetty.webapp.WebAppContext
0063: * @author Greg Wilkins
0064: */
0065: public class ServletHandler extends AbstractHandler {
0066: /* ------------------------------------------------------------ */
0067: public static final String __DEFAULT_SERVLET = "default";
0068: public static final String __J_S_CONTEXT_TEMPDIR = "javax.servlet.context.tempdir";
0069: public static final String __J_S_ERROR_EXCEPTION = "javax.servlet.error.exception";
0070: public static final String __J_S_ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";
0071: public static final String __J_S_ERROR_MESSAGE = "javax.servlet.error.message";
0072: public static final String __J_S_ERROR_REQUEST_URI = "javax.servlet.error.request_uri";
0073: public static final String __J_S_ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";
0074: public static final String __J_S_ERROR_STATUS_CODE = "javax.servlet.error.status_code";
0075:
0076: /* ------------------------------------------------------------ */
0077: private ContextHandler _contextHandler;
0078: private ContextHandler.SContext _servletContext;
0079: private FilterHolder[] _filters;
0080: private FilterMapping[] _filterMappings;
0081: private boolean _filterChainsCached = true;
0082: private int _maxFilterChainsCacheSize = 1000;
0083:
0084: private ServletHolder[] _servlets;
0085: private ServletMapping[] _servletMappings;
0086:
0087: private transient Map _filterNameMap = new HashMap();
0088: private transient List _filterPathMappings;
0089: private transient MultiMap _filterNameMappings;
0090:
0091: private transient Map _servletNameMap = new HashMap();
0092: private transient PathMap _servletPathMap;
0093:
0094: protected transient HashMap _chainCache[];
0095: protected transient HashMap _namedChainCache[];
0096:
0097: /* ------------------------------------------------------------ */
0098: /** Constructor.
0099: */
0100: public ServletHandler() {
0101: }
0102:
0103: /* ------------------------------------------------------------ */
0104: /*
0105: * @see org.mortbay.jetty.handler.AbstractHandler#setServer(org.mortbay.jetty.Server)
0106: */
0107: public void setServer(Server server) {
0108: if (getServer() != null && getServer() != server) {
0109: getServer().getContainer().update(this , _filters, null,
0110: "filter", true);
0111: getServer().getContainer().update(this , _filterMappings,
0112: null, "filterMapping", true);
0113: getServer().getContainer().update(this , _servlets, null,
0114: "servlet", true);
0115: getServer().getContainer().update(this , _servletMappings,
0116: null, "servletMapping", true);
0117: }
0118: if (server != null && getServer() != server) {
0119: server.getContainer().update(this , null, _filters,
0120: "filter", true);
0121: server.getContainer().update(this , null, _filterMappings,
0122: "filterMapping", true);
0123: server.getContainer().update(this , null, _servlets,
0124: "servlet", true);
0125: server.getContainer().update(this , null, _servletMappings,
0126: "servletMapping", true);
0127: }
0128: super .setServer(server);
0129:
0130: }
0131:
0132: /* ----------------------------------------------------------------- */
0133: protected synchronized void doStart() throws Exception {
0134: _servletContext = ContextHandler.getCurrentContext();
0135: _contextHandler = _servletContext == null ? null
0136: : _servletContext.getContextHandler();
0137:
0138: updateNameMappings();
0139: updateMappings();
0140:
0141: if (_filterChainsCached) {
0142: _chainCache = new HashMap[] { null, new HashMap(),
0143: new HashMap(), null, new HashMap(), null, null,
0144: null, new HashMap() };
0145: _namedChainCache = new HashMap[] { null, null,
0146: new HashMap(), null, new HashMap(), null, null,
0147: null, new HashMap() };
0148: }
0149:
0150: super .doStart();
0151:
0152: if (_contextHandler == null
0153: || !(_contextHandler instanceof Context))
0154: initialize();
0155: }
0156:
0157: /* ----------------------------------------------------------------- */
0158: protected synchronized void doStop() throws Exception {
0159: super .doStop();
0160:
0161: // Stop filters
0162: if (_filters != null) {
0163: for (int i = _filters.length; i-- > 0;) {
0164: try {
0165: _filters[i].stop();
0166: } catch (Exception e) {
0167: Log.warn(Log.EXCEPTION, e);
0168: }
0169: }
0170: }
0171:
0172: // Stop servlets
0173: if (_servlets != null) {
0174: for (int i = _servlets.length; i-- > 0;) {
0175: try {
0176: _servlets[i].stop();
0177: } catch (Exception e) {
0178: Log.warn(Log.EXCEPTION, e);
0179: }
0180: }
0181: }
0182:
0183: _filterPathMappings = null;
0184: _filterNameMappings = null;
0185:
0186: _servletPathMap = null;
0187: _chainCache = null;
0188: _namedChainCache = null;
0189: }
0190:
0191: /* ------------------------------------------------------------ */
0192: /**
0193: * @return Returns the contextLog.
0194: */
0195: public Object getContextLog() {
0196: return null;
0197: }
0198:
0199: /* ------------------------------------------------------------ */
0200: /**
0201: * @return Returns the filterMappings.
0202: */
0203: public FilterMapping[] getFilterMappings() {
0204: return _filterMappings;
0205: }
0206:
0207: /* ------------------------------------------------------------ */
0208: /** Get Filters.
0209: * @return Array of defined servlets
0210: */
0211: public FilterHolder[] getFilters() {
0212: return _filters;
0213: }
0214:
0215: /* ------------------------------------------------------------ */
0216: /** ServletHolder matching path.
0217: * @param pathInContext Path within _context.
0218: * @return PathMap Entries pathspec to ServletHolder
0219: */
0220: public PathMap.Entry getHolderEntry(String pathInContext) {
0221: if (_servletPathMap == null)
0222: return null;
0223: return _servletPathMap.getMatch(pathInContext);
0224: }
0225:
0226: /* ------------------------------------------------------------ */
0227: /**
0228: * @return A {@link RequestDispatcher dispatcher} wrapping the resource at <code>uriInContext</code>,
0229: * or <code>null</code> if the specified uri cannot be dispatched to.
0230: */
0231: public RequestDispatcher getRequestDispatcher(String uriInContext) {
0232: if (uriInContext == null)
0233: return null;
0234:
0235: if (!uriInContext.startsWith("/"))
0236: return null;
0237:
0238: try {
0239: String query = null;
0240: int q = 0;
0241: if ((q = uriInContext.indexOf('?')) > 0) {
0242: query = uriInContext.substring(q + 1);
0243: uriInContext = uriInContext.substring(0, q);
0244: }
0245: if ((q = uriInContext.indexOf(';')) > 0)
0246: uriInContext = uriInContext.substring(0, q);
0247:
0248: String pathInContext = URIUtil.canonicalPath(URIUtil
0249: .decodePath(uriInContext));
0250: String uri = URIUtil.addPaths(_contextHandler
0251: .getContextPath(), uriInContext);
0252: return new Dispatcher(_contextHandler, uri, pathInContext,
0253: query);
0254: } catch (Exception e) {
0255: Log.ignore(e);
0256: }
0257: return null;
0258: }
0259:
0260: /* ------------------------------------------------------------ */
0261: public ServletContext getServletContext() {
0262: return _servletContext;
0263: }
0264:
0265: /* ------------------------------------------------------------ */
0266: /**
0267: * @return Returns the servletMappings.
0268: */
0269: public ServletMapping[] getServletMappings() {
0270: return _servletMappings;
0271: }
0272:
0273: /* ------------------------------------------------------------ */
0274: /** Get Servlets.
0275: * @return Array of defined servlets
0276: */
0277: public ServletHolder[] getServlets() {
0278: return _servlets;
0279: }
0280:
0281: /* ------------------------------------------------------------ */
0282: public ServletHolder getServlet(String name) {
0283: return (ServletHolder) _servletNameMap.get(name);
0284: }
0285:
0286: /* ------------------------------------------------------------ */
0287: /*
0288: * @see org.mortbay.jetty.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
0289: */
0290: public void handle(String target, HttpServletRequest request,
0291: HttpServletResponse response, int type) throws IOException,
0292: ServletException {
0293: if (!isStarted())
0294: return;
0295:
0296: // Get the base requests
0297: final Request base_request = (request instanceof Request) ? ((Request) request)
0298: : HttpConnection.getCurrentConnection().getRequest();
0299: final String old_servlet_name = base_request.getServletName();
0300: final String old_servlet_path = base_request.getServletPath();
0301: final String old_path_info = base_request.getPathInfo();
0302: final Map old_role_map = base_request.getRoleMap();
0303:
0304: try {
0305: ServletHolder servlet_holder = null;
0306: FilterChain chain = null;
0307:
0308: // find the servlet
0309: if (target.startsWith("/")) {
0310: // Look for the servlet by path
0311: PathMap.Entry entry = getHolderEntry(target);
0312: if (entry != null) {
0313: servlet_holder = (ServletHolder) entry.getValue();
0314: base_request.setServletName(servlet_holder
0315: .getName());
0316: base_request
0317: .setRoleMap(servlet_holder.getRoleMap());
0318: if (Log.isDebugEnabled())
0319: Log.debug("servlet=" + servlet_holder);
0320:
0321: String servlet_path_spec = (String) entry.getKey();
0322: String servlet_path = entry.getMapped() != null ? entry
0323: .getMapped()
0324: : PathMap.pathMatch(servlet_path_spec,
0325: target);
0326: String path_info = PathMap.pathInfo(
0327: servlet_path_spec, target);
0328:
0329: if (type == INCLUDE) {
0330: base_request.setAttribute(
0331: Dispatcher.__INCLUDE_SERVLET_PATH,
0332: servlet_path);
0333: base_request.setAttribute(
0334: Dispatcher.__INCLUDE_PATH_INFO,
0335: path_info);
0336: } else {
0337: base_request.setServletPath(servlet_path);
0338: base_request.setPathInfo(path_info);
0339: }
0340:
0341: if (servlet_holder != null
0342: && _filterMappings != null
0343: && _filterMappings.length > 0)
0344: chain = getFilterChain(type, target,
0345: servlet_holder);
0346: }
0347: } else {
0348: // look for a servlet by name!
0349: servlet_holder = (ServletHolder) _servletNameMap
0350: .get(target);
0351: if (servlet_holder != null && _filterMappings != null
0352: && _filterMappings.length > 0) {
0353: base_request.setServletName(servlet_holder
0354: .getName());
0355: chain = getFilterChain(type, null, servlet_holder);
0356: }
0357: }
0358:
0359: if (Log.isDebugEnabled()) {
0360: Log.debug("chain=" + chain);
0361: Log.debug("servelet holder=" + servlet_holder);
0362: }
0363:
0364: // Do the filter/handling thang
0365: if (servlet_holder != null) {
0366: base_request.setHandled(true);
0367: if (chain != null)
0368: chain.doFilter(request, response);
0369: else
0370: servlet_holder.handle(request, response);
0371: } else
0372: notFound(request, response);
0373: } catch (RetryRequest e) {
0374: base_request.setHandled(false);
0375: throw e;
0376: } catch (EofException e) {
0377: throw e;
0378: } catch (Exception e) {
0379: if (type != REQUEST) {
0380: if (e instanceof IOException)
0381: throw (IOException) e;
0382: if (e instanceof RuntimeException)
0383: throw (RuntimeException) e;
0384: if (e instanceof ServletException)
0385: throw (ServletException) e;
0386: }
0387:
0388: Throwable th = e;
0389: while (th instanceof ServletException) {
0390: Log.warn(th);
0391: Throwable cause = ((ServletException) th)
0392: .getRootCause();
0393: if (cause == th || cause == null)
0394: break;
0395: th = cause;
0396: }
0397:
0398: if (th instanceof HttpException)
0399: throw (HttpException) th;
0400: else if (Log.isDebugEnabled()
0401: || !(th instanceof java.io.IOException)) {
0402: Log.warn(request.getRequestURI() + ": ", th);
0403: if (Log.isDebugEnabled())
0404: Log.debug(request.toString());
0405: }
0406: // TODO clean up
0407: Log.warn(request.getRequestURI(), th);
0408:
0409: // TODO httpResponse.getHttpConnection().forceClose();
0410: if (!response.isCommitted()) {
0411: request.setAttribute(
0412: ServletHandler.__J_S_ERROR_EXCEPTION_TYPE, th
0413: .getClass());
0414: request.setAttribute(
0415: ServletHandler.__J_S_ERROR_EXCEPTION, th);
0416: if (th instanceof UnavailableException) {
0417: UnavailableException ue = (UnavailableException) th;
0418: if (ue.isPermanent())
0419: response.sendError(
0420: HttpServletResponse.SC_NOT_FOUND, th
0421: .getMessage());
0422: else
0423: response
0424: .sendError(
0425: HttpServletResponse.SC_SERVICE_UNAVAILABLE,
0426: th.getMessage());
0427: } else
0428: response
0429: .sendError(
0430: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
0431: th.getMessage());
0432: } else if (Log.isDebugEnabled())
0433: Log.debug("Response already committed for handling "
0434: + th);
0435: } catch (Error e) {
0436: if (type != REQUEST)
0437: throw e;
0438: Log.warn("Error for " + request.getRequestURI(), e);
0439: if (Log.isDebugEnabled())
0440: Log.debug(request.toString());
0441:
0442: // TODO httpResponse.getHttpConnection().forceClose();
0443: if (!response.isCommitted()) {
0444: request.setAttribute(
0445: ServletHandler.__J_S_ERROR_EXCEPTION_TYPE, e
0446: .getClass());
0447: request.setAttribute(
0448: ServletHandler.__J_S_ERROR_EXCEPTION, e);
0449: response.sendError(
0450: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
0451: .getMessage());
0452: } else if (Log.isDebugEnabled())
0453: Log
0454: .debug(
0455: "Response already committed for handling ",
0456: e);
0457: } finally {
0458: base_request.setServletName(old_servlet_name);
0459: base_request.setRoleMap(old_role_map);
0460: if (type != INCLUDE) {
0461: base_request.setServletPath(old_servlet_path);
0462: base_request.setPathInfo(old_path_info);
0463: }
0464: }
0465: return;
0466: }
0467:
0468: /* ------------------------------------------------------------ */
0469: private FilterChain getFilterChain(int requestType,
0470: String pathInContext, ServletHolder servletHolder) {
0471: String key = pathInContext == null ? servletHolder.getName()
0472: : pathInContext;
0473:
0474: if (_filterChainsCached && _chainCache != null) {
0475: synchronized (this ) {
0476: if (_chainCache[requestType].containsKey(key))
0477: return (FilterChain) _chainCache[requestType]
0478: .get(key);
0479: }
0480: }
0481:
0482: // Build list of filters
0483: Object filters = null;
0484:
0485: // Path filters
0486: if (pathInContext != null && _filterPathMappings != null) {
0487: for (int i = 0; i < _filterPathMappings.size(); i++) {
0488: FilterMapping mapping = (FilterMapping) _filterPathMappings
0489: .get(i);
0490: if (mapping.appliesTo(pathInContext, requestType))
0491: filters = LazyList.add(filters, mapping
0492: .getFilterHolder());
0493: }
0494: }
0495:
0496: // Servlet name filters
0497: if (servletHolder != null && _filterNameMappings != null
0498: && _filterNameMappings.size() > 0) {
0499: // Servlet name filters
0500: if (_filterNameMappings.size() > 0) {
0501: Object o = _filterNameMappings.get(servletHolder
0502: .getName());
0503: for (int i = 0; i < LazyList.size(o); i++) {
0504: FilterMapping mapping = (FilterMapping) LazyList
0505: .get(o, i);
0506: if (mapping.appliesTo(requestType))
0507: filters = LazyList.add(filters, mapping
0508: .getFilterHolder());
0509: }
0510:
0511: o = _filterNameMappings.get("*");
0512: for (int i = 0; i < LazyList.size(o); i++) {
0513: FilterMapping mapping = (FilterMapping) LazyList
0514: .get(o, i);
0515: if (mapping.appliesTo(requestType))
0516: filters = LazyList.add(filters, mapping
0517: .getFilterHolder());
0518: }
0519: }
0520: }
0521:
0522: if (filters == null)
0523: return null;
0524:
0525: FilterChain chain = null;
0526: if (_filterChainsCached) {
0527: synchronized (this ) {
0528: if (LazyList.size(filters) > 0)
0529: chain = new CachedChain(filters, servletHolder);
0530: if (_maxFilterChainsCacheSize > 0
0531: && _chainCache[requestType].size() > _maxFilterChainsCacheSize)
0532: _chainCache[requestType].clear();
0533: _chainCache[requestType].put(key, chain);
0534: }
0535: } else if (LazyList.size(filters) > 0)
0536: chain = new Chain(filters, servletHolder);
0537:
0538: return chain;
0539: }
0540:
0541: /* ------------------------------------------------------------ */
0542: /**
0543: * @return Returns the initializeAtStart.
0544: * @deprecated
0545: */
0546: public boolean isInitializeAtStart() {
0547: return false;
0548: }
0549:
0550: /* ------------------------------------------------------------ */
0551: /**
0552: * @param initializeAtStart The initializeAtStart to set.
0553: * @deprecated
0554: */
0555: public void setInitializeAtStart(boolean initializeAtStart) {
0556: }
0557:
0558: /* ------------------------------------------------------------ */
0559: /** Initialize filters and load-on-startup servlets.
0560: * Called automatically from start if autoInitializeServlet is true.
0561: */
0562: public void initialize() throws Exception {
0563: MultiException mx = new MultiException();
0564:
0565: // Start filters
0566: if (_filters != null) {
0567: for (int i = 0; i < _filters.length; i++)
0568: _filters[i].start();
0569: }
0570:
0571: if (_servlets != null) {
0572: // Sort and Initialize servlets
0573: ServletHolder[] servlets = (ServletHolder[]) _servlets
0574: .clone();
0575: Arrays.sort(servlets);
0576: for (int i = 0; i < servlets.length; i++) {
0577: try {
0578: if (servlets[i].getClassName() == null
0579: && servlets[i].getForcedPath() != null) {
0580: ServletHolder forced_holder = (ServletHolder) _servletPathMap
0581: .match(servlets[i].getForcedPath());
0582: if (forced_holder == null) {
0583: mx.add(new IllegalStateException(
0584: "No servlet for "
0585: + servlets[i]
0586: .getForcedPath()));
0587: continue;
0588: }
0589: servlets[i].setClassName(forced_holder
0590: .getClassName());
0591: }
0592:
0593: servlets[i].start();
0594: } catch (Throwable e) {
0595: Log.debug(Log.EXCEPTION, e);
0596: mx.add(e);
0597: }
0598: }
0599: mx.ifExceptionThrow();
0600: }
0601: }
0602:
0603: /* ------------------------------------------------------------ */
0604: /**
0605: * @return Returns the filterChainsCached.
0606: */
0607: public boolean isFilterChainsCached() {
0608: return _filterChainsCached;
0609: }
0610:
0611: /* ------------------------------------------------------------ */
0612: /**
0613: * @see also newServletHolder(Class)
0614: */
0615: public ServletHolder newServletHolder() {
0616: return new ServletHolder();
0617: }
0618:
0619: /* ------------------------------------------------------------ */
0620: public ServletHolder newServletHolder(Class servlet) {
0621: return new ServletHolder(servlet);
0622: }
0623:
0624: /* ------------------------------------------------------------ */
0625: /** conveniance method to add a servlet.
0626: * @return The servlet holder.
0627: */
0628: public ServletHolder addServletWithMapping(String className,
0629: String pathSpec) {
0630: ServletHolder holder = newServletHolder(null);
0631: holder.setName(className);
0632: holder.setClassName(className);
0633:
0634: addServletWithMapping(holder, pathSpec);
0635:
0636: return holder;
0637: }
0638:
0639: /* ------------------------------------------------------------ */
0640: /** conveniance method to add a servlet.
0641: * @return The servlet holder.
0642: */
0643: public ServletHolder addServletWithMapping(Class servlet,
0644: String pathSpec) {
0645: ServletHolder holder = newServletHolder(servlet);
0646: setServlets((ServletHolder[]) LazyList.addToArray(
0647: getServlets(), holder, ServletHolder.class));
0648:
0649: addServletWithMapping(holder, pathSpec);
0650:
0651: return holder;
0652: }
0653:
0654: /* ------------------------------------------------------------ */
0655: /** conveniance method to add a servlet.
0656: * @param name
0657: * @param className
0658: * @param pathSpec
0659: * @return The servlet holder.
0660: */
0661: public void addServletWithMapping(ServletHolder servlet,
0662: String pathSpec) {
0663: ServletHolder[] holders = getServlets();
0664: if (holders != null)
0665: holders = (ServletHolder[]) holders.clone();
0666:
0667: try {
0668: setServlets((ServletHolder[]) LazyList.addToArray(holders,
0669: servlet, ServletHolder.class));
0670:
0671: ServletMapping mapping = new ServletMapping();
0672: mapping.setServletName(servlet.getName());
0673: mapping.setPathSpec(pathSpec);
0674: setServletMappings((ServletMapping[]) LazyList
0675: .addToArray(getServletMappings(), mapping,
0676: ServletMapping.class));
0677: } catch (Exception e) {
0678: setServlets(holders);
0679: if (e instanceof RuntimeException)
0680: throw (RuntimeException) e;
0681: throw new RuntimeException(e);
0682: }
0683: }
0684:
0685: /* ------------------------------------------------------------ */
0686: /** Convenience method to add a servlet with a servlet mapping.
0687: * @param className
0688: * @param pathSpec
0689: * @return
0690: * @deprecated
0691: */
0692: public ServletHolder addServlet(String className, String pathSpec) {
0693: return addServletWithMapping(className, pathSpec);
0694: }
0695:
0696: /* ------------------------------------------------------------ */
0697: /**Convenience method to add a pre-constructed ServletHolder.
0698: * @param holder
0699: */
0700: public void addServlet(ServletHolder holder) {
0701: setServlets((ServletHolder[]) LazyList.addToArray(
0702: getServlets(), holder, ServletHolder.class));
0703: }
0704:
0705: /* ------------------------------------------------------------ */
0706: /** Convenience method to add a pre-constructed ServletMapping.
0707: * @param mapping
0708: */
0709: public void addServletMapping(ServletMapping mapping) {
0710: setServletMappings((ServletMapping[]) LazyList.addToArray(
0711: getServletMappings(), mapping, ServletMapping.class));
0712: }
0713:
0714: /* ------------------------------------------------------------ */
0715: public FilterHolder newFilterHolder(Class filter) {
0716: return new FilterHolder(filter);
0717: }
0718:
0719: /* ------------------------------------------------------------ */
0720: /**
0721: * @see {@link #newFilterHolder(Class)}
0722: */
0723: public FilterHolder newFilterHolder() {
0724: return new FilterHolder();
0725: }
0726:
0727: /* ------------------------------------------------------------ */
0728: public FilterHolder getFilter(String name) {
0729: return (FilterHolder) _filterNameMap.get(name);
0730: }
0731:
0732: /* ------------------------------------------------------------ */
0733: /** conveniance method to add a filter.
0734: * @param name
0735: * @param className
0736: * @param pathSpec
0737: * @param dispatches see {@link FilterMapping#setDispatches(int)}
0738: * @return The filter holder.
0739: */
0740: public FilterHolder addFilterWithMapping(Class filter,
0741: String pathSpec, int dispatches) {
0742: FilterHolder holder = newFilterHolder(filter);
0743: addFilterWithMapping(holder, pathSpec, dispatches);
0744:
0745: return holder;
0746: }
0747:
0748: /* ------------------------------------------------------------ */
0749: /** conveniance method to add a filter.
0750: * @param name
0751: * @param className
0752: * @param pathSpec
0753: * @param dispatches see {@link FilterMapping#setDispatches(int)}
0754: * @return The filter holder.
0755: */
0756: public FilterHolder addFilterWithMapping(String className,
0757: String pathSpec, int dispatches) {
0758: FilterHolder holder = newFilterHolder(null);
0759: holder.setName(className);
0760: holder.setClassName(className);
0761:
0762: addFilterWithMapping(holder, pathSpec, dispatches);
0763: return holder;
0764: }
0765:
0766: /* ------------------------------------------------------------ */
0767: /** conveniance method to add a filter.
0768: * @param name
0769: * @param className
0770: * @param pathSpec
0771: * @param dispatches see {@link FilterMapping#setDispatches(int)}
0772: * @return The filter holder.
0773: */
0774: public void addFilterWithMapping(FilterHolder holder,
0775: String pathSpec, int dispatches) {
0776: FilterHolder[] holders = getFilters();
0777: if (holders != null)
0778: holders = (FilterHolder[]) holders.clone();
0779:
0780: try {
0781: setFilters((FilterHolder[]) LazyList.addToArray(holders,
0782: holder, FilterHolder.class));
0783:
0784: FilterMapping mapping = new FilterMapping();
0785: mapping.setFilterName(holder.getName());
0786: mapping.setPathSpec(pathSpec);
0787: mapping.setDispatches(dispatches);
0788: setFilterMappings((FilterMapping[]) LazyList.addToArray(
0789: getFilterMappings(), mapping, FilterMapping.class));
0790: } catch (RuntimeException e) {
0791: setFilters(holders);
0792: throw e;
0793: } catch (Error e) {
0794: setFilters(holders);
0795: throw e;
0796: }
0797:
0798: }
0799:
0800: /* ------------------------------------------------------------ */
0801: /** Convenience method to add a filter with a mapping
0802: * @param className
0803: * @param pathSpec
0804: * @param dispatches
0805: * @return
0806: * @deprecated
0807: */
0808: public FilterHolder addFilter(String className, String pathSpec,
0809: int dispatches) {
0810: return addFilterWithMapping(className, pathSpec, dispatches);
0811: }
0812:
0813: /* ------------------------------------------------------------ */
0814: /**
0815: * convenience method to add a filter and mapping
0816: * @param filter
0817: * @param filterMapping
0818: */
0819: public void addFilter(FilterHolder filter,
0820: FilterMapping filterMapping) {
0821: if (filter != null)
0822: setFilters((FilterHolder[]) LazyList.addToArray(
0823: getFilters(), filter, FilterHolder.class));
0824: if (filterMapping != null)
0825: setFilterMappings((FilterMapping[]) LazyList.addToArray(
0826: getFilterMappings(), filterMapping,
0827: FilterMapping.class));
0828: }
0829:
0830: /* ------------------------------------------------------------ */
0831: /** Convenience method to add a preconstructed FilterHolder
0832: * @param filter
0833: */
0834: public void addFilter(FilterHolder filter) {
0835: if (filter != null)
0836: setFilters((FilterHolder[]) LazyList.addToArray(
0837: getFilters(), filter, FilterHolder.class));
0838: }
0839:
0840: /* ------------------------------------------------------------ */
0841: /** Convenience method to add a preconstructed FilterMapping
0842: * @param mapping
0843: */
0844: public void addFilterMapping(FilterMapping mapping) {
0845: if (mapping != null)
0846: setFilterMappings((FilterMapping[]) LazyList.addToArray(
0847: getFilterMappings(), mapping, FilterMapping.class));
0848: }
0849:
0850: /* ------------------------------------------------------------ */
0851: protected synchronized void updateNameMappings() {
0852: // update filter name map
0853: _filterNameMap.clear();
0854: if (_filters != null) {
0855: for (int i = 0; i < _filters.length; i++) {
0856: _filterNameMap.put(_filters[i].getName(), _filters[i]);
0857: _filters[i].setServletHandler(this );
0858: }
0859: }
0860:
0861: // Map servlet names to holders
0862: _servletNameMap.clear();
0863: if (_servlets != null) {
0864: // update the maps
0865: for (int i = 0; i < _servlets.length; i++) {
0866: _servletNameMap.put(_servlets[i].getName(),
0867: _servlets[i]);
0868: _servlets[i].setServletHandler(this );
0869: }
0870: }
0871: }
0872:
0873: /* ------------------------------------------------------------ */
0874: protected synchronized void updateMappings() {
0875: // update filter mappings
0876: if (_filterMappings == null) {
0877: _filterPathMappings = null;
0878: _filterNameMappings = null;
0879: } else {
0880: _filterPathMappings = new ArrayList();
0881: _filterNameMappings = new MultiMap();
0882: for (int i = 0; i < _filterMappings.length; i++) {
0883: FilterHolder filter_holder = (FilterHolder) _filterNameMap
0884: .get(_filterMappings[i].getFilterName());
0885: if (filter_holder == null)
0886: throw new IllegalStateException("No filter named "
0887: + _filterMappings[i].getFilterName());
0888: _filterMappings[i].setFilterHolder(filter_holder);
0889: if (_filterMappings[i].getPathSpecs() != null)
0890: _filterPathMappings.add(_filterMappings[i]);
0891:
0892: if (_filterMappings[i].getServletNames() != null) {
0893: String[] names = _filterMappings[i]
0894: .getServletNames();
0895: for (int j = 0; j < names.length; j++) {
0896: if (names[j] != null)
0897: _filterNameMappings.add(names[j],
0898: _filterMappings[i]);
0899: }
0900: }
0901: }
0902: }
0903:
0904: // Map servlet paths to holders
0905: if (_servletMappings == null || _servletNameMap == null) {
0906: _servletPathMap = null;
0907: } else {
0908: PathMap pm = new PathMap();
0909:
0910: // update the maps
0911: for (int i = 0; i < _servletMappings.length; i++) {
0912: ServletHolder servlet_holder = (ServletHolder) _servletNameMap
0913: .get(_servletMappings[i].getServletName());
0914: if (servlet_holder == null)
0915: throw new IllegalStateException("No such servlet: "
0916: + _servletMappings[i].getServletName());
0917: else if (_servletMappings[i].getPathSpecs() != null) {
0918: String[] pathSpecs = _servletMappings[i]
0919: .getPathSpecs();
0920: for (int j = 0; j < pathSpecs.length; j++)
0921: if (pathSpecs[j] != null)
0922: pm.put(pathSpecs[j], servlet_holder);
0923: }
0924: }
0925:
0926: _servletPathMap = pm;
0927: }
0928:
0929: if (Log.isDebugEnabled()) {
0930: Log.debug("filterNameMap=" + _filterNameMap);
0931: Log.debug("pathFilters=" + _filterPathMappings);
0932: Log.debug("servletFilterMap=" + _filterNameMappings);
0933: Log.debug("servletPathMap=" + _servletPathMap);
0934: Log.debug("servletNameMap=" + _servletNameMap);
0935: }
0936:
0937: try {
0938: if (isStarted())
0939: initialize();
0940: } catch (Exception e) {
0941: throw new RuntimeException(e);
0942: }
0943: }
0944:
0945: /* ------------------------------------------------------------ */
0946: protected void notFound(HttpServletRequest request,
0947: HttpServletResponse response) throws IOException {
0948: if (Log.isDebugEnabled())
0949: Log.debug("Not Found " + request.getRequestURI());
0950: response.sendError(HttpServletResponse.SC_NOT_FOUND);
0951: }
0952:
0953: /* ------------------------------------------------------------ */
0954: /**
0955: * @param filterChainsCached The filterChainsCached to set.
0956: */
0957: public void setFilterChainsCached(boolean filterChainsCached) {
0958: _filterChainsCached = filterChainsCached;
0959: }
0960:
0961: /* ------------------------------------------------------------ */
0962: /**
0963: * @param filterMappings The filterMappings to set.
0964: */
0965: public void setFilterMappings(FilterMapping[] filterMappings) {
0966: if (getServer() != null)
0967: getServer().getContainer().update(this , _filterMappings,
0968: filterMappings, "filterMapping", true);
0969: _filterMappings = filterMappings;
0970: updateMappings();
0971: }
0972:
0973: /* ------------------------------------------------------------ */
0974: public synchronized void setFilters(FilterHolder[] holders) {
0975: if (getServer() != null)
0976: getServer().getContainer().update(this , _filters, holders,
0977: "filter", true);
0978: _filters = holders;
0979: updateNameMappings();
0980: }
0981:
0982: /* ------------------------------------------------------------ */
0983: /**
0984: * @param servletMappings The servletMappings to set.
0985: */
0986: public void setServletMappings(ServletMapping[] servletMappings) {
0987: if (getServer() != null)
0988: getServer().getContainer().update(this , _servletMappings,
0989: servletMappings, "servletMapping", true);
0990: _servletMappings = servletMappings;
0991: updateMappings();
0992: }
0993:
0994: /* ------------------------------------------------------------ */
0995: /** Set Servlets.
0996: * @param holders Array of servletsto define
0997: */
0998: public synchronized void setServlets(ServletHolder[] holders) {
0999: if (getServer() != null)
1000: getServer().getContainer().update(this , _servlets, holders,
1001: "servlet", true);
1002: _servlets = holders;
1003: updateNameMappings();
1004: }
1005:
1006: /* ------------------------------------------------------------ */
1007: /* ------------------------------------------------------------ */
1008: private class CachedChain implements FilterChain {
1009: FilterHolder _filterHolder;
1010: CachedChain _next;
1011: ServletHolder _servletHolder;
1012:
1013: /* ------------------------------------------------------------ */
1014: CachedChain(Object filters, ServletHolder servletHolder) {
1015: if (LazyList.size(filters) > 0) {
1016: _filterHolder = (FilterHolder) LazyList.get(filters, 0);
1017: filters = LazyList.remove(filters, 0);
1018: _next = new CachedChain(filters, servletHolder);
1019: } else
1020: _servletHolder = servletHolder;
1021: }
1022:
1023: /* ------------------------------------------------------------ */
1024: public void doFilter(ServletRequest request,
1025: ServletResponse response) throws IOException,
1026: ServletException {
1027: // pass to next filter
1028: if (_filterHolder != null) {
1029: if (Log.isDebugEnabled())
1030: Log.debug("call filter " + _filterHolder);
1031: Filter filter = _filterHolder.getFilter();
1032: filter.doFilter(request, response, _next);
1033: return;
1034: }
1035:
1036: // Call servlet
1037: if (_servletHolder != null) {
1038: if (Log.isDebugEnabled())
1039: Log.debug("call servlet " + _servletHolder);
1040: _servletHolder.handle(request, response);
1041: } else
1042: // Not found
1043: notFound((HttpServletRequest) request,
1044: (HttpServletResponse) response);
1045: }
1046:
1047: public String toString() {
1048: if (_filterHolder != null)
1049: return _filterHolder + "->" + _next.toString();
1050: if (_servletHolder != null)
1051: return _servletHolder.toString();
1052: return "null";
1053: }
1054: }
1055:
1056: /* ------------------------------------------------------------ */
1057: /* ------------------------------------------------------------ */
1058: private class Chain implements FilterChain {
1059: int _filter = 0;
1060: Object _chain;
1061: ServletHolder _servletHolder;
1062:
1063: /* ------------------------------------------------------------ */
1064: Chain(Object filters, ServletHolder servletHolder) {
1065: _chain = filters;
1066: _servletHolder = servletHolder;
1067: }
1068:
1069: /* ------------------------------------------------------------ */
1070: public void doFilter(ServletRequest request,
1071: ServletResponse response) throws IOException,
1072: ServletException {
1073: if (Log.isDebugEnabled())
1074: Log.debug("doFilter " + _filter);
1075:
1076: // pass to next filter
1077: if (_filter < LazyList.size(_chain)) {
1078: FilterHolder holder = (FilterHolder) LazyList.get(
1079: _chain, _filter++);
1080: if (Log.isDebugEnabled())
1081: Log.debug("call filter " + holder);
1082: Filter filter = holder.getFilter();
1083: filter.doFilter(request, response, this );
1084: return;
1085: }
1086:
1087: // Call servlet
1088: if (_servletHolder != null) {
1089: if (Log.isDebugEnabled())
1090: Log.debug("call servlet " + _servletHolder);
1091: _servletHolder.handle(request, response);
1092: } else
1093: // Not found
1094: notFound((HttpServletRequest) request,
1095: (HttpServletResponse) response);
1096: }
1097:
1098: /* ------------------------------------------------------------ */
1099: public String toString() {
1100: StringBuffer b = new StringBuffer();
1101: for (int i = 0; i < LazyList.size(_chain); i++) {
1102: b.append(LazyList.get(_chain, i).toString());
1103: b.append("->");
1104: }
1105: b.append(_servletHolder);
1106: return b.toString();
1107: }
1108: }
1109:
1110: /* ------------------------------------------------------------ */
1111: /**
1112: * @return The maximum entries in a filter chain cache.
1113: */
1114: public int getMaxFilterChainsCacheSize() {
1115: return _maxFilterChainsCacheSize;
1116: }
1117:
1118: /* ------------------------------------------------------------ */
1119: /** Set the maximum filter chain cache size.
1120: * Filter chains are cached if {@link #isFilterChainsCached()} is true. If the max cache size
1121: * is greater than zero, then the cache is flushed whenever it grows to be this size.
1122: *
1123: * @param maxFilterChainsCacheSize the maximum number of entries in a filter chain cache.
1124: */
1125: public void setMaxFilterChainsCacheSize(int maxFilterChainsCacheSize) {
1126: _maxFilterChainsCacheSize = maxFilterChainsCacheSize;
1127: }
1128:
1129: /**
1130: * Customize a servlet.
1131: *
1132: * Called before the servlet goes into service.
1133: * Subclasses of ServletHandler should override
1134: * this method.
1135: *
1136: * @param servlet
1137: * @return
1138: * @throws Exception
1139: */
1140: public Servlet customizeServlet(Servlet servlet) throws Exception {
1141: return servlet;
1142: }
1143:
1144: public Servlet customizeServletDestroy(Servlet servlet)
1145: throws Exception {
1146: return servlet;
1147: }
1148:
1149: /**
1150: * Customize a Filter.
1151: *
1152: * Called before the Filter goes into service.
1153: * Subclasses of ServletHandler should override
1154: * this method.
1155: *
1156: * @param filter
1157: * @return
1158: * @throws Exception
1159: */
1160: public Filter customizeFilter(Filter filter) throws Exception {
1161: return filter;
1162: }
1163:
1164: public Filter customizeFilterDestroy(Filter filter)
1165: throws Exception {
1166: return filter;
1167: }
1168: }
|