Results 1 to 3 of 3

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

  1. #1
    Join Date
    Jul 2005
    Posts
    111

    Default 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. #2
    Join Date
    Jul 2005
    Posts
    111

    Default

    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();
        }
    }

  3. #3
    Join Date
    Jun 2010
    Location
    London
    Posts
    304

    Default

    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •