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