Announcement Announcement Module
Collapse
No announcement yet.
do grails controller actions catch or allow exceptions to bubble up by default? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • do grails controller actions catch or allow exceptions to bubble up by default?

    i'm trying to use spring-security-oauth in a grails application and it depends on a mechanism which allows for exceptions to be thrown at the controller layer or below
    and caught by a servlet filter inserted into the core spring-security filter chain.

    i could be wrong, but it appears as if the exception which needs to be trapped by the filter may be being trapped by the grails infrastructure which is calling the controller
    action.

    is this possible? and if so, any way to identify exceptions that would be allowed to bubble up?

  • #2
    looks like GrailsExceptionResolver is eating my exception:

    Code:
    //...
    package org.codehaus.groovy.grails.web.errors;
    
    import grails.util.Environment;
    import grails.util.GrailsUtil;
    
    import java.util.Collections;
    import java.util.Enumeration;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.codehaus.groovy.control.CompilationFailedException;
    import org.codehaus.groovy.control.MultipleCompilationErrorsException;
    import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
    import org.codehaus.groovy.grails.commons.ConfigurationHolder;
    import org.codehaus.groovy.grails.exceptions.GrailsRuntimeException;
    import org.codehaus.groovy.grails.web.mapping.UrlMappingInfo;
    import org.codehaus.groovy.grails.web.mapping.UrlMappingsHolder;
    import org.codehaus.groovy.grails.web.servlet.mvc.exceptions.GrailsMVCException;
    import org.codehaus.groovy.grails.web.util.WebUtils;
    import org.codehaus.groovy.runtime.InvokerInvocationException;
    import org.springframework.web.context.ServletContextAware;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.View;
    import org.springframework.web.servlet.ViewResolver;
    import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
    
    /**
     * Wraps any runtime exceptions with a GrailsWrappedException instance.
     *
     * @author Graeme Rocher
     */
    public class GrailsExceptionResolver extends SimpleMappingExceptionResolver implements ServletContextAware {
    
        private ServletContext servletContext;
    
        private static final Log LOG = LogFactory.getLog(GrailsExceptionResolver.class);
    
        /* (non-Javadoc)
         * @see org.springframework.web.servlet.handler.SimpleMappingExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
         */
        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
            if ((ex instanceof InvokerInvocationException)||(ex instanceof GrailsMVCException)) {
                Throwable t = getRootCause(ex);
                if (t instanceof Exception) {
                    ex = (Exception) t;
                }
            }
    
            ModelAndView mv = super.resolveException(request, response, handler, ex);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            // expose the servlet 2.3 specs status code request attribute as 500
            request.setAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    
            GrailsUtil.deepSanitize(ex);
    
            GrailsWrappedRuntimeException gwrex = new GrailsWrappedRuntimeException(servletContext, ex);
            mv.addObject("exception",gwrex);
    
            UrlMappingsHolder urlMappings = null;
            try {
                urlMappings = WebUtils.lookupUrlMappings(servletContext);
            }
            catch (Exception e) {
                // ignore, no app ctx in this case.
            }
    
            LOG.error(getRequestLogMessage(request), ex);
    
            if (urlMappings != null) {
                UrlMappingInfo info = urlMappings.matchStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
                if (info == null) {
                    info = urlMappings.matchStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                            getRootCause(ex));
                }
                if (info == null) {
                    info = urlMappings.matchStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                }
                try {
                    if (info != null && info.getViewName() != null) {
                        ViewResolver viewResolver = WebUtils.lookupViewResolver(servletContext);
                        View v = WebUtils.resolveView(request, info, info.getViewName(),viewResolver);
                        if (v != null) {
                            mv.setView(v);
                        }
                    }
                    else if (info != null && info.getControllerName() != null) {
                        String uri;
                        if (request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE) != null) {
                            uri = (String)request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE);
                        }
                        else {
                            uri = request.getRequestURI();
                        }
    
                        if (!response.isCommitted()) {
                            info.configure(WebUtils.retrieveGrailsWebRequest());
                            String forwardUrl = WebUtils.forwardRequestForUrlMappingInfo(
                                    request, response, info, mv.getModel());
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("Matched URI [" + uri + "] to URL mapping [" + info +
                                        "], forwarding to [" + forwardUrl + "] with response [" + response.getClass() + "]");
                            }
                            // return an empty ModelAndView since the error handler has been processed
                            return new ModelAndView();
                        }
                    }
                }
                catch (Exception e) {
                    LOG.error("Unable to render errors view: " + e.getMessage(), e);
                    throw new GrailsRuntimeException(e);
                }
            }
    
            return mv;
        }
    
        /**
         * Obtains the root cause of the given exception
         * @param ex The exception
         * @return The root cause
         */
        public static Throwable getRootCause(Throwable ex) {
            while (ex.getCause() != null && !ex.equals(ex.getCause())) {
                ex = ex.getCause();
            }
            return ex;
        }
    
        public void setServletContext(ServletContext servletContext) {
            this.servletContext = servletContext;
        }
    
        public static int extractLineNumber(CompilationFailedException e) {
            int lineNumber = -1;
            if (e instanceof MultipleCompilationErrorsException) {
                MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException)e;
                Object message = mcee.getErrorCollector().getErrors().iterator().next();
                if (message instanceof SyntaxErrorMessage) {
                    SyntaxErrorMessage sem = (SyntaxErrorMessage)message;
                    lineNumber = sem.getCause().getLine();
                }
            }
            return lineNumber;
        }
    
        public static RuntimeException getFirstRuntimeException(Throwable e) {
            if (e instanceof RuntimeException) return (RuntimeException) e;
    
            Throwable ex = e;
            while (ex.getCause() != null && !ex.equals(ex.getCause())) {
                ex = ex.getCause();
                if (ex instanceof RuntimeException) return (RuntimeException) ex;
            }
            return null;
        }
    
        private static final String LINE_SEPARATOR = System.getProperty("line.separator");
        public static String getRequestLogMessage(HttpServletRequest request) {
            StringBuilder sb = new StringBuilder();
    
            sb.append("Exception occurred when processing request: ");
            sb.append("[").append(request.getMethod().toUpperCase()).append("] ");
    
            if (request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE) != null) {
                sb.append(request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE));
            } else {
                sb.append(request.getRequestURI());
            }
    
            Map flatConfig = ConfigurationHolder.getFlatConfig();
            final boolean shouldLogRequestParameters;
    
            if(flatConfig.containsKey("grails.exceptionresolver.logRequestParameters")) {
                shouldLogRequestParameters = Boolean.TRUE.equals(flatConfig.get("grails.exceptionresolver.logRequestParameters"));
            } else {
                shouldLogRequestParameters = Environment.getCurrent() == Environment.DEVELOPMENT;
            }
            if (shouldLogRequestParameters) {
                Enumeration<String> params = request.getParameterNames();
    
                if (params.hasMoreElements()) {
                    String param;
                    String values[];
                    int i;
    
                    sb.append(" - parameters:");
                    List<String> blackList = (List<String>) flatConfig.get(
                                    "grails.exceptionresolver.params.exclude");
    
                    if (blackList == null) {
                        blackList = Collections.emptyList();
                    }
                    while (params.hasMoreElements()) {
                        param = params.nextElement();
                        values = request.getParameterValues(param);
    
                        for (i = 0; i < values.length; i++) {
                            sb.append(LINE_SEPARATOR).append(param).append(": ");
    
                            if (blackList.contains(param)) {
                                sb.append("***");
                            } else {
                                sb.append(values[i]);
                            }
                        }
                    }
                }
            }
    
            sb.append(LINE_SEPARATOR)
              .append("Stacktrace follows:");
    
            return sb.toString();
        }
    }

    Comment


    • #3
      GrailsExceptionResolver is not catching the exception, but the underlying framework, Spring MVC, is. You can read it bit more about Spring MVC and exceptions here.

      What does this mean for you? I haven't looked into this in any depth, but you should be able to configure your own HandlerExceptionResolver that rethrows the exception, thus ensuring it propagates to the servlet filter.

      Comment

      Working...
      X