Results 1 to 10 of 10

Thread: How to handle FlowExceptions in SWF 1.05 + Spring 2.5.4

  1. #1

    Wink How to handle FlowExceptions in SWF 1.05 + Spring 2.5.4

    Hi,

    Am using SWF 1.0.5 along with Spring MVC 2.5.4

    Am facing an issue in handling RuntimeExceptions like

    org.springframework.webflow.execution.repository.N oSuchFlowExecutionException
    I have defined a custom "FlowExecutionExceptionHandler" which handles
    all FlowExcecutionExceptions.

    But when any exceptions like NoSuchFlowExecutionException occurs , which are of type FlowException this handler is not useful , since control is not reaching there.



    Can anybody suggest a mechanism by which I can

    1) Handle Such FlowExceptions which are out control of FlowExcecutor?

    2) How can I Specify "Timeout" of a flow?


    Any help is greatly appreciated

    Thanks in Advance,
    Spring new bee
    Sudheesh

  2. #2
    Join Date
    Nov 2006
    Location
    Boston, MA
    Posts
    303

    Default handling previously uncaught exceptions outside flow

    To handle any exceptions thrown outside your flow you need to implement a Spring MVC exception resolver (or several resolvers if you have the need to handle some error cases distinctly) and register it (them) in your servlet XML.

    1) In your-app-servlet.xml, add the following definition:
    Code:
        <!-- 
               insert any exception resolver definitions for more specific exceptions 
               if you need to distinctly handle some specific cases; the lower the 
               order property value, the higher the handler's precedence 
         -->
    
    
        <!-- Generic system/programming error resolver that handles the rest of the exceptions not handled by the app; it must have the highest order -->
        <bean id="genericErrorHandler" class="com.yourcompany.yourapp.whatever.exceptionresolvers.SystemErrorResolver">
            <property name="order" value="10"/>
        </bean>
    Exceptions that are thrown during the request processing and not caught anywhere else go to the hander exception resolver chain. Spring looks at all registered handler exception resolvers (beans that implement the appropriate HandlerExceptionResolver interface) in the application context. Any instances that implement the Ordered interface are sorted (lowest order first), and others are added at the end of the list. (per Spring documentation.)

    2) Implement the exception resolver class. Here's an example of the ultimate resolver that handles all previously uncaught system errors and displays the standard system error view.



    Code:
    package com.yourcompany.yourapp.whatever.exceptionresolvers;
    
    import org.apache.log4j.Logger;
    import org.springframework.core.Ordered;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    /**
     * This class implements an exception resolver that redirects to the designated error view in cases of any exceptions that
     * <i>have not been previously caught and handled</i> by the application or framework (including any Spring Webflow error
    * handlers registered with the application). 
    */
    public class SystemErrorResolver implements HandlerExceptionResolver, Ordered {
        
        private static final String ERROR_VIEW = "yourerrorpage";
    
        private int order; // prioritization order number for this Ordered object
        private static final Logger logger = Logger.getLogger(SystemErrorResolver.class);
        private static final String ERR_MESSAGE =
                "Unrecoverable error occurred in the application. See the nested exception stack trace for details. Redirecting to the Error View.";
    
        /** {@inheritDoc} */
        public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse response, Object handler,
                                             Exception e) {
            // return the Error Page view in case of any unhandled exception
            if (e != null) {
                logger.error(ERR_MESSAGE, e); // log msg and complete error stack trace
                return new ModelAndView(ERROR_VIEW);
            } else {
                return null;
            }
        }
    
        /** {@inheritDoc} */
        public int getOrder() {
            return order;
        }
    
        /**
         * Sets the prioritization order number for this Ordered object. 
         *
         * @param num order number
         */
        public void setOrder(int num) {
            this.order = num;
        }
    This is the error resolver for all exceptions that should not - and must not - be caught anywhere else. The only exceptions that must be caught and handled by the application individually are the ones that have specific use cases associated with them. To ensure that all your errors correctly propagate to the designated handler(s) - unaltered! - use runtime exceptions. Checked exceptions are nothing more than glorified error codes that force programmers to mishandle errors before they reach the only place in the application that knows how to handle them properly. Runtime exceptions ensure the exact behavior the exceptions mechanism was invented for: instantly unwind the call stack all the way from the source of the error to the designated handler. It is the job of the programmer to decide where to place such handlers, not the job of the compiler. What to handle and how is dictated by the application requirements only - and nothing else. It was a horrible idea to suggest that the compiler should be advising on error handling.

    So, once you have implemented your SWF and Spring MVC resolvers, use RT exceptions (wrap any JDK and 3rd party checked exceptions into your custom RTEs) and they will be caught and handled by these resolvers. You won't have to do anything else. In other words, throughout your application, you only need to worry about throwing new exceptions when it is appropriate (i.e. when wrapping annoying checked exceptions that you can't handle immediately at their source) and never worry about catching and handling them - since you already have registered the handlers that will do their job - as long as the errors are not intercepted (by incorrect code and a use of checked exceptions.)

    HTH,
    Constantine
    Last edited by constv; May 23rd, 2008 at 09:18 AM.

  3. #3

    Smile

    Thank you for your reply and imm help.
    This will really help me.

    I agree with the philosphy of "keeping error handling techniques away from custom classes" by using runtime unchecked exceptions.


    And the beauty of the Spring IOC is that at any time I can point to any EXCEPTION RESOLVER IMPLEMENTATION just by changing the class in the bean specification.


    Some Questions

    <bean id="genericErrorHandler" class="com.yourcompany.yourapp.whatever.exceptionr esolvers.SystemErrorResolver">
    <property name="order" value="10"/>
    </bean>


    The name "genericErrorHandler" is important right?

    Since in the example given, I can see that bean

    1) genericErrorHandler is not injected to any class in SWF or MVC.

    2) No where its specfied to configure


    I think your points are

    1) Just specify a ERROR handler with id SPECIFICALLY as "genericErrorHandler"

    2) It should be an implementation of 'HandlerExceptionResolver'

    Am not sure whether first point is correct or not.

  4. #4
    Join Date
    Nov 2006
    Location
    Boston, MA
    Posts
    303

    Default

    1) No, the bean ID can be anything you want, it just must be a unique ID. You don't have to use it in other bean definitions.

    2) Yes, it must be an implementation of the HandlerExceptionResolver interface, and you must register it as a bean in the application context. Spring will maintain an ordered list of all your resolvers (if you have more than one) and will use them - in the order you specify by the "order" property, lower numbers first - to catch and handle any exceptions that were not previously caught inside the application. If you have some specific exception that you want to handle in a distinct manner, you need to implement a class that handles that specific exception - with the priority order lower than the one that is designed to catch and handle the rest of all possible Throwables. For example, you might want to catch the NosSuchFlowException specifically (that would mean that the user is trying to return to a state in a flow that no longer exists, such as using the browser history after the end state of the flow has been reached.) In that case, you may define a separate HandlerExceptionResolver implementation. Something like this:


    Code:
    public class NoFlowErrorResolver implements HandlerExceptionResolver, Ordered {
        private static final String MSG_REDIRECTING_TO_START =
                "Caught an attempt to access a state in a flow that is not active. Redirecting to the starting page.";
        private static final String REDIRECT_VIEW = "restart"; // some page that relaunches the flow (e.g does something like: <c:redirect url="/flow.do?_flowId=my-flow"/>)
    
        private int order; // prioritization order
        private static final Logger logger = Logger.getLogger(NoFlowErrorResolver.class);
    
        /** {@inheritDoc} */
        public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse response, Object handler,
                                             Exception e) {
            // return the start view in case of user trying to return to a state in the flow that has ended
            if (e instanceof NoSuchFlowExecutionException) {
                logger.debug(MSG_REDIRECTING_TO_START);
                return new ModelAndView(REDIRECT_VIEW);
            } else {
                return null;
            }
        }
    
        /** {@inheritDoc} */
        public int getOrder() {
            return order;
        }
    
        
        public void setOrder(int num) {
            this.order = num;
        }
    }
    Then, in you Spring MVC servlet XML, you add the definition to register this resolver. So, you now have something like this:

    Code:
        <!-- Exception resolver that specifically handles the SWF NoSuchFlowException -->
        <bean id="endFlowHandler" class="com.usps.mgo.icoa.exceptionresolvers.NoFlowErrorResolver">
            <property name="order" value="1"/>
        </bean>
    
        <!-- Generic system/programming error resolver that handles the rest of the exceptions not handled by the app -->
        <bean id="genericErrorHandler" class="com.usps.mgo.icoa.exceptionresolvers.SystemErrorResolver">
            <property name="order" value="10"/>
        </bean>
    assuming that you have all your flow exceptions handled by your <exception-handler> definition, for any "out-of-flow" exceptions Spring will try to use the resolvers you have defined above. When such out-of-flow exception (not caught by SWF <exception-handler> ) is thrown, Spring will try to apply the resolver with the lower order first. If that exception is NoSuchFlowException, the first resolver will handle it. If not, the first resolver will ignore it and the exception will propagate further to the next registered resolver, which is, in the case of our example, is the ultimate resolver that catches everything else. So that exception will be caught and handled in the generic way, e.g. logged, processed somehow, and the user friendly error page will be displayed.

    If you need an example of how to use <exception-handler> for you flow exceptions, check out this: http://forum.springframework.org/showthread.php?t=54392
    Disregard the lost stack trace issue, it actually works fine, there must have been a problem with my build that caused the debugger to show null stack traces.


    Note that such strategy will take care of ALL your server-side/middle-tier exceptions. To catch the exceptions that occur inside JSPs (e.g. in custom tags; you are not using scriptlets in your JSPs, are you? ;-) ) you will need to define the exception filter(s) in your web.xml that will redirect to an error page - to avoid throwing nasty stack traces on the pages in the user's face.

    Hope this is helpful.

    P.S. I think it would be nice if Spring/SFW tutorials provided a short error-handling philosophy/guide with a good example of error handling in each application area. I think it would be very helpful considering that millions of Java programmers have been raised on Java's horrible checked exceptions philosophy that has corrupted their understanding of error handling all together. Most Java books are useless when it comes to explaining exceptions. I recently looked into Bruce Eckel's 4th edition of Thinking in Java (a great book by a great author whom I respect tremendously.) The only chapter in the book that hardly makes any sense is the one on exceptions. It's like Bruce is trying to please both sides at the same time, says one thing and contradicts himself in the next sentence. I was surprised b/c he actually wrote a very good blog questioning the checked exceptions philosophy back in 2003. Most authors are trying to be diplomatic on the issue in order not to alienate the checked exception zealots who would never admit that they were doing things wrong for years.
    Last edited by constv; May 24th, 2008 at 09:45 AM.

  5. #5

    Smile

    Thank you for your reply.

    You have given the answer with real example.

    Thanks alot.
    As you said , most of the docs are not covering exception handling strategies...

    In Spring we are expecting solutions to such usual probelms.. And I know that Spring is giving it... But as u said the real problem is that its really difficult to know such facilities with out docs...


    Thanks for your help,

    Cheers,
    Sudheesh

  6. #6
    Join Date
    May 2008
    Posts
    26

    Default Exception handling in webflow

    Hi,
    I am facing a number of issues,
    How to specify the exceptionhandler , how does it work?
    How to create the ViewSelection Object?

    how can I specify in exception handler that , when an excption occurs,
    It should go back to the page where the transition was triggered?
    Thanks in advance
    Shino

  7. #7
    Join Date
    Nov 2006
    Location
    Boston, MA
    Posts
    303

    Default

    Quote Originally Posted by Shino View Post
    Hi,
    I am facing a number of issues,
    How to specify the exceptionhandler , how does it work?
    How to create the ViewSelection Object?

    how can I specify in exception handler that , when an excption occurs,
    It should go back to the page where the transition was triggered?
    Thanks in advance
    Shino

    It sounds as if you posted your questions without actually reading this thread. I suggest that you read it carefully, and take a look at the complete working example of using SWF's <exception-handler> in http://forum.springframework.org/showthread.php?t=54392.
    That should answer your questions. The handle(..) method on an implementation of TransitionExecutingStateExceptionHandler takes a RequestControlContext object as one of the arguments. You may use the context object to track the last active view state in the flow, and program your handler to redirect to it. (You can always use flow execution listeners to put any additional tracking parameters you need into the flow scope upon entering each view state. Check the Javadoc and reference guide for more info on FlowExecutionListener.) Normally, you configure the handler to map different exception classes to state IDs using the add(exceptionclass, stateId) method. You will see that in the above-mentioned example the mappings are loaded via the handler bean definition in a Spring context XML. But if you want to direct to a dynamically obtained state ID, you'd have to override the handle(...) method that would, for example, retrieve the last view state's ID from the context and return the appropriate view selection, which would be a new instance of an implementation of the abstract ViewSelection class. If you read the javadoc you'd notice that it is an abstract class (i.e. no instances of it may be created.) However SWF provides concrete implementations of it - such as ApplicationView. So, you could return a new instance of ApplicationView(stateId, Map viewAttributes), where "viewAttributes" is a map of any objects you might want to pass to the view you are redirecting to. If you don't need to pass anything, that map may be empty or null. It is all in the SWF Javadocs. So, my last advice is: ALWAYS make sure you do read the available documentation and Javadocs on the subject. It is the only proper and efficient way to learn. Looking for quick answers without making any effort or analysis of your own may provide a quick fix here and there but won't make you a good programmer. HTH. Good luck,
    CV

  8. #8

    Smile

    Hi Shino,

    There are two cases that u must hanlde

    FlowExectution Exceptions
    --------------------------
    These are generated when an exception (user defined one) is thrown from
    a module level class.

    FlowExcecutor can handle such exceptions.





    It will reach to the EXCEPTION HANDLER (that u must specify in the flow xml)
    which is typically a FlowExecutionException handler.




    This handler can create EVENTS like showException , showBusinessException etc.. (Also put some Error messages
    based on the EXCEPTION ERROR CODES in appropriate scopes (usually in FLASH scope) which can be used in the JSPs)


    Handler will have following methods

    1) handles .. checks whether the handler can hande the specific FlowExcecutionException
    2) handles... actual exception handling code here

    RequestControlContext has a handleEventMethod. Generate event like new Event(this,"eventName);



    So in the flow xml you have to handle that transition
    <transition on "showBusinessException" to "someState">

    Now answer to your question
    (Give "someState" as your viewState in which your current screen is populated)


    Out Of the SWF Box EXCEPTIONS
    --------------------------------

    For eg : NoSuchFlow..Exception etc.

    Such Exceptions can not be handled by FLowExcecutor.

    Now dig deeper and find out that these are to be handled by SPRING MVC (if you are using SPring MVC as the MVC).

    For that u read from the top of this Thread.

    Use HandlerExceptionResolver, Ordered

    Cheers,
    Sudheesh
    Last edited by Sudheesh; May 24th, 2008 at 11:37 PM.

  9. #9
    Join Date
    May 2008
    Posts
    26

    Default

    Thanks for replies . That answered most of the questions. Now my question,Since I am transiting from one view state to an action state, and when an excepton occurs, how can I go back to the previous (view) state.
    or is it possible only thru <transition on-exception ?

  10. #10

    Smile

    Hi Shino,

    You dont need a transition on exception here

    You can use transition on "event"

    Since your exception handler will catch the EXCEPTION and do some thing and geneates say EVENT1
    Now what you need is to go to a previous screen

    <transition on "EVENT1" to "AvailabilitySearchViewState">
    use this transition in the ACTION STATE.

    and AvailabilitySearchViewState typically will be the VIEW state which handles your previous screen



    transition on exception can be used to handle some specific exceptions

    Suppose You are trying to use "webservices" and If you are getting an exception that WebserviceNotAccessible, then you can use
    transition on execption "webserviceNotAccessibleException" to "firstViewState"

    where firstViewState should be your VIEW STATE handling the first screen.

    All depends on your application.


    I think its better to use EXCEPTION HANDLERS and generate event and
    based on custom events route it.


    Use GLOBAL transition statements for Some common events.


    Cheers,
    Sudheesh
    Last edited by Sudheesh; May 25th, 2008 at 03:07 AM.

Posting Permissions

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