Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » core » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   
   19   package org.apache.catalina.core;
   20   
   21   import java.io.IOException;
   22   import java.io.PrintWriter;
   23   import java.security.AccessController;
   24   import java.security.PrivilegedActionException;
   25   import java.security.PrivilegedExceptionAction;
   26   
   27   import javax.servlet.RequestDispatcher;
   28   import javax.servlet.Servlet;
   29   import javax.servlet.ServletException;
   30   import javax.servlet.ServletOutputStream;
   31   import javax.servlet.ServletRequest;
   32   import javax.servlet.ServletRequestWrapper;
   33   import javax.servlet.ServletResponse;
   34   import javax.servlet.ServletResponseWrapper;
   35   import javax.servlet.UnavailableException;
   36   import javax.servlet.http.HttpServletRequest;
   37   import javax.servlet.http.HttpServletResponse;
   38   
   39   import org.apache.catalina.Context;
   40   import org.apache.catalina.Globals;
   41   import org.apache.catalina.InstanceEvent;
   42   import org.apache.catalina.Wrapper;
   43   import org.apache.catalina.connector.ClientAbortException;
   44   import org.apache.catalina.connector.Request;
   45   import org.apache.catalina.connector.RequestFacade;
   46   import org.apache.catalina.connector.Response;
   47   import org.apache.catalina.connector.ResponseFacade;
   48   import org.apache.catalina.util.InstanceSupport;
   49   import org.apache.catalina.util.StringManager;
   50   
   51   /**
   52    * Standard implementation of <code>RequestDispatcher</code> that allows a
   53    * request to be forwarded to a different resource to create the ultimate
   54    * response, or to include the output of another resource in the response
   55    * from this resource.  This implementation allows application level servlets
   56    * to wrap the request and/or response objects that are passed on to the
   57    * called resource, as long as the wrapping classes extend
   58    * <code>javax.servlet.ServletRequestWrapper</code> and
   59    * <code>javax.servlet.ServletResponseWrapper</code>.
   60    *
   61    * @author Craig R. McClanahan
   62    * @version $Revision: 836371 $ $Date: 2009-11-15 16:17:08 +0100 (Sun, 15 Nov 2009) $
   63    */
   64   
   65   final class ApplicationDispatcher
   66       implements RequestDispatcher {
   67   
   68   
   69       protected class PrivilegedForward implements PrivilegedExceptionAction {
   70           private ServletRequest request;
   71           private ServletResponse response;
   72   
   73           PrivilegedForward(ServletRequest request, ServletResponse response)
   74           {
   75               this.request = request;
   76               this.response = response;
   77           }
   78   
   79           public Object run() throws java.lang.Exception {
   80               doForward(request,response);
   81               return null;
   82           }
   83       }
   84   
   85       protected class PrivilegedInclude implements PrivilegedExceptionAction {
   86           private ServletRequest request;
   87           private ServletResponse response;
   88   
   89           PrivilegedInclude(ServletRequest request, ServletResponse response)
   90           {
   91               this.request = request;
   92               this.response = response;
   93           }
   94   
   95           public Object run() throws ServletException, IOException {
   96               doInclude(request,response);
   97               return null;
   98           }
   99       }
  100   
  101       
  102       /**
  103        * Used to pass state when the request dispatcher is used. Using instance
  104        * variables causes threading issues and state is too complex to pass and
  105        * return single ServletRequest or ServletResponse objects.
  106        */
  107       private class State {
  108           State(ServletRequest request, ServletResponse response,
  109                   boolean including) {
  110               this.outerRequest = request;
  111               this.outerResponse = response;
  112               this.including = including;
  113           }
  114   
  115           /**
  116            * The outermost request that will be passed on to the invoked servlet.
  117            */
  118           ServletRequest outerRequest = null;
  119   
  120   
  121           /**
  122            * The outermost response that will be passed on to the invoked servlet.
  123            */
  124           ServletResponse outerResponse = null;
  125           
  126           /**
  127            * The request wrapper we have created and installed (if any).
  128            */
  129           ServletRequest wrapRequest = null;
  130   
  131   
  132           /**
  133            * The response wrapper we have created and installed (if any).
  134            */
  135           ServletResponse wrapResponse = null;
  136           
  137           /**
  138            * Are we performing an include() instead of a forward()?
  139            */
  140           boolean including = false;
  141   
  142           /**
  143            * Outermost HttpServletRequest in the chain
  144            */
  145           HttpServletRequest hrequest = null;
  146   
  147           /**
  148            * Outermost HttpServletResponse in the chain
  149            */
  150           HttpServletResponse hresponse = null;
  151       }
  152   
  153       // ----------------------------------------------------------- Constructors
  154   
  155   
  156       /**
  157        * Construct a new instance of this class, configured according to the
  158        * specified parameters.  If both servletPath and pathInfo are
  159        * <code>null</code>, it will be assumed that this RequestDispatcher
  160        * was acquired by name, rather than by path.
  161        *
  162        * @param wrapper The Wrapper associated with the resource that will
  163        *  be forwarded to or included (required)
  164        * @param requestURI The request URI to this resource (if any)
  165        * @param servletPath The revised servlet path to this resource (if any)
  166        * @param pathInfo The revised extra path information to this resource
  167        *  (if any)
  168        * @param queryString Query string parameters included with this request
  169        *  (if any)
  170        * @param name Servlet name (if a named dispatcher was created)
  171        *  else <code>null</code>
  172        */
  173       public ApplicationDispatcher
  174           (Wrapper wrapper, String requestURI, String servletPath,
  175            String pathInfo, String queryString, String name) {
  176   
  177           super();
  178   
  179           // Save all of our configuration parameters
  180           this.wrapper = wrapper;
  181           this.context = (Context) wrapper.getParent();
  182           this.requestURI = requestURI;
  183           this.servletPath = servletPath;
  184           this.pathInfo = pathInfo;
  185           this.queryString = queryString;
  186           this.name = name;
  187           if (wrapper instanceof StandardWrapper)
  188               this.support = ((StandardWrapper) wrapper).getInstanceSupport();
  189           else
  190               this.support = new InstanceSupport(wrapper);
  191   
  192       }
  193   
  194   
  195       // ----------------------------------------------------- Instance Variables
  196   
  197       /**
  198        * The Context this RequestDispatcher is associated with.
  199        */
  200       private Context context = null;
  201   
  202   
  203       /**
  204        * Descriptive information about this implementation.
  205        */
  206       private static final String info =
  207           "org.apache.catalina.core.ApplicationDispatcher/1.0";
  208   
  209   
  210       /**
  211        * The servlet name for a named dispatcher.
  212        */
  213       private String name = null;
  214   
  215   
  216       /**
  217        * The extra path information for this RequestDispatcher.
  218        */
  219       private String pathInfo = null;
  220   
  221   
  222       /**
  223        * The query string parameters for this RequestDispatcher.
  224        */
  225       private String queryString = null;
  226   
  227   
  228       /**
  229        * The request URI for this RequestDispatcher.
  230        */
  231       private String requestURI = null;
  232   
  233   
  234       /**
  235        * The servlet path for this RequestDispatcher.
  236        */
  237       private String servletPath = null;
  238   
  239   
  240       /**
  241        * The StringManager for this package.
  242        */
  243       private static final StringManager sm =
  244         StringManager.getManager(Constants.Package);
  245   
  246   
  247       /**
  248        * The InstanceSupport instance associated with our Wrapper (used to
  249        * send "before dispatch" and "after dispatch" events.
  250        */
  251       private InstanceSupport support = null;
  252   
  253   
  254       /**
  255        * The Wrapper associated with the resource that will be forwarded to
  256        * or included.
  257        */
  258       private Wrapper wrapper = null;
  259   
  260   
  261       // ------------------------------------------------------------- Properties
  262   
  263   
  264       /**
  265        * Return the descriptive information about this implementation.
  266        */
  267       public String getInfo() {
  268   
  269           return (info);
  270   
  271       }
  272   
  273   
  274       // --------------------------------------------------------- Public Methods
  275   
  276   
  277       /**
  278        * Forward this request and response to another resource for processing.
  279        * Any runtime exception, IOException, or ServletException thrown by the
  280        * called servlet will be propogated to the caller.
  281        *
  282        * @param request The servlet request to be forwarded
  283        * @param response The servlet response to be forwarded
  284        *
  285        * @exception IOException if an input/output error occurs
  286        * @exception ServletException if a servlet exception occurs
  287        */
  288       public void forward(ServletRequest request, ServletResponse response)
  289           throws ServletException, IOException
  290       {
  291           if (Globals.IS_SECURITY_ENABLED) {
  292               try {
  293                   PrivilegedForward dp = new PrivilegedForward(request,response);
  294                   AccessController.doPrivileged(dp);
  295               } catch (PrivilegedActionException pe) {
  296                   Exception e = pe.getException();
  297                   if (e instanceof ServletException)
  298                       throw (ServletException) e;
  299                   throw (IOException) e;
  300               }
  301           } else {
  302               doForward(request,response);
  303           }
  304       }
  305   
  306       private void doForward(ServletRequest request, ServletResponse response)
  307           throws ServletException, IOException
  308       {
  309           
  310           // Reset any output that has been buffered, but keep headers/cookies
  311           if (response.isCommitted()) {
  312               throw new IllegalStateException
  313                   (sm.getString("applicationDispatcher.forward.ise"));
  314           }
  315           try {
  316               response.resetBuffer();
  317           } catch (IllegalStateException e) {
  318               throw e;
  319           }
  320   
  321           // Set up to handle the specified request and response
  322           State state = new State(request, response, false);
  323   
  324           if (Globals.STRICT_SERVLET_COMPLIANCE) {
  325               // Check SRV.8.2 / SRV.14.2.5.1 compliance
  326               checkSameObjects(request, response);
  327           }
  328   
  329           wrapResponse(state);
  330           // Handle an HTTP named dispatcher forward
  331           if ((servletPath == null) && (pathInfo == null)) {
  332   
  333               ApplicationHttpRequest wrequest =
  334                   (ApplicationHttpRequest) wrapRequest(state);
  335               HttpServletRequest hrequest = state.hrequest;
  336               wrequest.setRequestURI(hrequest.getRequestURI());
  337               wrequest.setContextPath(hrequest.getContextPath());
  338               wrequest.setServletPath(hrequest.getServletPath());
  339               wrequest.setPathInfo(hrequest.getPathInfo());
  340               wrequest.setQueryString(hrequest.getQueryString());
  341   
  342               processRequest(request,response,state);
  343           }
  344   
  345           // Handle an HTTP path-based forward
  346           else {
  347   
  348               ApplicationHttpRequest wrequest =
  349                   (ApplicationHttpRequest) wrapRequest(state);
  350               String contextPath = context.getPath();
  351               HttpServletRequest hrequest = state.hrequest;
  352               if (hrequest.getAttribute(Globals.FORWARD_REQUEST_URI_ATTR) == null) {
  353                   wrequest.setAttribute(Globals.FORWARD_REQUEST_URI_ATTR,
  354                                         hrequest.getRequestURI());
  355                   wrequest.setAttribute(Globals.FORWARD_CONTEXT_PATH_ATTR,
  356                                         hrequest.getContextPath());
  357                   wrequest.setAttribute(Globals.FORWARD_SERVLET_PATH_ATTR,
  358                                         hrequest.getServletPath());
  359                   wrequest.setAttribute(Globals.FORWARD_PATH_INFO_ATTR,
  360                                         hrequest.getPathInfo());
  361                   wrequest.setAttribute(Globals.FORWARD_QUERY_STRING_ATTR,
  362                                         hrequest.getQueryString());
  363               }
  364    
  365               wrequest.setContextPath(contextPath);
  366               wrequest.setRequestURI(requestURI);
  367               wrequest.setServletPath(servletPath);
  368               wrequest.setPathInfo(pathInfo);
  369               if (queryString != null) {
  370                   wrequest.setQueryString(queryString);
  371                   wrequest.setQueryParams(queryString);
  372               }
  373   
  374               processRequest(request,response,state);
  375           }
  376   
  377           // This is not a real close in order to support error processing
  378           if (wrapper.getLogger().isDebugEnabled() )
  379               wrapper.getLogger().debug(" Disabling the response for futher output");
  380   
  381           if  (response instanceof ResponseFacade) {
  382               ((ResponseFacade) response).finish();
  383           } else {
  384               // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
  385               // and may no longer be instance of RequestFacade 
  386               if (wrapper.getLogger().isDebugEnabled()){
  387                   wrapper.getLogger().debug( " The Response is vehiculed using a wrapper: " 
  388                              + response.getClass().getName() );
  389               }
  390   
  391               // Close anyway
  392               try {
  393                   PrintWriter writer = response.getWriter();
  394                   writer.close();
  395               } catch (IllegalStateException e) {
  396                   try {
  397                       ServletOutputStream stream = response.getOutputStream();
  398                       stream.close();
  399                   } catch (IllegalStateException f) {
  400                       ;
  401                   } catch (IOException f) {
  402                       ;
  403                   }
  404               } catch (IOException e) {
  405                   ;
  406               }
  407           }
  408   
  409       }
  410   
  411       
  412       /**
  413        * Prepare the request based on the filter configuration.
  414        * @param request The servlet request we are processing
  415        * @param response The servlet response we are creating
  416        * @param state The RD state
  417        *
  418        * @exception IOException if an input/output error occurs
  419        * @exception ServletException if a servlet error occurs
  420        */
  421       private void processRequest(ServletRequest request, 
  422                                   ServletResponse response,
  423                                   State state)
  424           throws IOException, ServletException {
  425                   
  426           Integer disInt = (Integer) request.getAttribute
  427               (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR);
  428           if (disInt != null) {
  429               if (disInt.intValue() != ApplicationFilterFactory.ERROR) {
  430                   state.outerRequest.setAttribute
  431                       (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
  432                        getCombinedPath());
  433                   state.outerRequest.setAttribute
  434                       (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
  435                        Integer.valueOf(ApplicationFilterFactory.FORWARD));
  436                   invoke(state.outerRequest, response, state);
  437               } else {
  438                   invoke(state.outerRequest, response, state);
  439               }
  440           }
  441   
  442       }
  443       
  444       
  445       /**
  446        * Combine the servletPath and the pathInfo. If pathInfo is
  447        * <code>null</code> it is ignored. If servletPath is <code>null</code> then
  448        * <code>null</code> is returned.
  449        * @return The combined path with pathInfo appended to servletInfo
  450        */
  451       private String getCombinedPath() {
  452           if (servletPath == null) {
  453               return null;
  454           }
  455           if (pathInfo == null) {
  456               return servletPath;
  457           }
  458           return servletPath + pathInfo;
  459       }
  460   
  461   
  462       /**
  463        * Include the response from another resource in the current response.
  464        * Any runtime exception, IOException, or ServletException thrown by the
  465        * called servlet will be propogated to the caller.
  466        *
  467        * @param request The servlet request that is including this one
  468        * @param response The servlet response to be appended to
  469        *
  470        * @exception IOException if an input/output error occurs
  471        * @exception ServletException if a servlet exception occurs
  472        */
  473       public void include(ServletRequest request, ServletResponse response)
  474           throws ServletException, IOException
  475       {
  476           if (Globals.IS_SECURITY_ENABLED) {
  477               try {
  478                   PrivilegedInclude dp = new PrivilegedInclude(request,response);
  479                   AccessController.doPrivileged(dp);
  480               } catch (PrivilegedActionException pe) {
  481                   Exception e = pe.getException();
  482   
  483                   if (e instanceof ServletException)
  484                       throw (ServletException) e;
  485                   throw (IOException) e;
  486               }
  487           } else {
  488               doInclude(request,response);
  489           }
  490       }
  491   
  492       private void doInclude(ServletRequest request, ServletResponse response)
  493           throws ServletException, IOException
  494       {
  495           // Set up to handle the specified request and response
  496           State state = new State(request, response, true);
  497   
  498           if (Globals.STRICT_SERVLET_COMPLIANCE) {
  499               // Check SRV.8.2 / SRV.14.2.5.1 compliance
  500               checkSameObjects(request, response);
  501           }
  502           
  503           // Create a wrapped response to use for this request
  504           wrapResponse(state);
  505   
  506           // Handle an HTTP named dispatcher include
  507           if (name != null) {
  508   
  509               ApplicationHttpRequest wrequest =
  510                   (ApplicationHttpRequest) wrapRequest(state);
  511               wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name);
  512               if (servletPath != null)
  513                   wrequest.setServletPath(servletPath);
  514               wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
  515                       Integer.valueOf(ApplicationFilterFactory.INCLUDE));
  516               wrequest.setAttribute(
  517                       ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
  518                       getCombinedPath());
  519               invoke(state.outerRequest, state.outerResponse, state);
  520           }
  521   
  522           // Handle an HTTP path based include
  523           else {
  524   
  525               ApplicationHttpRequest wrequest =
  526                   (ApplicationHttpRequest) wrapRequest(state);
  527               String contextPath = context.getPath();
  528               if (requestURI != null)
  529                   wrequest.setAttribute(Globals.INCLUDE_REQUEST_URI_ATTR,
  530                                         requestURI);
  531               if (contextPath != null)
  532                   wrequest.setAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR,
  533                                         contextPath);
  534               if (servletPath != null)
  535                   wrequest.setAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR,
  536                                         servletPath);
  537               if (pathInfo != null)
  538                   wrequest.setAttribute(Globals.INCLUDE_PATH_INFO_ATTR,
  539                                         pathInfo);
  540               if (queryString != null) {
  541                   wrequest.setAttribute(Globals.INCLUDE_QUERY_STRING_ATTR,
  542                                         queryString);
  543                   wrequest.setQueryParams(queryString);
  544               }
  545               
  546               wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
  547                       Integer.valueOf(ApplicationFilterFactory.INCLUDE));
  548               wrequest.setAttribute(
  549                       ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
  550                       getCombinedPath());
  551               invoke(state.outerRequest, state.outerResponse, state);
  552           }
  553   
  554       }
  555   
  556   
  557       // -------------------------------------------------------- Private Methods
  558   
  559   
  560       /**
  561        * Ask the resource represented by this RequestDispatcher to process
  562        * the associated request, and create (or append to) the associated
  563        * response.
  564        * <p>
  565        * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
  566        * that no filters are applied to a forwarded or included resource,
  567        * because they were already done for the original request.
  568        *
  569        * @param request The servlet request we are processing
  570        * @param response The servlet response we are creating
  571        *
  572        * @exception IOException if an input/output error occurs
  573        * @exception ServletException if a servlet error occurs
  574        */
  575       private void invoke(ServletRequest request, ServletResponse response,
  576               State state) throws IOException, ServletException {
  577   
  578           // Checking to see if the context classloader is the current context
  579           // classloader. If it's not, we're saving it, and setting the context
  580           // classloader to the Context classloader
  581           ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
  582           ClassLoader contextClassLoader = context.getLoader().getClassLoader();
  583   
  584           if (oldCCL != contextClassLoader) {
  585               Thread.currentThread().setContextClassLoader(contextClassLoader);
  586           } else {
  587               oldCCL = null;
  588           }
  589   
  590           // Initialize local variables we may need
  591           HttpServletResponse hresponse = state.hresponse;
  592           Servlet servlet = null;
  593           IOException ioException = null;
  594           ServletException servletException = null;
  595           RuntimeException runtimeException = null;
  596           boolean unavailable = false;
  597   
  598           // Check for the servlet being marked unavailable
  599           if (wrapper.isUnavailable()) {
  600               wrapper.getLogger().warn(
  601                       sm.getString("applicationDispatcher.isUnavailable", 
  602                       wrapper.getName()));
  603               long available = wrapper.getAvailable();
  604               if ((available > 0L) && (available < Long.MAX_VALUE))
  605                   hresponse.setDateHeader("Retry-After", available);
  606               hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm
  607                       .getString("applicationDispatcher.isUnavailable", wrapper
  608                               .getName()));
  609               unavailable = true;
  610           }
  611   
  612           // Allocate a servlet instance to process this request
  613           try {
  614               if (!unavailable) {
  615                   servlet = wrapper.allocate();
  616               }
  617           } catch (ServletException e) {
  618               wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
  619                                wrapper.getName()), StandardWrapper.getRootCause(e));
  620               servletException = e;
  621               servlet = null;
  622           } catch (Throwable e) {
  623               wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
  624                                wrapper.getName()), e);
  625               servletException = new ServletException
  626                   (sm.getString("applicationDispatcher.allocateException",
  627                                 wrapper.getName()), e);
  628               servlet = null;
  629           }
  630                   
  631           // Get the FilterChain Here
  632           ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
  633           ApplicationFilterChain filterChain = factory.createFilterChain(request,
  634                                                                   wrapper,servlet);
  635           // Call the service() method for the allocated servlet instance
  636           try {
  637               String jspFile = wrapper.getJspFile();
  638               if (jspFile != null)
  639                   request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
  640               else
  641                   request.removeAttribute(Globals.JSP_FILE_ATTR);
  642               support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT,
  643                                         servlet, request, response);
  644               // for includes/forwards
  645               if ((servlet != null) && (filterChain != null)) {
  646                  filterChain.doFilter(request, response);
  647                }
  648               // Servlet Service Method is called by the FilterChain
  649               request.removeAttribute(Globals.JSP_FILE_ATTR);
  650               support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
  651                                         servlet, request, response);
  652           } catch (ClientAbortException e) {
  653               request.removeAttribute(Globals.JSP_FILE_ATTR);
  654               support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
  655                                         servlet, request, response);
  656               ioException = e;
  657           } catch (IOException e) {
  658               request.removeAttribute(Globals.JSP_FILE_ATTR);
  659               support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
  660                                         servlet, request, response);
  661               wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
  662                                wrapper.getName()), e);
  663               ioException = e;
  664           } catch (UnavailableException e) {
  665               request.removeAttribute(Globals.JSP_FILE_ATTR);
  666               support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
  667                                         servlet, request, response);
  668               wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
  669                                wrapper.getName()), e);
  670               servletException = e;
  671               wrapper.unavailable(e);
  672           } catch (ServletException e) {
  673               request.removeAttribute(Globals.JSP_FILE_ATTR);
  674               support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
  675                                         servlet, request, response);
  676               Throwable rootCause = StandardWrapper.getRootCause(e);
  677               if (!(rootCause instanceof ClientAbortException)) {
  678                   wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
  679                           wrapper.getName()), rootCause);
  680               }
  681               servletException = e;
  682           } catch (RuntimeException e) {
  683               request.removeAttribute(Globals.JSP_FILE_ATTR);
  684               support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
  685                                         servlet, request, response);
  686               wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
  687                                wrapper.getName()), e);
  688               runtimeException = e;
  689           }
  690   
  691           // Release the filter chain (if any) for this request
  692           try {
  693               if (filterChain != null)
  694                   filterChain.release();
  695           } catch (Throwable e) {
  696               wrapper.getLogger().error(sm.getString("standardWrapper.releaseFilters",
  697                                wrapper.getName()), e);
  698               // FIXME: Exception handling needs to be simpiler to what is in the StandardWrapperValue
  699           }
  700   
  701           // Deallocate the allocated servlet instance
  702           try {
  703               if (servlet != null) {
  704                   wrapper.deallocate(servlet);
  705               }
  706           } catch (ServletException e) {
  707               wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException",
  708                                wrapper.getName()), e);
  709               servletException = e;
  710           } catch (Throwable e) {
  711               wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException",
  712                                wrapper.getName()), e);
  713               servletException = new ServletException
  714                   (sm.getString("applicationDispatcher.deallocateException",
  715                                 wrapper.getName()), e);
  716           }
  717   
  718           // Reset the old context class loader
  719           if (oldCCL != null)
  720               Thread.currentThread().setContextClassLoader(oldCCL);
  721           
  722           // Unwrap request/response if needed
  723           // See Bugzilla 30949
  724           unwrapRequest(state);
  725           unwrapResponse(state);
  726           // Recycle request if necessary (also BZ 30949)
  727           recycleRequestWrapper(state);
  728           
  729           // Rethrow an exception if one was thrown by the invoked servlet
  730           if (ioException != null)
  731               throw ioException;
  732           if (servletException != null)
  733               throw servletException;
  734           if (runtimeException != null)
  735               throw runtimeException;
  736   
  737       }
  738   
  739   
  740       /**
  741        * Unwrap the request if we have wrapped it.
  742        */
  743       private void unwrapRequest(State state) {
  744   
  745           if (state.wrapRequest == null)
  746               return;
  747   
  748           ServletRequest previous = null;
  749           ServletRequest current = state.outerRequest;
  750           while (current != null) {
  751   
  752               // If we run into the container request we are done
  753               if ((current instanceof Request)
  754                   || (current instanceof RequestFacade))
  755                   break;
  756   
  757               // Remove the current request if it is our wrapper
  758               if (current == state.wrapRequest) {
  759                   ServletRequest next =
  760                     ((ServletRequestWrapper) current).getRequest();
  761                   if (previous == null)
  762                       state.outerRequest = next;
  763                   else
  764                       ((ServletRequestWrapper) previous).setRequest(next);
  765                   break;
  766               }
  767   
  768               // Advance to the next request in the chain
  769               previous = current;
  770               current = ((ServletRequestWrapper) current).getRequest();
  771   
  772           }
  773   
  774       }
  775   
  776   
  777       /**
  778        * Unwrap the response if we have wrapped it.
  779        */
  780       private void unwrapResponse(State state) {
  781   
  782           if (state.wrapResponse == null)
  783               return;
  784   
  785           ServletResponse previous = null;
  786           ServletResponse current = state.outerResponse;
  787           while (current != null) {
  788   
  789               // If we run into the container response we are done
  790               if ((current instanceof Response)
  791                   || (current instanceof ResponseFacade))
  792                   break;
  793   
  794               // Remove the current response if it is our wrapper
  795               if (current == state.wrapResponse) {
  796                   ServletResponse next =
  797                     ((ServletResponseWrapper) current).getResponse();
  798                   if (previous == null)
  799                       state.outerResponse = next;
  800                   else
  801                       ((ServletResponseWrapper) previous).setResponse(next);
  802                   break;
  803               }
  804   
  805               // Advance to the next response in the chain
  806               previous = current;
  807               current = ((ServletResponseWrapper) current).getResponse();
  808   
  809           }
  810   
  811       }
  812   
  813   
  814       /**
  815        * Create and return a request wrapper that has been inserted in the
  816        * appropriate spot in the request chain.
  817        */
  818       private ServletRequest wrapRequest(State state) {
  819   
  820           // Locate the request we should insert in front of
  821           ServletRequest previous = null;
  822           ServletRequest current = state.outerRequest;
  823           while (current != null) {
  824               if(state.hrequest == null && (current instanceof HttpServletRequest))
  825                   state.hrequest = (HttpServletRequest)current;
  826               if ("org.apache.catalina.servlets.InvokerHttpRequest".
  827                   equals(current.getClass().getName()))
  828                   break; // KLUDGE - Make nested RD.forward() using invoker work
  829               if (!(current instanceof ServletRequestWrapper))
  830                   break;
  831               if (current instanceof ApplicationHttpRequest)
  832                   break;
  833               if (current instanceof ApplicationRequest)
  834                   break;
  835               if (current instanceof Request)
  836                   break;
  837               previous = current;
  838               current = ((ServletRequestWrapper) current).getRequest();
  839           }
  840   
  841           // Instantiate a new wrapper at this point and insert it in the chain
  842           ServletRequest wrapper = null;
  843           if ((current instanceof ApplicationHttpRequest) ||
  844               (current instanceof Request) ||
  845               (current instanceof HttpServletRequest)) {
  846               // Compute a crossContext flag
  847               HttpServletRequest hcurrent = (HttpServletRequest) current;
  848               boolean crossContext = false;
  849               if ((state.outerRequest instanceof ApplicationHttpRequest) ||
  850                   (state.outerRequest instanceof Request) ||
  851                   (state.outerRequest instanceof HttpServletRequest)) {
  852                   HttpServletRequest houterRequest = 
  853                       (HttpServletRequest) state.outerRequest;
  854                   Object contextPath = houterRequest.getAttribute
  855                       (Globals.INCLUDE_CONTEXT_PATH_ATTR);
  856                   if (contextPath == null) {
  857                       // Forward
  858                       contextPath = houterRequest.getContextPath();
  859                   }
  860                   crossContext = !(context.getPath().equals(contextPath));
  861               }
  862               wrapper = new ApplicationHttpRequest
  863                   (hcurrent, context, crossContext);
  864           } else {
  865               wrapper = new ApplicationRequest(current);
  866           }
  867           if (previous == null)
  868               state.outerRequest = wrapper;
  869           else
  870               ((ServletRequestWrapper) previous).setRequest(wrapper);
  871           state.wrapRequest = wrapper;
  872           return (wrapper);
  873   
  874       }
  875   
  876   
  877       /**
  878        * Create and return a response wrapper that has been inserted in the
  879        * appropriate spot in the response chain.
  880        */
  881       private ServletResponse wrapResponse(State state) {
  882   
  883           // Locate the response we should insert in front of
  884           ServletResponse previous = null;
  885           ServletResponse current = state.outerResponse;
  886           while (current != null) {
  887               if(state.hresponse == null && (current instanceof HttpServletResponse)) {
  888                   state.hresponse = (HttpServletResponse)current;
  889                   if(!state.including) // Forward only needs hresponse
  890                       return null;
  891               }
  892               if (!(current instanceof ServletResponseWrapper))
  893                   break;
  894               if (current instanceof ApplicationHttpResponse)
  895                   break;
  896               if (current instanceof ApplicationResponse)
  897                   break;
  898               if (current instanceof Response)
  899                   break;
  900               previous = current;
  901               current = ((ServletResponseWrapper) current).getResponse();
  902           }
  903   
  904           // Instantiate a new wrapper at this point and insert it in the chain
  905           ServletResponse wrapper = null;
  906           if ((current instanceof ApplicationHttpResponse) ||
  907               (current instanceof Response) ||
  908               (current instanceof HttpServletResponse))
  909               wrapper =
  910                   new ApplicationHttpResponse((HttpServletResponse) current,
  911                           state.including);
  912           else
  913               wrapper = new ApplicationResponse(current, state.including);
  914           if (previous == null)
  915               state.outerResponse = wrapper;
  916           else
  917               ((ServletResponseWrapper) previous).setResponse(wrapper);
  918           state.wrapResponse = wrapper;
  919           return (wrapper);
  920   
  921       }
  922   
  923       private void checkSameObjects(ServletRequest appRequest,
  924               ServletResponse appResponse) throws ServletException {
  925           ServletRequest originalRequest =
  926               ApplicationFilterChain.getLastServicedRequest();
  927           ServletResponse originalResponse =
  928               ApplicationFilterChain.getLastServicedResponse();
  929           
  930           // Some forwards, eg from valves will not set original values 
  931           if (originalRequest == null || originalResponse == null) {
  932               return;
  933           }
  934           
  935           boolean same = false;
  936           ServletRequest dispatchedRequest = appRequest;
  937           
  938           //find the request that was passed into the service method
  939           while (originalRequest instanceof ServletRequestWrapper &&
  940                   ((ServletRequestWrapper) originalRequest).getRequest()!=null ) {
  941               originalRequest =
  942                   ((ServletRequestWrapper) originalRequest).getRequest();
  943           }
  944           //compare with the dispatched request
  945           while (!same) {
  946               if (originalRequest.equals(dispatchedRequest)) {
  947                   same = true;
  948               }
  949               if (!same && dispatchedRequest instanceof ServletRequestWrapper) {
  950                   dispatchedRequest =
  951                       ((ServletRequestWrapper) dispatchedRequest).getRequest();
  952               } else {
  953                   break;
  954               }
  955           }
  956           if (!same) {
  957               throw new ServletException(sm.getString(
  958                       "applicationDispatcher.specViolation.request"));
  959           }
  960           
  961           same = false;
  962           ServletResponse dispatchedResponse = appResponse;
  963           
  964           //find the response that was passed into the service method
  965           while (originalResponse instanceof ServletResponseWrapper &&
  966                   ((ServletResponseWrapper) originalResponse).getResponse() != 
  967                       null ) {
  968               originalResponse =
  969                   ((ServletResponseWrapper) originalResponse).getResponse();
  970           }
  971           //compare with the dispatched response
  972           while (!same) {
  973               if (originalResponse.equals(dispatchedResponse)) {
  974                   same = true;
  975               }
  976               
  977               if (!same && dispatchedResponse instanceof ServletResponseWrapper) {
  978                   dispatchedResponse =
  979                       ((ServletResponseWrapper) dispatchedResponse).getResponse();
  980               } else {
  981                   break;
  982               }
  983           }
  984   
  985           if (!same) {
  986               throw new ServletException(sm.getString(
  987                       "applicationDispatcher.specViolation.response"));
  988           }
  989       }
  990   
  991       private void recycleRequestWrapper(State state) {
  992           if (state.wrapRequest instanceof ApplicationHttpRequest) {
  993               ((ApplicationHttpRequest) state.wrapRequest).recycle();        }
  994       }
  995   }

Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » core » [javadoc | source]