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   
   22   import java.io.IOException;
   23   
   24   import javax.management.MalformedObjectNameException;
   25   import javax.management.ObjectName;
   26   import javax.servlet.Servlet;
   27   import javax.servlet.ServletException;
   28   import javax.servlet.UnavailableException;
   29   import javax.servlet.http.HttpServletResponse;
   30   
   31   import org.apache.catalina.CometEvent;
   32   import org.apache.catalina.CometProcessor;
   33   import org.apache.catalina.Context;
   34   import org.apache.catalina.Globals;
   35   import org.apache.catalina.connector.ClientAbortException;
   36   import org.apache.catalina.connector.Request;
   37   import org.apache.catalina.connector.Response;
   38   import org.apache.catalina.util.StringManager;
   39   import org.apache.catalina.valves.ValveBase;
   40   import org.apache.tomcat.util.buf.MessageBytes;
   41   import org.apache.tomcat.util.log.SystemLogHandler;
   42   
   43   /**
   44    * Valve that implements the default basic behavior for the
   45    * <code>StandardWrapper</code> container implementation.
   46    *
   47    * @author Craig R. McClanahan
   48    * @version $Revision: 596489 $ $Date: 2007-11-20 00:38:40 +0100 (Tue, 20 Nov 2007) $
   49    */
   50   
   51   final class StandardWrapperValve
   52       extends ValveBase {
   53   
   54       // ----------------------------------------------------- Instance Variables
   55   
   56   
   57       // Some JMX statistics. This vavle is associated with a StandardWrapper.
   58       // We expose the StandardWrapper as JMX ( j2eeType=Servlet ). The fields
   59       // are here for performance.
   60       private volatile long processingTime;
   61       private volatile long maxTime;
   62       private volatile long minTime = Long.MAX_VALUE;
   63       private volatile int requestCount;
   64       private volatile int errorCount;
   65   
   66   
   67       /**
   68        * The string manager for this package.
   69        */
   70       private static final StringManager sm =
   71           StringManager.getManager(Constants.Package);
   72   
   73   
   74       // --------------------------------------------------------- Public Methods
   75   
   76   
   77       /**
   78        * Invoke the servlet we are managing, respecting the rules regarding
   79        * servlet lifecycle and SingleThreadModel support.
   80        *
   81        * @param request Request to be processed
   82        * @param response Response to be produced
   83        * @param valveContext Valve context used to forward to the next Valve
   84        *
   85        * @exception IOException if an input/output error occurred
   86        * @exception ServletException if a servlet error occurred
   87        */
   88       public final void invoke(Request request, Response response)
   89           throws IOException, ServletException {
   90   
   91           // Initialize local variables we may need
   92           boolean unavailable = false;
   93           Throwable throwable = null;
   94           // This should be a Request attribute...
   95           long t1=System.currentTimeMillis();
   96           requestCount++;
   97           StandardWrapper wrapper = (StandardWrapper) getContainer();
   98           Servlet servlet = null;
   99           Context context = (Context) wrapper.getParent();
  100           
  101           // Check for the application being marked unavailable
  102           if (!context.getAvailable()) {
  103           	response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
  104                              sm.getString("standardContext.isUnavailable"));
  105               unavailable = true;
  106           }
  107   
  108           // Check for the servlet being marked unavailable
  109           if (!unavailable && wrapper.isUnavailable()) {
  110               container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
  111                       wrapper.getName()));
  112               long available = wrapper.getAvailable();
  113               if ((available > 0L) && (available < Long.MAX_VALUE)) {
  114                   response.setDateHeader("Retry-After", available);
  115                   response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
  116                           sm.getString("standardWrapper.isUnavailable",
  117                                   wrapper.getName()));
  118               } else if (available == Long.MAX_VALUE) {
  119                   response.sendError(HttpServletResponse.SC_NOT_FOUND,
  120                           sm.getString("standardWrapper.notFound",
  121                                   wrapper.getName()));
  122               }
  123               unavailable = true;
  124           }
  125   
  126           // Allocate a servlet instance to process this request
  127           try {
  128               if (!unavailable) {
  129                   servlet = wrapper.allocate();
  130               }
  131           } catch (UnavailableException e) {
  132               container.getLogger().error(
  133                       sm.getString("standardWrapper.allocateException",
  134                               wrapper.getName()), e);
  135               long available = wrapper.getAvailable();
  136               if ((available > 0L) && (available < Long.MAX_VALUE)) {
  137               	response.setDateHeader("Retry-After", available);
  138               	response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
  139                              sm.getString("standardWrapper.isUnavailable",
  140                                           wrapper.getName()));
  141               } else if (available == Long.MAX_VALUE) {
  142               	response.sendError(HttpServletResponse.SC_NOT_FOUND,
  143                              sm.getString("standardWrapper.notFound",
  144                                           wrapper.getName()));
  145               }
  146           } catch (ServletException e) {
  147               container.getLogger().error(sm.getString("standardWrapper.allocateException",
  148                                wrapper.getName()), StandardWrapper.getRootCause(e));
  149               throwable = e;
  150               exception(request, response, e);
  151               servlet = null;
  152           } catch (Throwable e) {
  153               container.getLogger().error(sm.getString("standardWrapper.allocateException",
  154                                wrapper.getName()), e);
  155               throwable = e;
  156               exception(request, response, e);
  157               servlet = null;
  158           }
  159   
  160           // Identify if the request is Comet related now that the servlet has been allocated
  161           boolean comet = false;
  162           if (servlet instanceof CometProcessor 
  163                   && request.getAttribute("org.apache.tomcat.comet.support") == Boolean.TRUE) {
  164               comet = true;
  165               request.setComet(true);
  166           }
  167           
  168           // Acknowledge the request
  169           try {
  170               response.sendAcknowledgement();
  171           } catch (IOException e) {
  172           	request.removeAttribute(Globals.JSP_FILE_ATTR);
  173               container.getLogger().warn(sm.getString("standardWrapper.acknowledgeException",
  174                                wrapper.getName()), e);
  175               throwable = e;
  176               exception(request, response, e);
  177           } catch (Throwable e) {
  178               container.getLogger().error(sm.getString("standardWrapper.acknowledgeException",
  179                                wrapper.getName()), e);
  180               throwable = e;
  181               exception(request, response, e);
  182               servlet = null;
  183           }
  184           MessageBytes requestPathMB = null;
  185           if (request != null) {
  186               requestPathMB = request.getRequestPathMB();
  187           }
  188           request.setAttribute
  189               (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
  190                ApplicationFilterFactory.REQUEST_INTEGER);
  191           request.setAttribute
  192               (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
  193                requestPathMB);
  194           // Create the filter chain for this request
  195           ApplicationFilterFactory factory =
  196               ApplicationFilterFactory.getInstance();
  197           ApplicationFilterChain filterChain =
  198               factory.createFilterChain(request, wrapper, servlet);
  199           // Reset comet flag value after creating the filter chain
  200           request.setComet(false);
  201   
  202           // Call the filter chain for this request
  203           // NOTE: This also calls the servlet's service() method
  204           try {
  205               String jspFile = wrapper.getJspFile();
  206               if (jspFile != null)
  207               	request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
  208               else
  209               	request.removeAttribute(Globals.JSP_FILE_ATTR);
  210               if ((servlet != null) && (filterChain != null)) {
  211                   // Swallow output if needed
  212                   if (context.getSwallowOutput()) {
  213                       try {
  214                           SystemLogHandler.startCapture();
  215                           if (comet) {
  216                               filterChain.doFilterEvent(request.getEvent());
  217                               request.setComet(true);
  218                           } else {
  219                               filterChain.doFilter(request.getRequest(), 
  220                                       response.getResponse());
  221                           }
  222                       } finally {
  223                           String log = SystemLogHandler.stopCapture();
  224                           if (log != null && log.length() > 0) {
  225                               context.getLogger().info(log);
  226                           }
  227                       }
  228                   } else {
  229                       if (comet) {
  230                           request.setComet(true);
  231                           filterChain.doFilterEvent(request.getEvent());
  232                       } else {
  233                           filterChain.doFilter
  234                               (request.getRequest(), response.getResponse());
  235                       }
  236                   }
  237   
  238               }
  239               request.removeAttribute(Globals.JSP_FILE_ATTR);
  240           } catch (ClientAbortException e) {
  241           	request.removeAttribute(Globals.JSP_FILE_ATTR);
  242               throwable = e;
  243               exception(request, response, e);
  244           } catch (IOException e) {
  245           	request.removeAttribute(Globals.JSP_FILE_ATTR);
  246               container.getLogger().error(sm.getString("standardWrapper.serviceException",
  247                                wrapper.getName()), e);
  248               throwable = e;
  249               exception(request, response, e);
  250           } catch (UnavailableException e) {
  251           	request.removeAttribute(Globals.JSP_FILE_ATTR);
  252               container.getLogger().error(sm.getString("standardWrapper.serviceException",
  253                                wrapper.getName()), e);
  254               //            throwable = e;
  255               //            exception(request, response, e);
  256               wrapper.unavailable(e);
  257               long available = wrapper.getAvailable();
  258               if ((available > 0L) && (available < Long.MAX_VALUE)) {
  259                   response.setDateHeader("Retry-After", available);
  260                   response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
  261                              sm.getString("standardWrapper.isUnavailable",
  262                                           wrapper.getName()));
  263               } else if (available == Long.MAX_VALUE) {
  264               	response.sendError(HttpServletResponse.SC_NOT_FOUND,
  265                               sm.getString("standardWrapper.notFound",
  266                                           wrapper.getName()));
  267               }
  268               // Do not save exception in 'throwable', because we
  269               // do not want to do exception(request, response, e) processing
  270           } catch (ServletException e) {
  271           	request.removeAttribute(Globals.JSP_FILE_ATTR);
  272               Throwable rootCause = StandardWrapper.getRootCause(e);
  273               if (!(rootCause instanceof ClientAbortException)) {
  274                   container.getLogger().error(sm.getString("standardWrapper.serviceException",
  275                                    wrapper.getName()), rootCause);
  276               }
  277               throwable = e;
  278               exception(request, response, e);
  279           } catch (Throwable e) {
  280               request.removeAttribute(Globals.JSP_FILE_ATTR);
  281               container.getLogger().error(sm.getString("standardWrapper.serviceException",
  282                                wrapper.getName()), e);
  283               throwable = e;
  284               exception(request, response, e);
  285           }
  286   
  287           // Release the filter chain (if any) for this request
  288           if (filterChain != null) {
  289               if (request.isComet()) {
  290                   // If this is a Comet request, then the same chain will be used for the
  291                   // processing of all subsequent events.
  292                   filterChain.reuse();
  293               } else {
  294                   filterChain.release();
  295               }
  296           }
  297   
  298           // Deallocate the allocated servlet instance
  299           try {
  300               if (servlet != null) {
  301                   wrapper.deallocate(servlet);
  302               }
  303           } catch (Throwable e) {
  304               container.getLogger().error(sm.getString("standardWrapper.deallocateException",
  305                                wrapper.getName()), e);
  306               if (throwable == null) {
  307                   throwable = e;
  308                   exception(request, response, e);
  309               }
  310           }
  311   
  312           // If this servlet has been marked permanently unavailable,
  313           // unload it and release this instance
  314           try {
  315               if ((servlet != null) &&
  316                   (wrapper.getAvailable() == Long.MAX_VALUE)) {
  317                   wrapper.unload();
  318               }
  319           } catch (Throwable e) {
  320               container.getLogger().error(sm.getString("standardWrapper.unloadException",
  321                                wrapper.getName()), e);
  322               if (throwable == null) {
  323                   throwable = e;
  324                   exception(request, response, e);
  325               }
  326           }
  327           long t2=System.currentTimeMillis();
  328   
  329           long time=t2-t1;
  330           processingTime += time;
  331           if( time > maxTime) maxTime=time;
  332           if( time < minTime) minTime=time;
  333   
  334       }
  335   
  336   
  337       /**
  338        * Process a Comet event. The main differences here are to not use sendError
  339        * (the response is committed), to avoid creating a new filter chain
  340        * (which would work but be pointless), and a few very minor tweaks. 
  341        *
  342        * @param request The servlet request to be processed
  343        * @param response The servlet response to be created
  344        *
  345        * @exception IOException if an input/output error occurs, or is thrown
  346        *  by a subsequently invoked Valve, Filter, or Servlet
  347        * @exception ServletException if a servlet error occurs, or is thrown
  348        *  by a subsequently invoked Valve, Filter, or Servlet
  349        */
  350       public void event(Request request, Response response, CometEvent event)
  351           throws IOException, ServletException {
  352           
  353           // Initialize local variables we may need
  354           Throwable throwable = null;
  355           // This should be a Request attribute...
  356           long t1=System.currentTimeMillis();
  357           // FIXME: Add a flag to count the total amount of events processed ? requestCount++;
  358           StandardWrapper wrapper = (StandardWrapper) getContainer();
  359           Servlet servlet = null;
  360           Context context = (Context) wrapper.getParent();
  361   
  362           // Check for the application being marked unavailable
  363           boolean unavailable = !context.getAvailable() || wrapper.isUnavailable();
  364           
  365           // Allocate a servlet instance to process this request
  366           try {
  367               if (!unavailable) {
  368                   servlet = wrapper.allocate();
  369               }
  370           } catch (UnavailableException e) {
  371               // The response is already committed, so it's not possible to do anything
  372           } catch (ServletException e) {
  373               container.getLogger().error(sm.getString("standardWrapper.allocateException",
  374                                wrapper.getName()), StandardWrapper.getRootCause(e));
  375               throwable = e;
  376               exception(request, response, e);
  377               servlet = null;
  378           } catch (Throwable e) {
  379               container.getLogger().error(sm.getString("standardWrapper.allocateException",
  380                                wrapper.getName()), e);
  381               throwable = e;
  382               exception(request, response, e);
  383               servlet = null;
  384           }
  385   
  386           MessageBytes requestPathMB = null;
  387           if (request != null) {
  388               requestPathMB = request.getRequestPathMB();
  389           }
  390           request.setAttribute
  391               (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
  392                ApplicationFilterFactory.REQUEST_INTEGER);
  393           request.setAttribute
  394               (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
  395                requestPathMB);
  396           // Get the current (unchanged) filter chain for this request
  397           ApplicationFilterChain filterChain = 
  398               (ApplicationFilterChain) request.getFilterChain();
  399   
  400           // Call the filter chain for this request
  401           // NOTE: This also calls the servlet's event() method
  402           try {
  403               String jspFile = wrapper.getJspFile();
  404               if (jspFile != null)
  405                   request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
  406               else
  407                   request.removeAttribute(Globals.JSP_FILE_ATTR);
  408               if ((servlet != null) && (filterChain != null)) {
  409   
  410                   // Swallow output if needed
  411                   if (context.getSwallowOutput()) {
  412                       try {
  413                           SystemLogHandler.startCapture();
  414                           filterChain.doFilterEvent(request.getEvent());
  415                       } finally {
  416                           String log = SystemLogHandler.stopCapture();
  417                           if (log != null && log.length() > 0) {
  418                               context.getLogger().info(log);
  419                           }
  420                       }
  421                   } else {
  422                       filterChain.doFilterEvent(request.getEvent());
  423                   }
  424   
  425               }
  426               request.removeAttribute(Globals.JSP_FILE_ATTR);
  427           } catch (ClientAbortException e) {
  428               request.removeAttribute(Globals.JSP_FILE_ATTR);
  429               throwable = e;
  430               exception(request, response, e);
  431           } catch (IOException e) {
  432               request.removeAttribute(Globals.JSP_FILE_ATTR);
  433               container.getLogger().error(sm.getString("standardWrapper.serviceException",
  434                                wrapper.getName()), e);
  435               throwable = e;
  436               exception(request, response, e);
  437           } catch (UnavailableException e) {
  438               request.removeAttribute(Globals.JSP_FILE_ATTR);
  439               container.getLogger().error(sm.getString("standardWrapper.serviceException",
  440                                wrapper.getName()), e);
  441               // Do not save exception in 'throwable', because we
  442               // do not want to do exception(request, response, e) processing
  443           } catch (ServletException e) {
  444               request.removeAttribute(Globals.JSP_FILE_ATTR);
  445               Throwable rootCause = StandardWrapper.getRootCause(e);
  446               if (!(rootCause instanceof ClientAbortException)) {
  447                   container.getLogger().error(sm.getString("standardWrapper.serviceException",
  448                                    wrapper.getName()), rootCause);
  449               }
  450               throwable = e;
  451               exception(request, response, e);
  452           } catch (Throwable e) {
  453               request.removeAttribute(Globals.JSP_FILE_ATTR);
  454               container.getLogger().error(sm.getString("standardWrapper.serviceException",
  455                                wrapper.getName()), e);
  456               throwable = e;
  457               exception(request, response, e);
  458           }
  459   
  460           // Release the filter chain (if any) for this request
  461           if (filterChain != null) {
  462               filterChain.reuse();
  463           }
  464   
  465           // Deallocate the allocated servlet instance
  466           try {
  467               if (servlet != null) {
  468                   wrapper.deallocate(servlet);
  469               }
  470           } catch (Throwable e) {
  471               container.getLogger().error(sm.getString("standardWrapper.deallocateException",
  472                                wrapper.getName()), e);
  473               if (throwable == null) {
  474                   throwable = e;
  475                   exception(request, response, e);
  476               }
  477           }
  478   
  479           // If this servlet has been marked permanently unavailable,
  480           // unload it and release this instance
  481           try {
  482               if ((servlet != null) &&
  483                   (wrapper.getAvailable() == Long.MAX_VALUE)) {
  484                   wrapper.unload();
  485               }
  486           } catch (Throwable e) {
  487               container.getLogger().error(sm.getString("standardWrapper.unloadException",
  488                                wrapper.getName()), e);
  489               if (throwable == null) {
  490                   throwable = e;
  491                   exception(request, response, e);
  492               }
  493           }
  494   
  495           long t2=System.currentTimeMillis();
  496   
  497           long time=t2-t1;
  498           processingTime += time;
  499           if( time > maxTime) maxTime=time;
  500           if( time < minTime) minTime=time;
  501   
  502       }
  503   
  504   
  505       // -------------------------------------------------------- Private Methods
  506   
  507   
  508       /**
  509        * Handle the specified ServletException encountered while processing
  510        * the specified Request to produce the specified Response.  Any
  511        * exceptions that occur during generation of the exception report are
  512        * logged and swallowed.
  513        *
  514        * @param request The request being processed
  515        * @param response The response being generated
  516        * @param exception The exception that occurred (which possibly wraps
  517        *  a root cause exception
  518        */
  519       private void exception(Request request, Response response,
  520                              Throwable exception) {
  521       	request.setAttribute(Globals.EXCEPTION_ATTR, exception);
  522           response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
  523   
  524       }
  525   
  526       public long getProcessingTime() {
  527           return processingTime;
  528       }
  529   
  530       public void setProcessingTime(long processingTime) {
  531           this.processingTime = processingTime;
  532       }
  533   
  534       public long getMaxTime() {
  535           return maxTime;
  536       }
  537   
  538       public void setMaxTime(long maxTime) {
  539           this.maxTime = maxTime;
  540       }
  541   
  542       public long getMinTime() {
  543           return minTime;
  544       }
  545   
  546       public void setMinTime(long minTime) {
  547           this.minTime = minTime;
  548       }
  549   
  550       public int getRequestCount() {
  551           return requestCount;
  552       }
  553   
  554       public void setRequestCount(int requestCount) {
  555           this.requestCount = requestCount;
  556       }
  557   
  558       public int getErrorCount() {
  559           return errorCount;
  560       }
  561   
  562       public void setErrorCount(int errorCount) {
  563           this.errorCount = errorCount;
  564       }
  565   
  566       // Don't register in JMX
  567   
  568       public ObjectName createObjectName(String domain, ObjectName parent)
  569               throws MalformedObjectNameException
  570       {
  571           return null;
  572       }
  573   }

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