0001: /*
0002: * Copyright 1999,2004 The Apache Software Foundation.
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: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.catalina.core;
0018:
0019: import java.io.IOException;
0020: import java.io.PrintWriter;
0021: import java.security.AccessController;
0022: import java.security.PrivilegedActionException;
0023: import java.security.PrivilegedExceptionAction;
0024:
0025: import javax.servlet.RequestDispatcher;
0026: import javax.servlet.Servlet;
0027: import javax.servlet.ServletException;
0028: import javax.servlet.ServletOutputStream;
0029: import javax.servlet.ServletRequest;
0030: import javax.servlet.ServletRequestWrapper;
0031: import javax.servlet.ServletResponse;
0032: import javax.servlet.ServletResponseWrapper;
0033: import javax.servlet.UnavailableException;
0034: import javax.servlet.http.HttpServletRequest;
0035: import javax.servlet.http.HttpServletResponse;
0036:
0037: import org.apache.catalina.Context;
0038: import org.apache.catalina.Globals;
0039: import org.apache.catalina.HttpRequest;
0040: import org.apache.catalina.HttpResponse;
0041: import org.apache.catalina.InstanceEvent;
0042: import org.apache.catalina.Logger;
0043: import org.apache.catalina.Request;
0044: import org.apache.catalina.Response;
0045: import org.apache.catalina.Wrapper;
0046: import org.apache.catalina.connector.ClientAbortException;
0047: import org.apache.catalina.connector.RequestFacade;
0048: import org.apache.catalina.connector.ResponseFacade;
0049: import org.apache.catalina.util.InstanceSupport;
0050: import org.apache.catalina.util.StringManager;
0051: import org.apache.commons.beanutils.PropertyUtils;
0052: import org.apache.commons.logging.Log;
0053: import org.apache.commons.logging.LogFactory;
0054:
0055: /**
0056: * Standard implementation of <code>RequestDispatcher</code> that allows a
0057: * request to be forwarded to a different resource to create the ultimate
0058: * response, or to include the output of another resource in the response
0059: * from this resource. This implementation allows application level servlets
0060: * to wrap the request and/or response objects that are passed on to the
0061: * called resource, as long as the wrapping classes extend
0062: * <code>javax.servlet.ServletRequestWrapper</code> and
0063: * <code>javax.servlet.ServletResponseWrapper</code>.
0064: *
0065: * @author Craig R. McClanahan
0066: * @version $Revision: 1.34 $ $Date: 2004/06/07 17:32:15 $
0067: */
0068:
0069: final class ApplicationDispatcher implements RequestDispatcher {
0070:
0071: protected class PrivilegedForward implements
0072: PrivilegedExceptionAction {
0073: private ServletRequest request;
0074: private ServletResponse response;
0075:
0076: PrivilegedForward(ServletRequest request,
0077: ServletResponse response) {
0078: this .request = request;
0079: this .response = response;
0080: }
0081:
0082: public Object run() throws java.lang.Exception {
0083: doForward(request, response);
0084: return null;
0085: }
0086: }
0087:
0088: protected class PrivilegedInclude implements
0089: PrivilegedExceptionAction {
0090: private ServletRequest request;
0091: private ServletResponse response;
0092:
0093: PrivilegedInclude(ServletRequest request,
0094: ServletResponse response) {
0095: this .request = request;
0096: this .response = response;
0097: }
0098:
0099: public Object run() throws ServletException, IOException {
0100: doInclude(request, response);
0101: return null;
0102: }
0103: }
0104:
0105: // ----------------------------------------------------------- Constructors
0106:
0107: /**
0108: * Construct a new instance of this class, configured according to the
0109: * specified parameters. If both servletPath and pathInfo are
0110: * <code>null</code>, it will be assumed that this RequestDispatcher
0111: * was acquired by name, rather than by path.
0112: *
0113: * @param wrapper The Wrapper associated with the resource that will
0114: * be forwarded to or included (required)
0115: * @param requestURI The request URI to this resource (if any)
0116: * @param servletPath The revised servlet path to this resource (if any)
0117: * @param pathInfo The revised extra path information to this resource
0118: * (if any)
0119: * @param queryString Query string parameters included with this request
0120: * (if any)
0121: * @param name Servlet name (if a named dispatcher was created)
0122: * else <code>null</code>
0123: */
0124: public ApplicationDispatcher(Wrapper wrapper, String requestURI,
0125: String servletPath, String pathInfo, String queryString,
0126: String name) {
0127:
0128: super ();
0129:
0130: // Save all of our configuration parameters
0131: this .wrapper = wrapper;
0132: this .context = (Context) wrapper.getParent();
0133: this .requestURI = requestURI;
0134: this .servletPath = servletPath;
0135: this .origServletPath = servletPath;
0136: this .pathInfo = pathInfo;
0137: this .queryString = queryString;
0138: this .name = name;
0139: if (wrapper instanceof StandardWrapper)
0140: this .support = ((StandardWrapper) wrapper)
0141: .getInstanceSupport();
0142: else
0143: this .support = new InstanceSupport(wrapper);
0144:
0145: if (log.isDebugEnabled())
0146: log.debug("servletPath=" + this .servletPath + ", pathInfo="
0147: + this .pathInfo + ", queryString=" + queryString
0148: + ", name=" + this .name);
0149:
0150: }
0151:
0152: // ----------------------------------------------------- Instance Variables
0153:
0154: private static Log log = LogFactory
0155: .getLog(ApplicationDispatcher.class);
0156:
0157: /**
0158: * The request specified by the dispatching application.
0159: */
0160: private ServletRequest appRequest = null;
0161:
0162: /**
0163: * The response specified by the dispatching application.
0164: */
0165: private ServletResponse appResponse = null;
0166:
0167: /**
0168: * The Context this RequestDispatcher is associated with.
0169: */
0170: private Context context = null;
0171:
0172: /**
0173: * The debugging detail level for this component.
0174: */
0175: private int debug = 0;
0176:
0177: /**
0178: * Are we performing an include() instead of a forward()?
0179: */
0180: private boolean including = false;
0181:
0182: /**
0183: * Descriptive information about this implementation.
0184: */
0185: private static final String info = "org.apache.catalina.core.ApplicationDispatcher/1.0";
0186:
0187: /**
0188: * The servlet name for a named dispatcher.
0189: */
0190: private String name = null;
0191:
0192: /**
0193: * The outermost request that will be passed on to the invoked servlet.
0194: */
0195: private ServletRequest outerRequest = null;
0196:
0197: /**
0198: * The outermost response that will be passed on to the invoked servlet.
0199: */
0200: private ServletResponse outerResponse = null;
0201:
0202: /**
0203: * The extra path information for this RequestDispatcher.
0204: */
0205: private String pathInfo = null;
0206:
0207: /**
0208: * The query string parameters for this RequestDispatcher.
0209: */
0210: private String queryString = null;
0211:
0212: /**
0213: * The request URI for this RequestDispatcher.
0214: */
0215: private String requestURI = null;
0216:
0217: /**
0218: * The servlet path for this RequestDispatcher.
0219: */
0220: private String servletPath = null;
0221:
0222: private String origServletPath = null;
0223:
0224: /**
0225: * The StringManager for this package.
0226: */
0227: private static final StringManager sm = StringManager
0228: .getManager(Constants.Package);
0229:
0230: /**
0231: * The InstanceSupport instance associated with our Wrapper (used to
0232: * send "before dispatch" and "after dispatch" events.
0233: */
0234: private InstanceSupport support = null;
0235:
0236: /**
0237: * The Wrapper associated with the resource that will be forwarded to
0238: * or included.
0239: */
0240: private Wrapper wrapper = null;
0241:
0242: /**
0243: * The request wrapper we have created and installed (if any).
0244: */
0245: private ServletRequest wrapRequest = null;
0246:
0247: /**
0248: * The response wrapper we have created and installed (if any).
0249: */
0250: private ServletResponse wrapResponse = null;
0251:
0252: // ------------------------------------------------------------- Properties
0253:
0254: /**
0255: * Return the descriptive information about this implementation.
0256: */
0257: public String getInfo() {
0258:
0259: return (info);
0260:
0261: }
0262:
0263: // --------------------------------------------------------- Public Methods
0264:
0265: /**
0266: * Forward this request and response to another resource for processing.
0267: * Any runtime exception, IOException, or ServletException thrown by the
0268: * called servlet will be propogated to the caller.
0269: *
0270: * @param request The servlet request to be forwarded
0271: * @param response The servlet response to be forwarded
0272: *
0273: * @exception IOException if an input/output error occurs
0274: * @exception ServletException if a servlet exception occurs
0275: */
0276: public void forward(ServletRequest request, ServletResponse response)
0277: throws ServletException, IOException {
0278: if (System.getSecurityManager() != null) {
0279: try {
0280: PrivilegedForward dp = new PrivilegedForward(request,
0281: response);
0282: AccessController.doPrivileged(dp);
0283: } catch (PrivilegedActionException pe) {
0284: Exception e = pe.getException();
0285: if (e instanceof ServletException)
0286: throw (ServletException) e;
0287: throw (IOException) e;
0288: }
0289: } else {
0290: doForward(request, response);
0291: }
0292: }
0293:
0294: private void doForward(ServletRequest request,
0295: ServletResponse response) throws ServletException,
0296: IOException {
0297:
0298: // Reset any output that has been buffered, but keep headers/cookies
0299: if (response.isCommitted()) {
0300: if (log.isDebugEnabled())
0301: log.debug(" Forward on committed response --> ISE");
0302: throw new IllegalStateException(sm
0303: .getString("applicationDispatcher.forward.ise"));
0304: }
0305: try {
0306: response.resetBuffer();
0307: } catch (IllegalStateException e) {
0308: if (log.isDebugEnabled())
0309: log.debug(" Forward resetBuffer() returned ISE: " + e);
0310: throw e;
0311: }
0312:
0313: // Set up to handle the specified request and response
0314: setup(request, response, false);
0315:
0316: // Identify the HTTP-specific request and response objects (if any)
0317: HttpServletRequest hrequest = null;
0318: if (request instanceof HttpServletRequest)
0319: hrequest = (HttpServletRequest) request;
0320: HttpServletResponse hresponse = null;
0321: if (response instanceof HttpServletResponse)
0322: hresponse = (HttpServletResponse) response;
0323:
0324: // Handle a non-HTTP forward by passing the existing request/response
0325: if ((hrequest == null) || (hresponse == null)) {
0326:
0327: if (log.isDebugEnabled())
0328: log.debug(" Non-HTTP Forward");
0329:
0330: processRequest(hrequest, hresponse);
0331:
0332: }
0333:
0334: // Handle an HTTP named dispatcher forward
0335: else if ((servletPath == null) && (pathInfo == null)) {
0336:
0337: if (log.isDebugEnabled())
0338: log.debug(" Named Dispatcher Forward");
0339:
0340: ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest();
0341: wrequest.setRequestURI(hrequest.getRequestURI());
0342: wrequest.setContextPath(hrequest.getContextPath());
0343: wrequest.setServletPath(hrequest.getServletPath());
0344: wrequest.setPathInfo(hrequest.getPathInfo());
0345: wrequest.setQueryString(hrequest.getQueryString());
0346:
0347: processRequest(request, response);
0348:
0349: wrequest.recycle();
0350: unwrapRequest();
0351:
0352: }
0353:
0354: // Handle an HTTP path-based forward
0355: else {
0356:
0357: if (log.isDebugEnabled())
0358: log.debug(" Path Based Forward");
0359:
0360: ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest();
0361: String contextPath = context.getPath();
0362: wrequest.setContextPath(contextPath);
0363: wrequest.setRequestURI(requestURI);
0364: wrequest.setServletPath(servletPath);
0365: wrequest.setPathInfo(pathInfo);
0366:
0367: if (hrequest.getAttribute(Globals.FORWARD_REQUEST_URI_ATTR) == null) {
0368: wrequest.setAttribute(Globals.FORWARD_REQUEST_URI_ATTR,
0369: hrequest.getRequestURI());
0370: wrequest.setAttribute(
0371: Globals.FORWARD_CONTEXT_PATH_ATTR, hrequest
0372: .getContextPath());
0373: wrequest.setAttribute(
0374: Globals.FORWARD_SERVLET_PATH_ATTR, hrequest
0375: .getServletPath());
0376: wrequest.setAttribute(Globals.FORWARD_PATH_INFO_ATTR,
0377: hrequest.getPathInfo());
0378: wrequest.setAttribute(
0379: Globals.FORWARD_QUERY_STRING_ATTR, hrequest
0380: .getQueryString());
0381: }
0382:
0383: if (queryString != null) {
0384: wrequest.setQueryString(queryString);
0385: wrequest.setQueryParams(queryString);
0386: }
0387:
0388: processRequest(request, response);
0389:
0390: wrequest.recycle();
0391: unwrapRequest();
0392:
0393: }
0394:
0395: // This is not a real close in order to support error processing
0396: if (log.isDebugEnabled())
0397: log.debug(" Disabling the response for futher output");
0398:
0399: if (response instanceof ResponseFacade) {
0400: ((ResponseFacade) response).finish();
0401: } else {
0402: // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
0403: // and may no longer be instance of RequestFacade
0404: if (log.isDebugEnabled()) {
0405: log
0406: .debug(" The Response is vehiculed using a wrapper: "
0407: + response.getClass().getName());
0408: }
0409:
0410: // Close anyway
0411: try {
0412: PrintWriter writer = response.getWriter();
0413: writer.close();
0414: } catch (IllegalStateException e) {
0415: try {
0416: ServletOutputStream stream = response
0417: .getOutputStream();
0418: stream.close();
0419: } catch (IllegalStateException f) {
0420: ;
0421: } catch (IOException f) {
0422: ;
0423: }
0424: } catch (IOException e) {
0425: ;
0426: }
0427: }
0428:
0429: }
0430:
0431: /**
0432: * Prepare the request based on the filter configuration.
0433: * @param request The servlet request we are processing
0434: * @param response The servlet response we are creating
0435: *
0436: * @exception IOException if an input/output error occurs
0437: * @exception ServletException if a servlet error occurs
0438: */
0439: private void processRequest(ServletRequest request,
0440: ServletResponse response) throws IOException,
0441: ServletException {
0442:
0443: Integer disInt = (Integer) request
0444: .getAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR);
0445: if (disInt != null) {
0446: if (disInt.intValue() != ApplicationFilterFactory.ERROR) {
0447: outerRequest
0448: .setAttribute(
0449: ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
0450: origServletPath);
0451: outerRequest.setAttribute(
0452: ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
0453: new Integer(ApplicationFilterFactory.FORWARD));
0454: invoke(outerRequest, response);
0455: } else {
0456: invoke(outerRequest, response);
0457: }
0458: }
0459:
0460: }
0461:
0462: /**
0463: * Include the response from another resource in the current response.
0464: * Any runtime exception, IOException, or ServletException thrown by the
0465: * called servlet will be propogated to the caller.
0466: *
0467: * @param request The servlet request that is including this one
0468: * @param response The servlet response to be appended to
0469: *
0470: * @exception IOException if an input/output error occurs
0471: * @exception ServletException if a servlet exception occurs
0472: */
0473: public void include(ServletRequest request, ServletResponse response)
0474: throws ServletException, IOException {
0475: if (System.getSecurityManager() != null) {
0476: try {
0477: PrivilegedInclude dp = new PrivilegedInclude(request,
0478: response);
0479: AccessController.doPrivileged(dp);
0480: } catch (PrivilegedActionException pe) {
0481: Exception e = pe.getException();
0482:
0483: if (e instanceof ServletException)
0484: throw (ServletException) e;
0485: throw (IOException) e;
0486: }
0487: } else {
0488: doInclude(request, response);
0489: }
0490: }
0491:
0492: private void doInclude(ServletRequest request,
0493: ServletResponse response) throws ServletException,
0494: IOException {
0495: // Set up to handle the specified request and response
0496: setup(request, response, true);
0497:
0498: // Create a wrapped response to use for this request
0499: // ServletResponse wresponse = null;
0500: ServletResponse wresponse = wrapResponse();
0501:
0502: // Handle a non-HTTP include
0503: if (!(request instanceof HttpServletRequest)
0504: || !(response instanceof HttpServletResponse)) {
0505:
0506: if (log.isDebugEnabled())
0507: log.debug(" Non-HTTP Include");
0508: request.setAttribute(
0509: ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
0510: new Integer(ApplicationFilterFactory.INCLUDE));
0511: request
0512: .setAttribute(
0513: ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
0514: origServletPath);
0515: invoke(request, outerResponse);
0516: unwrapResponse();
0517:
0518: }
0519:
0520: // Handle an HTTP named dispatcher include
0521: else if (name != null) {
0522:
0523: if (log.isDebugEnabled())
0524: log.debug(" Named Dispatcher Include");
0525:
0526: ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest();
0527: wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name);
0528: if (servletPath != null)
0529: wrequest.setServletPath(servletPath);
0530: wrequest.setAttribute(
0531: ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
0532: new Integer(ApplicationFilterFactory.INCLUDE));
0533: wrequest
0534: .setAttribute(
0535: ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
0536: origServletPath);
0537: invoke(outerRequest, outerResponse);
0538:
0539: wrequest.recycle();
0540: unwrapRequest();
0541: unwrapResponse();
0542:
0543: }
0544:
0545: // Handle an HTTP path based include
0546: else {
0547:
0548: if (log.isDebugEnabled())
0549: log.debug(" Path Based Include");
0550:
0551: ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest();
0552: String contextPath = context.getPath();
0553: if (requestURI != null)
0554: wrequest.setAttribute(Globals.INCLUDE_REQUEST_URI_ATTR,
0555: requestURI);
0556: if (contextPath != null)
0557: wrequest.setAttribute(
0558: Globals.INCLUDE_CONTEXT_PATH_ATTR, contextPath);
0559: if (servletPath != null)
0560: wrequest.setAttribute(
0561: Globals.INCLUDE_SERVLET_PATH_ATTR, servletPath);
0562: if (pathInfo != null)
0563: wrequest.setAttribute(Globals.INCLUDE_PATH_INFO_ATTR,
0564: pathInfo);
0565: if (queryString != null) {
0566: wrequest.setAttribute(
0567: Globals.INCLUDE_QUERY_STRING_ATTR, queryString);
0568: wrequest.setQueryParams(queryString);
0569: }
0570:
0571: wrequest.setAttribute(
0572: ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
0573: new Integer(ApplicationFilterFactory.INCLUDE));
0574: wrequest
0575: .setAttribute(
0576: ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
0577: origServletPath);
0578: invoke(outerRequest, outerResponse);
0579:
0580: wrequest.recycle();
0581: unwrapRequest();
0582: unwrapResponse();
0583:
0584: }
0585:
0586: }
0587:
0588: // -------------------------------------------------------- Private Methods
0589:
0590: /**
0591: * Ask the resource represented by this RequestDispatcher to process
0592: * the associated request, and create (or append to) the associated
0593: * response.
0594: * <p>
0595: * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
0596: * that no filters are applied to a forwarded or included resource,
0597: * because they were already done for the original request.
0598: *
0599: * @param request The servlet request we are processing
0600: * @param response The servlet response we are creating
0601: *
0602: * @exception IOException if an input/output error occurs
0603: * @exception ServletException if a servlet error occurs
0604: */
0605: private void invoke(ServletRequest request, ServletResponse response)
0606: throws IOException, ServletException {
0607:
0608: // Checking to see if the context classloader is the current context
0609: // classloader. If it's not, we're saving it, and setting the context
0610: // classloader to the Context classloader
0611: ClassLoader oldCCL = Thread.currentThread()
0612: .getContextClassLoader();
0613: ClassLoader contextClassLoader = context.getLoader()
0614: .getClassLoader();
0615:
0616: if (oldCCL != contextClassLoader) {
0617: Thread.currentThread().setContextClassLoader(
0618: contextClassLoader);
0619: } else {
0620: oldCCL = null;
0621: }
0622:
0623: // Initialize local variables we may need
0624: HttpServletRequest hrequest = null;
0625: if (request instanceof HttpServletRequest)
0626: hrequest = (HttpServletRequest) request;
0627: HttpServletResponse hresponse = null;
0628: if (response instanceof HttpServletResponse)
0629: hresponse = (HttpServletResponse) response;
0630: Servlet servlet = null;
0631: IOException ioException = null;
0632: ServletException servletException = null;
0633: RuntimeException runtimeException = null;
0634: boolean unavailable = false;
0635:
0636: // Check for the servlet being marked unavailable
0637: if (wrapper.isUnavailable()) {
0638: log(sm.getString("applicationDispatcher.isUnavailable",
0639: wrapper.getName()));
0640: if (hresponse == null) {
0641: ; // NOTE - Not much we can do generically
0642: } else {
0643: long available = wrapper.getAvailable();
0644: if ((available > 0L) && (available < Long.MAX_VALUE))
0645: hresponse.setDateHeader("Retry-After", available);
0646: hresponse.sendError(
0647: HttpServletResponse.SC_SERVICE_UNAVAILABLE,
0648: sm.getString(
0649: "applicationDispatcher.isUnavailable",
0650: wrapper.getName()));
0651: }
0652: unavailable = true;
0653: }
0654:
0655: // Allocate a servlet instance to process this request
0656: try {
0657: if (!unavailable) {
0658: // if (debug >= 2)
0659: // log(" Allocating servlet instance");
0660: servlet = wrapper.allocate();
0661: // if ((debug >= 2) && (servlet == null))
0662: // log(" No servlet instance returned!");
0663: }
0664: } catch (ServletException e) {
0665: log(sm.getString("applicationDispatcher.allocateException",
0666: wrapper.getName()), e);
0667: servletException = e;
0668: servlet = null;
0669: } catch (Throwable e) {
0670: log(sm.getString("applicationDispatcher.allocateException",
0671: wrapper.getName()), e);
0672: servletException = new ServletException(sm.getString(
0673: "applicationDispatcher.allocateException", wrapper
0674: .getName()), e);
0675: servlet = null;
0676: }
0677:
0678: // Get the FilterChain Here
0679: ApplicationFilterFactory factory = ApplicationFilterFactory
0680: .getInstance();
0681: ApplicationFilterChain filterChain = factory.createFilterChain(
0682: request, wrapper, servlet);
0683: // Call the service() method for the allocated servlet instance
0684: try {
0685: String jspFile = wrapper.getJspFile();
0686: if (jspFile != null)
0687: request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
0688: else
0689: request.removeAttribute(Globals.JSP_FILE_ATTR);
0690: support.fireInstanceEvent(
0691: InstanceEvent.BEFORE_DISPATCH_EVENT, servlet,
0692: request, response);
0693: // for includes/forwards
0694: if ((servlet != null) && (filterChain != null)) {
0695: filterChain.doFilter(request, response);
0696: }
0697: // Servlet Service Method is called by the FilterChain
0698: request.removeAttribute(Globals.JSP_FILE_ATTR);
0699: support.fireInstanceEvent(
0700: InstanceEvent.AFTER_DISPATCH_EVENT, servlet,
0701: request, response);
0702: } catch (ClientAbortException e) {
0703: request.removeAttribute(Globals.JSP_FILE_ATTR);
0704: support.fireInstanceEvent(
0705: InstanceEvent.AFTER_DISPATCH_EVENT, servlet,
0706: request, response);
0707: ioException = e;
0708: } catch (IOException e) {
0709: request.removeAttribute(Globals.JSP_FILE_ATTR);
0710: support.fireInstanceEvent(
0711: InstanceEvent.AFTER_DISPATCH_EVENT, servlet,
0712: request, response);
0713: log(sm.getString("applicationDispatcher.serviceException",
0714: wrapper.getName()), e);
0715: ioException = e;
0716: } catch (UnavailableException e) {
0717: request.removeAttribute(Globals.JSP_FILE_ATTR);
0718: support.fireInstanceEvent(
0719: InstanceEvent.AFTER_DISPATCH_EVENT, servlet,
0720: request, response);
0721: log(sm.getString("applicationDispatcher.serviceException",
0722: wrapper.getName()), e);
0723: servletException = e;
0724: wrapper.unavailable(e);
0725: } catch (ServletException e) {
0726: request.removeAttribute(Globals.JSP_FILE_ATTR);
0727: support.fireInstanceEvent(
0728: InstanceEvent.AFTER_DISPATCH_EVENT, servlet,
0729: request, response);
0730: Throwable rootCause = e;
0731: Throwable rootCauseCheck = null;
0732:
0733: // Extra aggressive rootCause finding
0734: do {
0735: try {
0736: rootCauseCheck = (Throwable) PropertyUtils
0737: .getProperty(rootCause, "rootCause");
0738: if (rootCauseCheck != null)
0739: rootCause = rootCauseCheck;
0740:
0741: } catch (ClassCastException ex) {
0742: rootCauseCheck = null;
0743: } catch (IllegalAccessException ex) {
0744: rootCauseCheck = null;
0745: } catch (NoSuchMethodException ex) {
0746: rootCauseCheck = null;
0747: } catch (java.lang.reflect.InvocationTargetException ex) {
0748: rootCauseCheck = null;
0749: }
0750: } while (rootCauseCheck != null);
0751:
0752: log(sm.getString("applicationDispatcher.serviceException",
0753: wrapper.getName()), rootCause);
0754: servletException = e;
0755: } catch (RuntimeException e) {
0756: request.removeAttribute(Globals.JSP_FILE_ATTR);
0757: support.fireInstanceEvent(
0758: InstanceEvent.AFTER_DISPATCH_EVENT, servlet,
0759: request, response);
0760: log(sm.getString("applicationDispatcher.serviceException",
0761: wrapper.getName()), e);
0762: runtimeException = e;
0763: }
0764:
0765: // Release the filter chain (if any) for this request
0766: try {
0767: if (filterChain != null)
0768: filterChain.release();
0769: } catch (Throwable e) {
0770: log.error(sm.getString("standardWrapper.releaseFilters",
0771: wrapper.getName()), e);
0772: //FIXME Exception handling needs to be simpiler to what is in the StandardWrapperValue
0773: }
0774:
0775: // Deallocate the allocated servlet instance
0776: try {
0777: if (servlet != null) {
0778: wrapper.deallocate(servlet);
0779: }
0780: } catch (ServletException e) {
0781: log(sm.getString(
0782: "applicationDispatcher.deallocateException",
0783: wrapper.getName()), e);
0784: servletException = e;
0785: } catch (Throwable e) {
0786: log(sm.getString(
0787: "applicationDispatcher.deallocateException",
0788: wrapper.getName()), e);
0789: servletException = new ServletException(sm.getString(
0790: "applicationDispatcher.deallocateException",
0791: wrapper.getName()), e);
0792: }
0793:
0794: // Reset the old context class loader
0795: if (oldCCL != null)
0796: Thread.currentThread().setContextClassLoader(oldCCL);
0797:
0798: // Rethrow an exception if one was thrown by the invoked servlet
0799: if (ioException != null)
0800: throw ioException;
0801: if (servletException != null)
0802: throw servletException;
0803: if (runtimeException != null)
0804: throw runtimeException;
0805:
0806: }
0807:
0808: /**
0809: * Log a message on the Logger associated with our Context (if any)
0810: *
0811: * @param message Message to be logged
0812: */
0813: private void log(String message) {
0814: Logger logger = context.getLogger();
0815: if (logger != null)
0816: logger.log("ApplicationDispatcher[" + context.getPath()
0817: + "]: " + message);
0818: else
0819: System.out.println("ApplicationDispatcher["
0820: + context.getPath() + "]: " + message);
0821:
0822: }
0823:
0824: /**
0825: * Log a message on the Logger associated with our Container (if any)
0826: *
0827: * @param message Message to be logged
0828: * @param throwable Associated exception
0829: */
0830: private void log(String message, Throwable throwable) {
0831: Logger logger = context.getLogger();
0832: if (logger != null)
0833: logger.log("ApplicationDispatcher[" + context.getPath()
0834: + "] " + message, throwable);
0835: else {
0836: System.out.println("ApplicationDispatcher["
0837: + context.getPath() + "]: " + message);
0838: throwable.printStackTrace(System.out);
0839: }
0840:
0841: }
0842:
0843: /**
0844: * Set up to handle the specified request and response
0845: *
0846: * @param request The servlet request specified by the caller
0847: * @param response The servlet response specified by the caller
0848: * @param including Are we performing an include() as opposed to
0849: * a forward()?
0850: */
0851: private void setup(ServletRequest request,
0852: ServletResponse response, boolean including) {
0853:
0854: this .appRequest = request;
0855: this .appResponse = response;
0856: this .outerRequest = request;
0857: this .outerResponse = response;
0858: this .including = including;
0859:
0860: }
0861:
0862: /**
0863: * Unwrap the request if we have wrapped it.
0864: */
0865: private void unwrapRequest() {
0866:
0867: if (wrapRequest == null)
0868: return;
0869:
0870: ServletRequest previous = null;
0871: ServletRequest current = outerRequest;
0872: while (current != null) {
0873:
0874: // If we run into the container request we are done
0875: if ((current instanceof Request)
0876: || (current instanceof RequestFacade))
0877: break;
0878:
0879: // Remove the current request if it is our wrapper
0880: if (current == wrapRequest) {
0881: ServletRequest next = ((ServletRequestWrapper) current)
0882: .getRequest();
0883: if (previous == null)
0884: outerRequest = next;
0885: else
0886: ((ServletRequestWrapper) previous).setRequest(next);
0887: break;
0888: }
0889:
0890: // Advance to the next request in the chain
0891: previous = current;
0892: current = ((ServletRequestWrapper) current).getRequest();
0893:
0894: }
0895:
0896: }
0897:
0898: /**
0899: * Unwrap the response if we have wrapped it.
0900: */
0901: private void unwrapResponse() {
0902:
0903: if (wrapResponse == null)
0904: return;
0905:
0906: ServletResponse previous = null;
0907: ServletResponse current = outerResponse;
0908: while (current != null) {
0909:
0910: // If we run into the container response we are done
0911: if ((current instanceof Response)
0912: || (current instanceof ResponseFacade))
0913: break;
0914:
0915: // Remove the current response if it is our wrapper
0916: if (current == wrapResponse) {
0917: ServletResponse next = ((ServletResponseWrapper) current)
0918: .getResponse();
0919: if (previous == null)
0920: outerResponse = next;
0921: else
0922: ((ServletResponseWrapper) previous)
0923: .setResponse(next);
0924: break;
0925: }
0926:
0927: // Advance to the next response in the chain
0928: previous = current;
0929: current = ((ServletResponseWrapper) current).getResponse();
0930:
0931: }
0932:
0933: }
0934:
0935: /**
0936: * Create and return a request wrapper that has been inserted in the
0937: * appropriate spot in the request chain.
0938: */
0939: private ServletRequest wrapRequest() {
0940:
0941: // Locate the request we should insert in front of
0942: ServletRequest previous = null;
0943: ServletRequest current = outerRequest;
0944: while (current != null) {
0945: if ("org.apache.catalina.servlets.InvokerHttpRequest"
0946: .equals(current.getClass().getName()))
0947: break; // KLUDGE - Make nested RD.forward() using invoker work
0948: if (!(current instanceof ServletRequestWrapper))
0949: break;
0950: if (current instanceof ApplicationHttpRequest)
0951: break;
0952: if (current instanceof ApplicationRequest)
0953: break;
0954: if (current instanceof Request)
0955: break;
0956: previous = current;
0957: current = ((ServletRequestWrapper) current).getRequest();
0958: }
0959:
0960: // Instantiate a new wrapper at this point and insert it in the chain
0961: ServletRequest wrapper = null;
0962: if ((current instanceof ApplicationHttpRequest)
0963: || (current instanceof HttpRequest)
0964: || (current instanceof HttpServletRequest)) {
0965: // Compute a crossContext flag
0966: HttpServletRequest hcurrent = (HttpServletRequest) current;
0967: boolean crossContext = false;
0968: if ((outerRequest instanceof ApplicationHttpRequest)
0969: || (outerRequest instanceof HttpRequest)
0970: || (outerRequest instanceof HttpServletRequest)) {
0971: HttpServletRequest houterRequest = (HttpServletRequest) outerRequest;
0972: Object contextPath = houterRequest
0973: .getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR);
0974: if (contextPath == null) {
0975: // Forward
0976: contextPath = houterRequest.getContextPath();
0977: }
0978: crossContext = !(context.getPath().equals(contextPath));
0979: }
0980: wrapper = new ApplicationHttpRequest(hcurrent, context,
0981: crossContext);
0982: } else {
0983: wrapper = new ApplicationRequest(current);
0984: }
0985: if (previous == null)
0986: outerRequest = wrapper;
0987: else
0988: ((ServletRequestWrapper) previous).setRequest(wrapper);
0989: wrapRequest = wrapper;
0990: return (wrapper);
0991:
0992: }
0993:
0994: /**
0995: * Create and return a response wrapper that has been inserted in the
0996: * appropriate spot in the response chain.
0997: */
0998: private ServletResponse wrapResponse() {
0999:
1000: // Locate the response we should insert in front of
1001: ServletResponse previous = null;
1002: ServletResponse current = outerResponse;
1003: while (current != null) {
1004: if (!(current instanceof ServletResponseWrapper))
1005: break;
1006: if (current instanceof ApplicationHttpResponse)
1007: break;
1008: if (current instanceof ApplicationResponse)
1009: break;
1010: if (current instanceof Response)
1011: break;
1012: previous = current;
1013: current = ((ServletResponseWrapper) current).getResponse();
1014: }
1015:
1016: // Instantiate a new wrapper at this point and insert it in the chain
1017: ServletResponse wrapper = null;
1018: if ((current instanceof ApplicationHttpResponse)
1019: || (current instanceof HttpResponse)
1020: || (current instanceof HttpServletResponse))
1021: wrapper = new ApplicationHttpResponse(
1022: (HttpServletResponse) current, including);
1023: else
1024: wrapper = new ApplicationResponse(current, including);
1025: if (previous == null)
1026: outerResponse = wrapper;
1027: else
1028: ((ServletResponseWrapper) previous).setResponse(wrapper);
1029: wrapResponse = wrapper;
1030: return (wrapper);
1031:
1032: }
1033:
1034: }
|