/* (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);
      }
    }
  }
예제 #2
0
  public Object invoke(Object target, String methodName, Object[] arguments) {
    if (arguments.length == 0)
      throw new MissingMethodException(METHOD_SIGNATURE, target.getClass(), arguments);

    GrailsWebRequest webRequest =
        (GrailsWebRequest) RequestContextHolder.currentRequestAttributes();
    GrailsApplication application = webRequest.getAttributes().getGrailsApplication();
    HttpServletRequest request = webRequest.getCurrentRequest();
    HttpServletResponse response = webRequest.getCurrentResponse();

    boolean renderView = true;
    GroovyObject controller = (GroovyObject) target;
    if ((arguments[0] instanceof String) || (arguments[0] instanceof GString)) {
      setContentType(response, TEXT_HTML, DEFAULT_ENCODING, true);
      String text = arguments[0].toString();
      renderView = renderText(text, response);
    } else if (arguments[0] instanceof Closure) {
      setContentType(response, TEXT_HTML, gspEncoding, true);
      Closure closure = (Closure) arguments[arguments.length - 1];
      renderView = renderMarkup(closure, response);
    } else if (arguments[0] instanceof Map) {
      Map argMap = (Map) arguments[0];
      Writer out;
      if (argMap.containsKey(ARGUMENT_CONTENT_TYPE) && argMap.containsKey(ARGUMENT_ENCODING)) {
        String contentType = argMap.get(ARGUMENT_CONTENT_TYPE).toString();
        String encoding = argMap.get(ARGUMENT_ENCODING).toString();
        setContentType(response, contentType, encoding);
        out = GSPResponseWriter.getInstance(response, BUFFER_SIZE);
      } else if (argMap.containsKey(ARGUMENT_CONTENT_TYPE)) {
        setContentType(response, argMap.get(ARGUMENT_CONTENT_TYPE).toString(), DEFAULT_ENCODING);
        out = GSPResponseWriter.getInstance(response, BUFFER_SIZE);
      } else {
        setContentType(response, TEXT_HTML, DEFAULT_ENCODING, true);
        out = GSPResponseWriter.getInstance(response, BUFFER_SIZE);
      }

      if (argMap.containsKey(ARGUMENT_STATUS)) {
        Object statusObj = argMap.get(ARGUMENT_STATUS);
        if (statusObj != null) {
          try {
            response.setStatus(Integer.parseInt(statusObj.toString()));
          } catch (NumberFormatException e) {
            throw new ControllerExecutionException(
                "Argument [status] of method [render] must be a valid integer.");
          }
        }
      }

      webRequest.setOut(out);

      if (arguments[arguments.length - 1] instanceof Closure) {
        Closure callable = (Closure) arguments[arguments.length - 1];
        if (BUILDER_TYPE_RICO.equals(argMap.get(ARGUMENT_BUILDER))) {
          renderView = renderRico(callable, response);
        } else if (BUILDER_TYPE_JSON.equals(argMap.get(ARGUMENT_BUILDER))
            || isJSONResponse(response)) {
          renderView = renderJSON(callable, response);
        } else {
          renderView = renderMarkup(callable, response);
        }
      } else if (arguments[arguments.length - 1] instanceof String) {
        String text = (String) arguments[arguments.length - 1];
        renderView = renderText(text, out);
      } else if (argMap.containsKey(ARGUMENT_TEXT)) {
        String text = argMap.get(ARGUMENT_TEXT).toString();
        renderView = renderText(text, out);
      } else if (argMap.containsKey(ARGUMENT_VIEW)) {

        renderView(argMap, target, controller);
      } else if (argMap.containsKey(ARGUMENT_TEMPLATE)) {
        renderView = renderTemplate(target, controller, webRequest, argMap, out);
      } else {
        Object object = arguments[0];
        renderView = renderObject(object, out);
      }
      try {
        if (!renderView) {
          out.flush();
        }
      } catch (IOException e) {
        throw new ControllerExecutionException(
            "I/O error executing render method for arguments [" + argMap + "]: " + e.getMessage(),
            e);
      }
    } else {
      throw new MissingMethodException(METHOD_SIGNATURE, target.getClass(), arguments);
    }
    webRequest.setRenderView(renderView);
    return null;
  }