/**
   * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. Will just invoke
   * afterCompletion for all interceptors whose preHandle invocation has successfully completed and
   * returned true.
   *
   * @param mappedHandler the mapped HandlerExecutionChain
   * @param interceptorIndex index of last interceptor that successfully completed
   * @param ex Exception thrown on handler execution, or <code>null</code> if none
   * @see HandlerInterceptor#afterCompletion
   */
  protected void triggerAfterCompletion(
      HandlerExecutionChain mappedHandler,
      int interceptorIndex,
      HttpServletRequest request,
      HttpServletResponse response,
      Exception ex)
      throws Exception {

    // Apply afterCompletion methods of registered interceptors.
    if (mappedHandler != null) {
      if (mappedHandler.getInterceptors() != null) {
        for (int i = interceptorIndex; i >= 0; i--) {
          HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
          try {
            interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex);
          } catch (Throwable ex2) {
            GrailsUtil.deepSanitize(ex2);
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
          }
        }
      }
    }
  }
	/**
	 * Processes the actual dispatching to the handler for event requests.
	 * <p>The handler will be obtained by applying the portlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the portlet's installed
	 * HandlerAdapters to find the first that supports the handler class.
	 * @param request current portlet action request
	 * @param response current portlet Action response
	 * @throws Exception in case of any kind of processing failure
	 */
	@Override
	protected void doEventService(EventRequest request, EventResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("DispatcherPortlet with name '" + getPortletName() + "' received action request");
		}

		HandlerExecutionChain mappedHandler = null;
		int interceptorIndex = -1;

		try {
			// Determine handler for the current request.
			mappedHandler = getHandler(request);
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				noHandlerFound(request, response);
				return;
			}

			// Apply preHandle methods of registered interceptors.
			HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
			if (interceptors != null) {
				for (int i = 0; i < interceptors.length; i++) {
					HandlerInterceptor interceptor = interceptors[i];
					if (!interceptor.preHandleEvent(request, response, mappedHandler.getHandler())) {
						triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, null);
						return;
					}
					interceptorIndex = i;
				}
			}

			// Actually invoke the handler.
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
			ha.handleEvent(request, response, mappedHandler.getHandler());

			// Trigger after-completion for successful outcome.
			triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, null);
		}

		catch (Exception ex) {
			// Trigger after-completion for thrown exception.
			triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, ex);
			// Forward the exception to the render phase to be displayed.
			if (this.forwardEventException) {
				try {
					exposeActionException(request, response, ex);
					logger.debug("Caught exception during event phase - forwarding to render phase", ex);
				}
				catch (IllegalStateException ex2) {
					// Probably sendRedirect called... need to rethrow exception immediately.
					throw ex;
				}
			}
			else {
				throw ex;
			}
		}
		catch (Error err) {
			PortletException ex =
					new PortletException("Error occured during request processing: " + err.getMessage(), err);
			// Trigger after-completion for thrown exception.
			triggerAfterEventCompletion(mappedHandler, interceptorIndex, request, response, ex);
			throw ex;
		}
	}
  /* (non-Javadoc)
   * @see org.springframework.web.servlet.DispatcherServlet#doDispatch(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
   */
  protected void doDispatch(final HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    int interceptorIndex = -1;
    final LocaleResolver localeResolver =
        (LocaleResolver) request.getAttribute(LOCALE_RESOLVER_ATTRIBUTE);

    // Expose current LocaleResolver and request as LocaleContext.
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContextHolder.setLocaleContext(
        new LocaleContext() {
          public Locale getLocale() {

            return localeResolver.resolveLocale(request);
          }
        });

    // If the request is an include we need to try to use the original wrapped sitemesh
    // response, otherwise layouts won't work properly
    if (WebUtils.isIncludeRequest(request)) {
      response = useWrappedOrOriginalResponse(response);
    }

    GrailsWebRequest requestAttributes = null;
    GrailsWebRequest previousRequestAttributes = null;
    Exception handlerException = null;
    try {
      ModelAndView mv = null;
      try {
        Object exceptionAttribute = request.getAttribute(EXCEPTION_ATTRIBUTE);
        // only process multipart requests if an exception hasn't occured
        if (exceptionAttribute == null) processedRequest = checkMultipart(request);
        // Expose current RequestAttributes to current thread.
        previousRequestAttributes =
            (GrailsWebRequest) RequestContextHolder.currentRequestAttributes();
        requestAttributes = new GrailsWebRequest(processedRequest, response, getServletContext());
        copyParamsFromPreviousRequest(previousRequestAttributes, requestAttributes);

        // Update the current web request.
        WebUtils.storeGrailsWebRequest(requestAttributes);

        if (logger.isDebugEnabled()) {
          logger.debug("Bound request context to thread: " + request);
          logger.debug("Using response object: " + response.getClass());
        }

        // Determine handler for the current request.
        mappedHandler = getHandler(processedRequest, false);
        if (mappedHandler == null || mappedHandler.getHandler() == null) {
          noHandlerFound(processedRequest, response);
          return;
        }

        // Apply preHandle methods of registered interceptors.
        if (mappedHandler.getInterceptors() != null) {
          for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
            HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
            if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
              triggerAfterCompletion(
                  mappedHandler, interceptorIndex, processedRequest, response, null);
              return;
            }
            interceptorIndex = i;
          }
        }

        // Actually invoke the handler.
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

        // Apply postHandle methods of registered interceptors.
        if (mappedHandler.getInterceptors() != null) {
          for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
            interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
          }
        }
      } catch (ModelAndViewDefiningException ex) {
        GrailsUtil.deepSanitize(ex);
        handlerException = ex;
        if (logger.isDebugEnabled()) logger.debug("ModelAndViewDefiningException encountered", ex);
        mv = ex.getModelAndView();
      } catch (Exception ex) {
        GrailsUtil.deepSanitize(ex);
        handlerException = ex;
        Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
        mv = processHandlerException(request, response, handler, ex);
      }

      // Did the handler return a view to render?
      if (mv != null && !mv.wasCleared()) {
        // If an exception occurs in here, like a bad closing tag,
        // we have nothing to render.

        try {
          render(mv, processedRequest, response);
        } catch (Exception e) {
          mv = super.processHandlerException(processedRequest, response, mappedHandler, e);
          handlerException = e;
          render(mv, processedRequest, response);
        }
      } else {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Null ModelAndView returned to DispatcherServlet with name '"
                  + getServletName()
                  + "': assuming HandlerAdapter completed request handling");
        }
      }

      // Trigger after-completion for successful outcome.
      triggerAfterCompletion(
          mappedHandler, interceptorIndex, processedRequest, response, handlerException);
    } catch (Exception ex) {
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
    } catch (Error err) {
      ServletException ex = new NestedServletException("Handler processing failed", err);
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
    } finally {
      // Clean up any resources used by a multipart request.
      if (processedRequest instanceof MultipartHttpServletRequest && processedRequest != request) {
        if (multipartResolver != null)
          this.multipartResolver.cleanupMultipart((MultipartHttpServletRequest) processedRequest);
      }
      request.removeAttribute(MultipartHttpServletRequest.class.getName());

      // Reset thread-bound holders
      if (requestAttributes != null) {
        requestAttributes.requestCompleted();
        WebUtils.storeGrailsWebRequest(previousRequestAttributes);
      }

      LocaleContextHolder.setLocaleContext(previousLocaleContext);

      if (logger.isDebugEnabled()) {
        logger.debug("Cleared thread-bound request context: " + request);
      }
    }
  }
	/**
	 * Processes the actual dispatching to the handler for resource requests.
	 * <p>The handler will be obtained by applying the portlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the portlet's installed
	 * HandlerAdapters to find the first that supports the handler class.
	 * @param request current portlet render request
	 * @param response current portlet render response
	 * @throws Exception in case of any kind of processing failure
	 */
	@Override
	protected void doResourceService(ResourceRequest request, ResourceResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("DispatcherPortlet with name '" + getPortletName() + "' received resource request");
		}

		HandlerExecutionChain mappedHandler = null;
		int interceptorIndex = -1;

		try {
			ModelAndView mv;
			try {
				// Determine handler for the current request.
				mappedHandler = getHandler(request);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(request, response);
					return;
				}

				// Apply preHandle methods of registered interceptors.
				HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
				if (interceptors != null) {
					for (int i = 0; i < interceptors.length; i++) {
						HandlerInterceptor interceptor = interceptors[i];
						if (!interceptor.preHandleResource(request, response, mappedHandler.getHandler())) {
							triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, null);
							return;
						}
						interceptorIndex = i;
					}
				}

				// Actually invoke the handler.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				mv = ha.handleResource(request, response, mappedHandler.getHandler());

				// Apply postHandle methods of registered interceptors.
				if (interceptors != null) {
					for (int i = interceptors.length - 1; i >= 0; i--) {
						HandlerInterceptor interceptor = interceptors[i];
						interceptor.postHandleResource(request, response, mappedHandler.getHandler(), mv);
					}
				}
			}
			catch (ModelAndViewDefiningException ex) {
				logger.debug("ModelAndViewDefiningException encountered", ex);
				mv = ex.getModelAndView();
			}
			catch (Exception ex) {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, ex);
			}

			// Did the handler return a view to render?
			if (mv != null && !mv.isEmpty()) {
				render(mv, request, response);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Null ModelAndView returned to DispatcherPortlet with name '" +
							getPortletName() + "': assuming HandlerAdapter completed request handling");
				}
			}

			// Trigger after-completion for successful outcome.
			triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, null);
		}

		catch (Exception ex) {
			// Trigger after-completion for thrown exception.
			triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, ex);
			throw ex;
		}
		catch (Error err) {
			PortletException ex =
					new PortletException("Error occured during request processing: " + err.getMessage(), err);
			// Trigger after-completion for thrown exception.
			triggerAfterResourceCompletion(mappedHandler, interceptorIndex, request, response, ex);
			throw ex;
		}
	}