Announcement Announcement Module
Collapse
No announcement yet.
struts FlowAction should unwrap ActionExecutionException Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • struts FlowAction should unwrap ActionExecutionException

    hi,

    i'm converting a struts app to webflow. i used to rely on struts's exception handlers to catch certain exceptions from my service layer. but now these are caught by webflow and wrapped in an ActionExecutionException.

    i think it would be useful if FlowAction could unwrap these and rethrow the underlying exception so that they can be handle by struts's exception handlers.

    any thoughts?

    --alex

  • #2
    Hmmm... action execution exception definitely provides useful information about what went wrong: e.g a handle to the action state, the action itself, and the root cause.

    Is it possible to have the exception handler do the unwrapping and invoke to a root cause exception handler?

    Comment


    • #3
      This would be easy to do. A simple implementation would look something like:
      Code:
      package com.jadecove.facet;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      import org.apache.struts.action.ActionForm;
      import org.apache.struts.action.ActionForward;
      import org.apache.struts.action.ActionMapping;
      import org.apache.struts.action.ExceptionHandler;
      import org.apache.struts.config.ExceptionConfig;
      
      import org.springframework.web.flow.ActionExecutionException;
      
      public class UnwrappingActionExecutionExceptionHandler extends ExceptionHandler {
      
          public ActionForward execute(
                  Exception ex,
                  ExceptionConfig ae,
                  ActionMapping mapping,
                  ActionForm formInstance,
                  HttpServletRequest request,
                  HttpServletResponse response)
                  throws ServletException {
              
              if (ex instanceof ActionExecutionException) {
                  Throwable cause = ((ActionExecutionException) ex).getCause();
                  if (cause != null && cause instanceof Exception) ex = (Exception) cause;
              }
              return super.execute(ex, ae, mapping, formInstance, request, response);
          }
      }

      Comment


      • #4
        not sure if that would do it... you'd want to plug back into the exception dispatcher... probably more something like this. i copied this from struts RequestProcessor... i haven't tested it yet, its just an idea:

        Code:
        public class UnwrappingActionExecutionExceptionHandler extends ExceptionHandler {
        
            public ActionForward execute(
                Exception ex,
                ExceptionConfig ae,
                ActionMapping mapping,
                ActionForm form,
                HttpServletRequest request,
                HttpServletResponse response)
            throws ServletException {
        
                // might not be necessary since it should always be the correct exception
                if (!(ex instanceof ActionExecutionException)) {
                    throw new ServletException("wrong exception");
                }
        
                // might want to check if the cause is also ActionExecutionException
                // to prevent loops, but that seems unlikely to happen
                Throwable cause = ((ActionExecutionException) ex).getCause();
                if (cause == null || !(cause instanceof Exception)) {
                    throw new ServletException("no underlying cause");
                }
        
                // Is there a defined handler for this exception?
                ExceptionConfig config = mapping.findException(cause.getClass());
                if (config == null) {
                    log.warn(getInternal().getMessage("unhandledException", exception.getClass()));
                    if (exception instanceof ServletException) {
                        throw (ServletException) cause;
                    } else {
                        throw new ServletException(cause);
                    }
                }
        
                // Use the configured exception handling
                try {
                    ExceptionHandler handler = (ExceptionHandler) 
                        RequestUtils.applicationInstance(config.getHandler());
                    return (handler.execute(cause, config, mapping, form, request, response));
                } catch (Exception e) {
                    throw new ServletException(e);
                }
            }
        }

        Comment


        • #5
          the code above mostly works (there's a few typos, so it won't compile directly). and it could even be refactored to work with any nested exception.

          but there's another issue somewhat related issue, which is that the Errors object doesn't get attached to the BindingActionForm when an exception is thrown.

          so when you return to the view, you'll get exceptions if you try to access the form.

          currently, Errors is attached to the BindingActionForm via a FlowListener which executes after the request has been processed. an alternative might be to put that Errors->BindingActionForm logic in a finally block.

          i'm not too familiar with that code, so maybe there's a better way to handle this.

          Comment


          • #6
            Yep -- you are right -- my hasty-solution does not find the ExceptionConfig for the root cause.

            Comment

            Working...
            X