Java tutorial
/* * $Header: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java,v 1.26 2003/09/12 17:04:12 remm Exp $ * $Revision: 1.26 $ * $Date: 2003/09/12 17:04:12 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.catalina.core; import java.io.IOException; import java.io.PrintWriter; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.HttpRequest; import org.apache.catalina.HttpResponse; import org.apache.catalina.InstanceEvent; import org.apache.catalina.Logger; import org.apache.catalina.Request; import org.apache.catalina.Response; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.ClientAbortException; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.connector.ResponseFacade; import org.apache.catalina.util.InstanceSupport; import org.apache.catalina.util.StringManager; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Standard implementation of <code>RequestDispatcher</code> that allows a * request to be forwarded to a different resource to create the ultimate * response, or to include the output of another resource in the response * from this resource. This implementation allows application level servlets * to wrap the request and/or response objects that are passed on to the * called resource, as long as the wrapping classes extend * <code>javax.servlet.ServletRequestWrapper</code> and * <code>javax.servlet.ServletResponseWrapper</code>. * * @author Craig R. McClanahan * @version $Revision: 1.26 $ $Date: 2003/09/12 17:04:12 $ */ final class ApplicationDispatcher implements RequestDispatcher { protected class PrivilegedForward implements PrivilegedExceptionAction { private ServletRequest request; private ServletResponse response; PrivilegedForward(ServletRequest request, ServletResponse response) { this.request = request; this.response = response; } public Object run() throws java.lang.Exception { doForward(request, response); return null; } } protected class PrivilegedInclude implements PrivilegedExceptionAction { private ServletRequest request; private ServletResponse response; PrivilegedInclude(ServletRequest request, ServletResponse response) { this.request = request; this.response = response; } public Object run() throws ServletException, IOException { doInclude(request, response); return null; } } // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class, configured according to the * specified parameters. If both servletPath and pathInfo are * <code>null</code>, it will be assumed that this RequestDispatcher * was acquired by name, rather than by path. * * @param wrapper The Wrapper associated with the resource that will * be forwarded to or included (required) * @param requestURI The request URI to this resource (if any) * @param servletPath The revised servlet path to this resource (if any) * @param pathInfo The revised extra path information to this resource * (if any) * @param queryString Query string parameters included with this request * (if any) * @param name Servlet name (if a named dispatcher was created) * else <code>null</code> */ public ApplicationDispatcher(Wrapper wrapper, String requestURI, String servletPath, String pathInfo, String queryString, String name) { super(); // Save all of our configuration parameters this.wrapper = wrapper; this.context = (Context) wrapper.getParent(); this.requestURI = requestURI; this.servletPath = servletPath; this.origServletPath = servletPath; this.pathInfo = pathInfo; this.queryString = queryString; this.name = name; if (wrapper instanceof StandardWrapper) this.support = ((StandardWrapper) wrapper).getInstanceSupport(); else this.support = new InstanceSupport(wrapper); if (log.isDebugEnabled()) log.debug("servletPath=" + this.servletPath + ", pathInfo=" + this.pathInfo + ", queryString=" + queryString + ", name=" + this.name); } // ----------------------------------------------------- Instance Variables private static Log log = LogFactory.getLog(ApplicationDispatcher.class); /** * The request specified by the dispatching application. */ private ServletRequest appRequest = null; /** * The response specified by the dispatching application. */ private ServletResponse appResponse = null; /** * The Context this RequestDispatcher is associated with. */ private Context context = null; /** * The debugging detail level for this component. */ private int debug = 0; /** * Are we performing an include() instead of a forward()? */ private boolean including = false; /** * Descriptive information about this implementation. */ private static final String info = "org.apache.catalina.core.ApplicationDispatcher/1.0"; /** * The servlet name for a named dispatcher. */ private String name = null; /** * The outermost request that will be passed on to the invoked servlet. */ private ServletRequest outerRequest = null; /** * The outermost response that will be passed on to the invoked servlet. */ private ServletResponse outerResponse = null; /** * The extra path information for this RequestDispatcher. */ private String pathInfo = null; /** * The query string parameters for this RequestDispatcher. */ private String queryString = null; /** * The request URI for this RequestDispatcher. */ private String requestURI = null; /** * The servlet path for this RequestDispatcher. */ private String servletPath = null; private String origServletPath = null; /** * The StringManager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The InstanceSupport instance associated with our Wrapper (used to * send "before dispatch" and "after dispatch" events. */ private InstanceSupport support = null; /** * The Wrapper associated with the resource that will be forwarded to * or included. */ private Wrapper wrapper = null; /** * The request wrapper we have created and installed (if any). */ private ServletRequest wrapRequest = null; /** * The response wrapper we have created and installed (if any). */ private ServletResponse wrapResponse = null; // ------------------------------------------------------------- Properties /** * Return the descriptive information about this implementation. */ public String getInfo() { return (this.info); } // --------------------------------------------------------- Public Methods /** * Forward this request and response to another resource for processing. * Any runtime exception, IOException, or ServletException thrown by the * called servlet will be propogated to the caller. * * @param request The servlet request to be forwarded * @param response The servlet response to be forwarded * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { if (System.getSecurityManager() != null) { try { PrivilegedForward dp = new PrivilegedForward(request, response); AccessController.doPrivileged(dp); } catch (PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; throw (IOException) e; } } else { doForward(request, response); } } private void doForward(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Reset any output that has been buffered, but keep headers/cookies if (response.isCommitted()) { if (log.isDebugEnabled()) log.debug(" Forward on committed response --> ISE"); throw new IllegalStateException(sm.getString("applicationDispatcher.forward.ise")); } try { response.resetBuffer(); } catch (IllegalStateException e) { if (log.isDebugEnabled()) log.debug(" Forward resetBuffer() returned ISE: " + e); throw e; } // Set up to handle the specified request and response setup(request, response, false); // Identify the HTTP-specific request and response objects (if any) HttpServletRequest hrequest = null; if (request instanceof HttpServletRequest) hrequest = (HttpServletRequest) request; HttpServletResponse hresponse = null; if (response instanceof HttpServletResponse) hresponse = (HttpServletResponse) response; // Handle a non-HTTP forward by passing the existing request/response if ((hrequest == null) || (hresponse == null)) { if (log.isDebugEnabled()) log.debug(" Non-HTTP Forward"); processRequest(hrequest, hresponse); } // Handle an HTTP named dispatcher forward else if ((servletPath == null) && (pathInfo == null)) { if (log.isDebugEnabled()) log.debug(" Named Dispatcher Forward"); processRequest(request, response); } // Handle an HTTP path-based forward else { if (log.isDebugEnabled()) log.debug(" Path Based Forward"); ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(); String contextPath = context.getPath(); wrequest.setContextPath(contextPath); wrequest.setRequestURI(requestURI); wrequest.setServletPath(servletPath); wrequest.setPathInfo(pathInfo); wrequest.setAttribute(Globals.FORWARD_REQUEST_URI_ATTR, hrequest.getRequestURI()); wrequest.setAttribute(Globals.FORWARD_CONTEXT_PATH_ATTR, hrequest.getContextPath()); wrequest.setAttribute(Globals.FORWARD_SERVLET_PATH_ATTR, hrequest.getServletPath()); wrequest.setAttribute(Globals.FORWARD_PATH_INFO_ATTR, hrequest.getPathInfo()); wrequest.setAttribute(Globals.FORWARD_QUERY_STRING_ATTR, hrequest.getQueryString()); if (queryString != null) { wrequest.setQueryString(queryString); wrequest.setQueryParams(queryString); } processRequest(request, response); unwrapRequest(); } // This is not a real close in order to support error processing if (log.isDebugEnabled()) log.debug(" Disabling the response for futher output"); if (response instanceof ResponseFacade) { ((ResponseFacade) response).finish(); } else { // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped // and may no longer be instance of RequestFacade if (log.isDebugEnabled()) { log.debug(" The Response is vehiculed using a wrapper: " + response.getClass().getName()); } // Close anyway try { PrintWriter writer = response.getWriter(); writer.close(); } catch (IllegalStateException e) { try { ServletOutputStream stream = response.getOutputStream(); stream.close(); } catch (IllegalStateException f) { ; } catch (IOException f) { ; } } catch (IOException e) { ; } } } /** * Prepare the request based on the filter configuration. * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ private void processRequest(ServletRequest request, ServletResponse response) throws IOException, ServletException { Integer disInt = (Integer) request.getAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR); if (disInt != null) { if (disInt.intValue() != ApplicationFilterFactory.ERROR) { outerRequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); outerRequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, new Integer(ApplicationFilterFactory.FORWARD)); invoke(outerRequest, response); } else { invoke(outerRequest, response); } } } /** * Include the response from another resource in the current response. * Any runtime exception, IOException, or ServletException thrown by the * called servlet will be propogated to the caller. * * @param request The servlet request that is including this one * @param response The servlet response to be appended to * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { if (System.getSecurityManager() != null) { try { PrivilegedInclude dp = new PrivilegedInclude(request, response); AccessController.doPrivileged(dp); } catch (PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; throw (IOException) e; } } else { doInclude(request, response); } } private void doInclude(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Set up to handle the specified request and response setup(request, response, true); // Create a wrapped response to use for this request // ServletResponse wresponse = null; ServletResponse wresponse = wrapResponse(); // Handle a non-HTTP include if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { if (log.isDebugEnabled()) log.debug(" Non-HTTP Include"); request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, new Integer(ApplicationFilterFactory.INCLUDE)); request.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); invoke(request, outerResponse); unwrapResponse(); } // Handle an HTTP named dispatcher include else if (name != null) { if (log.isDebugEnabled()) log.debug(" Named Dispatcher Include"); ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(); wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name); if (servletPath != null) wrequest.setServletPath(servletPath); wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, new Integer(ApplicationFilterFactory.INCLUDE)); wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); invoke(outerRequest, outerResponse); unwrapRequest(); unwrapResponse(); } // Handle an HTTP path based include else { if (log.isDebugEnabled()) log.debug(" Path Based Include"); ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(); String contextPath = context.getPath(); /* StringBuffer sb = new StringBuffer(); if (contextPath != null) sb.append(contextPath); if (servletPath != null) sb.append(servletPath); if (pathInfo != null) sb.append(pathInfo); if (sb.length() > 0) */ if (requestURI != null) wrequest.setAttribute(Globals.INCLUDE_REQUEST_URI_ATTR, requestURI); if (contextPath != null) wrequest.setAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR, contextPath); if (servletPath != null) wrequest.setAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR, servletPath); if (pathInfo != null) wrequest.setAttribute(Globals.INCLUDE_PATH_INFO_ATTR, pathInfo); if (queryString != null) { wrequest.setAttribute(Globals.INCLUDE_QUERY_STRING_ATTR, queryString); wrequest.setQueryParams(queryString); } wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, new Integer(ApplicationFilterFactory.INCLUDE)); wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); invoke(outerRequest, outerResponse); unwrapRequest(); unwrapResponse(); } } // -------------------------------------------------------- Private Methods /** * Ask the resource represented by this RequestDispatcher to process * the associated request, and create (or append to) the associated * response. * <p> * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes * that no filters are applied to a forwarded or included resource, * because they were already done for the original request. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ private void invoke(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Checking to see if the context classloader is the current context // classloader. If it's not, we're saving it, and setting the context // classloader to the Context classloader ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); ClassLoader contextClassLoader = context.getLoader().getClassLoader(); if (oldCCL != contextClassLoader) { Thread.currentThread().setContextClassLoader(contextClassLoader); } else { oldCCL = null; } // Initialize local variables we may need HttpServletRequest hrequest = null; if (request instanceof HttpServletRequest) hrequest = (HttpServletRequest) request; HttpServletResponse hresponse = null; if (response instanceof HttpServletResponse) hresponse = (HttpServletResponse) response; Servlet servlet = null; IOException ioException = null; ServletException servletException = null; RuntimeException runtimeException = null; boolean unavailable = false; // Check for the servlet being marked unavailable if (wrapper.isUnavailable()) { log(sm.getString("applicationDispatcher.isUnavailable", wrapper.getName())); if (hresponse == null) { ; // NOTE - Not much we can do generically } else { long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) hresponse.setDateHeader("Retry-After", available); hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("applicationDispatcher.isUnavailable", wrapper.getName())); } unavailable = true; } // Allocate a servlet instance to process this request try { if (!unavailable) { // if (debug >= 2) // log(" Allocating servlet instance"); servlet = wrapper.allocate(); // if ((debug >= 2) && (servlet == null)) // log(" No servlet instance returned!"); } } catch (ServletException e) { log(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), e); servletException = e; servlet = null; } catch (Throwable e) { log(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), e); servletException = new ServletException( sm.getString("applicationDispatcher.allocateException", wrapper.getName()), e); servlet = null; } // Get the FilterChain Here ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet); // Call the service() method for the allocated servlet instance try { String jspFile = wrapper.getJspFile(); if (jspFile != null) request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); else request.removeAttribute(Globals.JSP_FILE_ATTR); support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT, servlet, request, response); // for includes/forwards if ((servlet != null) && (filterChain != null)) { filterChain.doFilter(request, response); } // Servlet Service Method is called by the FilterChain request.removeAttribute(Globals.JSP_FILE_ATTR); support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); } catch (ClientAbortException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); ioException = e; } catch (IOException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); log(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e); ioException = e; } catch (UnavailableException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); log(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e); servletException = e; wrapper.unavailable(e); } catch (ServletException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); Throwable rootCause = e; Throwable rootCauseCheck = null; // Extra aggressive rootCause finding do { try { rootCauseCheck = (Throwable) PropertyUtils.getProperty(rootCause, "rootCause"); if (rootCauseCheck != null) rootCause = rootCauseCheck; } catch (ClassCastException ex) { rootCauseCheck = null; } catch (IllegalAccessException ex) { rootCauseCheck = null; } catch (NoSuchMethodException ex) { rootCauseCheck = null; } catch (java.lang.reflect.InvocationTargetException ex) { rootCauseCheck = null; } } while (rootCauseCheck != null); log(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), rootCause); servletException = e; } catch (RuntimeException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); log(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e); runtimeException = e; } // Release the filter chain (if any) for this request try { if (filterChain != null) filterChain.release(); } catch (Throwable e) { log.error(sm.getString("standardWrapper.releaseFilters", wrapper.getName()), e); //FIXME Exception handling needs to be simpiler to what is in the StandardWrapperValue } // Deallocate the allocated servlet instance try { if (servlet != null) { wrapper.deallocate(servlet); } } catch (ServletException e) { log(sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e); servletException = e; } catch (Throwable e) { log(sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e); servletException = new ServletException( sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e); } // Reset the old context class loader if (oldCCL != null) Thread.currentThread().setContextClassLoader(oldCCL); // Rethrow an exception if one was thrown by the invoked servlet if (ioException != null) throw ioException; if (servletException != null) throw servletException; if (runtimeException != null) throw runtimeException; } /** * Log a message on the Logger associated with our Context (if any) * * @param message Message to be logged */ private void log(String message) { Logger logger = context.getLogger(); if (logger != null) logger.log("ApplicationDispatcher[" + context.getPath() + "]: " + message); else System.out.println("ApplicationDispatcher[" + context.getPath() + "]: " + message); } /** * Log a message on the Logger associated with our Container (if any) * * @param message Message to be logged * @param throwable Associated exception */ private void log(String message, Throwable throwable) { Logger logger = context.getLogger(); if (logger != null) logger.log("ApplicationDispatcher[" + context.getPath() + "] " + message, throwable); else { System.out.println("ApplicationDispatcher[" + context.getPath() + "]: " + message); throwable.printStackTrace(System.out); } } /** * Set up to handle the specified request and response * * @param request The servlet request specified by the caller * @param response The servlet response specified by the caller * @param including Are we performing an include() as opposed to * a forward()? */ private void setup(ServletRequest request, ServletResponse response, boolean including) { this.appRequest = request; this.appResponse = response; this.outerRequest = request; this.outerResponse = response; this.including = including; } /** * Unwrap the request if we have wrapped it. */ private void unwrapRequest() { if (wrapRequest == null) return; ServletRequest previous = null; ServletRequest current = outerRequest; while (current != null) { // If we run into the container request we are done if ((current instanceof Request) || (current instanceof RequestFacade)) break; // Remove the current request if it is our wrapper if (current == wrapRequest) { ServletRequest next = ((ServletRequestWrapper) current).getRequest(); if (previous == null) outerRequest = next; else ((ServletRequestWrapper) previous).setRequest(next); break; } // Advance to the next request in the chain previous = current; current = ((ServletRequestWrapper) current).getRequest(); } } /** * Unwrap the response if we have wrapped it. */ private void unwrapResponse() { if (wrapResponse == null) return; ServletResponse previous = null; ServletResponse current = outerResponse; while (current != null) { // If we run into the container response we are done if ((current instanceof Response) || (current instanceof ResponseFacade)) break; // Remove the current response if it is our wrapper if (current == wrapResponse) { ServletResponse next = ((ServletResponseWrapper) current).getResponse(); if (previous == null) outerResponse = next; else ((ServletResponseWrapper) previous).setResponse(next); break; } // Advance to the next response in the chain previous = current; current = ((ServletResponseWrapper) current).getResponse(); } } /** * Create and return a request wrapper that has been inserted in the * appropriate spot in the request chain. */ private ServletRequest wrapRequest() { // Locate the request we should insert in front of ServletRequest previous = null; ServletRequest current = outerRequest; while (current != null) { if ("org.apache.catalina.servlets.InvokerHttpRequest".equals(current.getClass().getName())) break; // KLUDGE - Make nested RD.forward() using invoker work if (!(current instanceof ServletRequestWrapper)) break; if (current instanceof ApplicationHttpRequest) break; if (current instanceof ApplicationRequest) break; if (current instanceof Request) break; previous = current; current = ((ServletRequestWrapper) current).getRequest(); } // Instantiate a new wrapper at this point and insert it in the chain ServletRequest wrapper = null; if ((current instanceof ApplicationHttpRequest) || (current instanceof HttpRequest) || (current instanceof HttpServletRequest)) { // Compute a crossContext flag HttpServletRequest hcurrent = (HttpServletRequest) current; boolean crossContext = !(context.getPath().equals(hcurrent.getContextPath())); wrapper = new ApplicationHttpRequest(hcurrent, context, crossContext); } else { wrapper = new ApplicationRequest(current); } if (previous == null) outerRequest = wrapper; else ((ServletRequestWrapper) previous).setRequest(wrapper); wrapRequest = wrapper; return (wrapper); } /** * Create and return a response wrapper that has been inserted in the * appropriate spot in the response chain. */ private ServletResponse wrapResponse() { // Locate the response we should insert in front of ServletResponse previous = null; ServletResponse current = outerResponse; while (current != null) { if (!(current instanceof ServletResponseWrapper)) break; if (current instanceof ApplicationHttpResponse) break; if (current instanceof ApplicationResponse) break; if (current instanceof Response) break; previous = current; current = ((ServletResponseWrapper) current).getResponse(); } // Instantiate a new wrapper at this point and insert it in the chain ServletResponse wrapper = null; if ((current instanceof ApplicationHttpResponse) || (current instanceof HttpResponse) || (current instanceof HttpServletResponse)) wrapper = new ApplicationHttpResponse((HttpServletResponse) current, including); else wrapper = new ApplicationResponse(current, including); if (previous == null) outerResponse = wrapper; else ((ServletResponseWrapper) previous).setResponse(wrapper); wrapResponse = wrapper; return (wrapper); } }