/**
   * Test routes: GET /wildcard-a myTestController.wildcardA GET /wildcard-b
   * myTestController.wildcardB
   *
   * @throws Exception
   */
  @Test
  public void wildcardRouteFiles() throws Exception {

    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/wildcard-a");
    request.addHeader("host", sampleHost);
    HandlerExecutionChain chain = this.hm.getHandler(request);

    RouterHandler handler = (RouterHandler) chain.getHandler();
    Assert.assertNotNull(handler);

    Route route = handler.getRoute();
    Assert.assertNotNull(route);
    Assert.assertEquals(this.handlerName + ".wildcardA", route.action);

    request = new MockHttpServletRequest("GET", "/wildcard-b");
    request.addHeader("host", sampleHost);
    chain = this.hm.getHandler(request);

    handler = (RouterHandler) chain.getHandler();
    Assert.assertNotNull(handler);

    route = handler.getRoute();
    Assert.assertNotNull(route);
    Assert.assertEquals(this.handlerName + ".wildcardB", route.action);
  }
  public void testMapSimpleUri() throws Exception {
    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/welcome");
    HandlerExecutionChain chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("welcome"), chain.getHandler());

    request = new MockHttpServletRequest("GET", "/welcome/product");
    chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("welcome"), chain.getHandler());
  }
  public void testWithMultiActionControllerMapping() throws Exception {
    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/admin/user");
    HandlerExecutionChain chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("admin"), chain.getHandler());

    request = new MockHttpServletRequest("GET", "/admin/product");
    chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("admin"), chain.getHandler());
  }
  public void testIndexUri() throws Exception {
    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/index");
    HandlerExecutionChain chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("index"), chain.getHandler());

    request = new MockHttpServletRequest("GET", "/index/product");
    chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("index"), chain.getHandler());
  }
  public void testWithoutControllerSuffix() throws Exception {
    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/buyform");
    HandlerExecutionChain chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("buy"), chain.getHandler());

    request = new MockHttpServletRequest("GET", "/buyform/product");
    chain = this.hm.getHandler(request);
    assertEquals(this.wac.getBean("buy"), chain.getHandler());
  }
 @Override
 protected HandlerExecutionChain getHandlerExecutionChain(
     Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
   HandlerInterceptor[] interceptors = addSecurityInterceptor(chain.getInterceptors());
   return new HandlerExecutionChain(chain.getHandler(), interceptors);
 }
 public void testWithRootAsBasePackage() throws Exception {
   MockHttpServletRequest request =
       new MockHttpServletRequest(
           "GET", "/myapp/org/springframework/web/servlet/mvc/mapping/welcome");
   HandlerExecutionChain chain = this.hm4.getHandler(request);
   assertEquals(this.wac.getBean("welcome"), chain.getHandler());
 }
 @Override
 protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   HandlerExecutionChain chain = super.getHandler(request);
   if (chain != null) {
     DefaultMvcResult mvcResult = getMvcResult(request);
     mvcResult.setHandler(chain.getHandler());
     mvcResult.setInterceptors(chain.getInterceptors());
   }
   return chain;
 }
 public ModelAndView excuteAction(HttpServletRequest request, HttpServletResponse response)
     throws Exception {
   // 这里需要声明request的实际类型,否则会报错
   request.setAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING, true);
   HandlerExecutionChain chain = handlerMapping.getHandler(request);
   ModelAndView model = null;
   try {
     model = handlerAdapter.handle(request, response, chain.getHandler());
   } catch (Exception e) {
     e.printStackTrace();
   }
   return model;
 }
  /**
   * Test route: GET /simpleaction myTestController.simpleAction
   *
   * @throws Exception
   */
  @Test
  public void testSimpleRoute() throws Exception {

    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/simpleaction");
    request.addHeader("host", sampleHost);
    HandlerExecutionChain chain = this.hm.getHandler(request);

    RouterHandler handler = (RouterHandler) chain.getHandler();
    Assert.assertNotNull(handler);

    Route route = handler.getRoute();
    Assert.assertNotNull(route);
    Assert.assertEquals(this.handlerName + ".simpleAction", route.action);
  }
  /**
   * Test route: GET /caseinsensitive MyTestCONTROLLER.caseInsensitive
   *
   * @throws Exception
   */
  @Test
  public void caseInsensitiveRoute() throws Exception {

    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/caseinsensitive");
    request.addHeader("host", sampleHost);
    HandlerExecutionChain chain = this.hm.getHandler(request);

    RouterHandler handler = (RouterHandler) chain.getHandler();
    Assert.assertNotNull(handler);

    Route route = handler.getRoute();
    Assert.assertNotNull(route);
    Assert.assertTrue((this.handlerName + ".caseInsensitive").equalsIgnoreCase(route.action));
  }
  /**
   * Test route: PUT /http myTestController.httpAction(type:'PUT') with a GET request and a
   * "x-http-method-override" argument in queryString
   *
   * @throws Exception
   */
  @Test
  public void testOverrideQueryStringHTTPAction() throws Exception {

    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/http");
    request.setQueryString("x-http-method-override=PUT");
    request.addHeader("host", sampleHost);
    HandlerExecutionChain chain = this.hm.getHandler(request);

    RouterHandler handler = (RouterHandler) chain.getHandler();
    Assert.assertNotNull(handler);

    Route route = handler.getRoute();
    Assert.assertNotNull(route);
    Assert.assertEquals(this.handlerName + ".httpAction", route.action);
  }
  /**
   * Passes the given request to a proper controller.
   *
   * @param request
   * @return
   * @throws Exception
   */
  public MockHttpServletResponse handle(HttpServletRequest request) throws Exception {
    MockHttpServletResponse response = new MockHttpServletResponse();

    HandlerExecutionChain handlerExecutionChain = null;
    for (DefaultAnnotationHandlerMapping handlerMapping : handlerMappings) {
      handlerExecutionChain = handlerMapping.getHandler(request);
      if (handlerExecutionChain != null) {
        break;
      }
    }
    Assert.assertNotNull("The request URI does not exist", handlerExecutionChain);

    handlerAdapter.handle(request, response, handlerExecutionChain.getHandler());

    return response;
  }
  /**
   * This method finds the handler for a given request URI, or throws an exception if none were
   * found.
   *
   * <p>It will also ensure that the URI Parameters i.e. /context/test/{name} are added to the
   * request
   *
   * @param request the request for which to find a handler
   * @return The handler that agreed to handle the specified request.
   * @throws NoSuchMethodException if no acceptable handlers could be found
   */
  protected Object getHandler(final MockHttpServletRequest request) throws NoSuchMethodException {
    HandlerExecutionChain chain = null; // NOPMD by jon.adams on 5/14/12

    final Map<String, HandlerMapping> map = applicationContext.getBeansOfType(HandlerMapping.class);
    final Iterator<HandlerMapping> itt = map.values().iterator();

    while (itt.hasNext()) {
      final HandlerMapping mapping = itt.next();

      try {
        chain = mapping.getHandler(request);
      } catch (final HttpRequestMethodNotSupportedException exc) {
        // ignore and try next
        LOGGER.info(
            mapping.getClass().getName()
                + " handler determined it will not handle the request. Message: "
                + exc.getMessage(),
            exc);
      } catch (final Exception exc) {
        throw new RuntimeException(exc); // NOPMD
      }

      if (chain == null) {
        // ignore and try next
        LOGGER.debug(
            mapping.getClass().getName() + " handler determined it will not handle the request.");
      } else {
        // found one. quit looking for more.
        break;
      }
    }

    if (chain == null) {
      throw new NoSuchMethodException(
          "Unable to find handler for request URI: " + request.getRequestURI());
    }

    return chain.getHandler();
  }
  /**
   * 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 {

    if (mappedHandler == null || mappedHandler.getInterceptors() == null) {
      return;
    }

    // Apply afterCompletion methods of registered interceptors.
    for (int i = interceptorIndex; i >= 0; i--) {
      HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
      try {
        interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex);
      } catch (Throwable e) {
        stackFilterer.filter(e, true);
        logger.error("HandlerInterceptor.afterCompletion threw exception", e);
      }
    }
  }
  /**
   * 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);
          }
        }
      }
    }
  }
 public void testWithBasePackageAndCaseSensitive() throws Exception {
   MockHttpServletRequest request =
       new MockHttpServletRequest("GET", "/myapp/mvc/mapping/buyForm");
   HandlerExecutionChain chain = this.hm2.getHandler(request);
   assertEquals(this.wac.getBean("buy"), chain.getHandler());
 }
 public void testWithContextPath() throws Exception {
   MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome");
   request.setContextPath("/myapp");
   HandlerExecutionChain chain = this.hm.getHandler(request);
   assertEquals(this.wac.getBean("welcome"), chain.getHandler());
 }
  /* (non-Javadoc)
   * @see org.springframework.web.servlet.DispatcherServlet#doDispatch(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
   */
  @Override
  protected void doDispatch(final HttpServletRequest request, HttpServletResponse response)
      throws Exception {

    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, localeResolver);

    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    int interceptorIndex = -1;

    // 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;
    RequestAttributes previousRequestAttributes = null;
    Exception handlerException = null;
    boolean isAsyncRequest =
        processedRequest.getAttribute("javax.servlet.async.request_uri") != null;
    try {
      ModelAndView mv;
      boolean errorView = false;
      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 = 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);
        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;
          }
        }

        // if this is an async request that has been resumed, then don't execute the action again
        // instead try get the model and view and continue

        if (isAsyncRequest) {
          Object modelAndViewO =
              processedRequest.getAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW);
          if (modelAndViewO != null) {
            mv = (ModelAndView) modelAndViewO;
          } else {
            mv = null;
          }

        } else {
          // Actually invoke the handler.
          HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
          mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
          // if an async request was started simply return
          if (processedRequest.getAttribute(GrailsApplicationAttributes.ASYNC_STARTED) != null) {
            processedRequest.setAttribute(GrailsApplicationAttributes.MODEL_AND_VIEW, mv);
            return;
          }

          // Do we need view name translation?
          if ((ha instanceof AnnotationMethodHandlerAdapter
                  || ha instanceof RequestMappingHandlerAdapter)
              && mv != null
              && !mv.hasView()) {
            mv.setViewName(getDefaultViewName(request));
          }
        }

        // 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) {
        handlerException = ex;
        if (logger.isDebugEnabled()) {
          logger.debug("ModelAndViewDefiningException encountered", ex);
        }
        mv = ex.getModelAndView();
      } catch (Exception ex) {
        handlerException = ex;
        Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
        mv = processHandlerException(request, response, handler, ex);
        errorView = (mv != null);
      }

      // 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);
          if (isAsyncRequest && (response instanceof GrailsContentBufferingResponse)) {
            GroovyPageLayoutFinder groovyPageLayoutFinder =
                getWebApplicationContext()
                    .getBean("groovyPageLayoutFinder", GroovyPageLayoutFinder.class);
            GrailsContentBufferingResponse bufferingResponse =
                (GrailsContentBufferingResponse) response;
            HttpServletResponse targetResponse = bufferingResponse.getTargetResponse();
            Content content = bufferingResponse.getContent();
            if (content != null) {
              Decorator decorator = groovyPageLayoutFinder.findLayout(request, content);
              SiteMeshWebAppContext webAppContext =
                  new SiteMeshWebAppContext(request, targetResponse, getServletContext());
              if (decorator != null) {
                if (decorator instanceof com.opensymphony.sitemesh.Decorator) {
                  ((com.opensymphony.sitemesh.Decorator) decorator).render(content, webAppContext);
                } else {
                  new OldDecorator2NewDecorator(decorator).render(content, webAppContext);
                }
              } else {
                content.writeOriginal(targetResponse.getWriter());
              }
            }
          }
          if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
          }
        } catch (Exception e) {
          // Only render the error view if we're not already trying to render it.
          // This prevents a recursion if the error page itself has errors.
          if (request.getAttribute(GrailsApplicationAttributes.RENDERING_ERROR_ATTRIBUTE) == null) {
            request.setAttribute(
                GrailsApplicationAttributes.RENDERING_ERROR_ATTRIBUTE, Boolean.TRUE);

            mv = super.processHandlerException(processedRequest, response, mappedHandler, e);
            handlerException = e;
            if (mv != null) render(mv, processedRequest, response);
          } else {
            request.removeAttribute(GrailsApplicationAttributes.RENDERING_ERROR_ATTRIBUTE);
            logger.warn("Recursive rendering of error view detected.", e);

            try {
              response.setContentType("text/plain");
              response.getWriter().write("Internal server error");
              response.flushBuffer();
            } catch (Exception e2) {
              logger.error("Internal server error - problem rendering error view", e2);
            }

            requestAttributes.setRenderView(false);
            return;
          }
        }
      } 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) {
        if (multipartResolver != null) {
          multipartResolver.cleanupMultipart((MultipartHttpServletRequest) processedRequest);
        }
      }
      request.removeAttribute(MultipartHttpServletRequest.class.getName());

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

      LocaleContextHolder.setLocaleContext(previousLocaleContext);

      if (logger.isDebugEnabled()) {
        logger.debug("Cleared thread-bound request context: " + request);
      }
    }
  }
 public void testWithFullBasePackage() throws Exception {
   MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myapp/welcome");
   HandlerExecutionChain chain = this.hm3.getHandler(request);
   assertEquals(this.wac.getBean("welcome"), chain.getHandler());
 }
Esempio n. 21
0
  @Test
  public void webMvcConfigurerExtensionHooks() throws Exception {

    StaticWebApplicationContext appCxt = new StaticWebApplicationContext();
    appCxt.setServletContext(new MockServletContext(new FileSystemResourceLoader()));
    appCxt.registerSingleton("controller", TestController.class);

    WebConfig webConfig = new WebConfig();
    webConfig.setApplicationContext(appCxt);
    webConfig.setServletContext(appCxt.getServletContext());

    String actual = webConfig.mvcConversionService().convert(new TestBean(), String.class);
    assertEquals("converted", actual);

    RequestMappingHandlerAdapter adapter = webConfig.requestMappingHandlerAdapter();
    assertEquals(1, adapter.getMessageConverters().size());

    ConfigurableWebBindingInitializer initializer =
        (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
    assertNotNull(initializer);

    BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(null, "");
    initializer.getValidator().validate(null, bindingResult);
    assertEquals("invalid", bindingResult.getAllErrors().get(0).getCode());

    @SuppressWarnings("unchecked")
    List<HandlerMethodArgumentResolver> argResolvers =
        (List<HandlerMethodArgumentResolver>)
            new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
    assertEquals(1, argResolvers.size());

    @SuppressWarnings("unchecked")
    List<HandlerMethodReturnValueHandler> handlers =
        (List<HandlerMethodReturnValueHandler>)
            new DirectFieldAccessor(adapter).getPropertyValue("customReturnValueHandlers");
    assertEquals(1, handlers.size());

    HandlerExceptionResolverComposite composite =
        (HandlerExceptionResolverComposite) webConfig.handlerExceptionResolver();
    assertEquals(1, composite.getExceptionResolvers().size());

    RequestMappingHandlerMapping rmHandlerMapping = webConfig.requestMappingHandlerMapping();
    rmHandlerMapping.setApplicationContext(appCxt);
    HandlerExecutionChain chain =
        rmHandlerMapping.getHandler(new MockHttpServletRequest("GET", "/"));
    assertNotNull(chain.getInterceptors());
    assertEquals(2, chain.getInterceptors().length);
    assertEquals(LocaleChangeInterceptor.class, chain.getInterceptors()[0].getClass());
    assertEquals(ConversionServiceExposingInterceptor.class, chain.getInterceptors()[1].getClass());

    AbstractHandlerMapping handlerMapping =
        (AbstractHandlerMapping) webConfig.viewControllerHandlerMapping();
    handlerMapping.setApplicationContext(appCxt);
    assertNotNull(handlerMapping);
    assertEquals(1, handlerMapping.getOrder());
    HandlerExecutionChain handler =
        handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path"));
    assertNotNull(handler.getHandler());

    handlerMapping = (AbstractHandlerMapping) webConfig.resourceHandlerMapping();
    handlerMapping.setApplicationContext(appCxt);
    assertNotNull(handlerMapping);
    assertEquals(Integer.MAX_VALUE - 1, handlerMapping.getOrder());
    handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif"));
    assertNotNull(handler.getHandler());

    handlerMapping = (AbstractHandlerMapping) webConfig.defaultServletHandlerMapping();
    handlerMapping.setApplicationContext(appCxt);
    assertNotNull(handlerMapping);
    assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder());
    handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/anyPath"));
    assertNotNull(handler.getHandler());
  }
  /* (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);
      }
    }
  }