10 Replies Latest reply on Mar 30, 2011 4:29 AM by multanis

    Request Errors Handling - actionlistener

    multanis

      Hello,

       

      I just noticed that if an exception occurred in my action listener method, there is nothing displayed to the client side.

      So I decided to fix this using

      A4J.AJAX.onError = function(req, status, message) { alert('CRASH !');}

       

      But it doesn't do anything ... The only way it works is when I shutdown my application (so I got a page not found)

       

      I've added in my web.xml (I don't know if this is required but it is written in the dev guide):

      <context-param>
          <param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name>
          <param-value>true</param-value>

      </context-param>

       

      In my jspx:

      <a4j:commandLink value="Save" actionListener="#{myBean.save}" eventsQueue="default"/>

       

      MyBean.java:

      public void save(ActionEvent event) {

           throw new NullPointerException();

      }

       

      I'm using richfaces 3.3.3-FINAL/Spring/Facelet (NOT MyFaces ;-) )

       

      Many thanks for your light !

       

       

      Update:

       

      I succeeded to make it work, but it is a bit tricky and I'm not sure of the consequences:

      I had to write my own AjaxViewRoot to redefine the processEvents method to let it throw AbortProcessingException.

       

      faces-confix.xml:

           <component>
              <component-type>javax.faces.ViewRoot</component-type>
              <component-class>my.package.CustomViewRoot</component-class>
          </component>

       

      CustomViewRoot:

          @Override
          public void processEvents(FacesContext context, EventsQueue phaseEventsQueue, boolean havePhaseEvents) {
              FacesEvent event;
              while (havePhaseEvents) {
                  try {
                      event = (FacesEvent) phaseEventsQueue.remove();
                      UIComponent source = event.getComponent();
                      source.broadcast(event);
                  } catch (NoSuchElementException e) {
                      havePhaseEvents = false;
                  }
              }
          }

       

      Is this acceptable ? Why is this exception catched in AjaxViewRoot ?


        • 1. Request Errors Handling - actionlistener
          nbelaevski

          Nicolas,

           

          That's how JSF 1.2 handles exception. See UIViewRoot sources for another example of such behavior. JSF 2.0 introduced special handler for exceptions.

          • 2. Request Errors Handling - actionlistener
            multanis

            Nick,

             

            Thanks for your lights !

             

            So is my solution correct ? Or is this dangerous for any reason and will break something later ?

            • 3. Request Errors Handling - actionlistener
              nbelaevski

              Nicolas,

               

              Looking at the code I see that some things can break if AbortProcessingException won't be caught - e.g. phase listeners invocation at view root. I'd suggest to take a look at MyFaces 1.2 code - they have implemented exception handler as extension.

              • 4. Re: Request Errors Handling - actionlistener
                multanis

                Nick,

                 

                I had a look in MyFaces 1.2 code but as far as I understand, they don't do anything with the AbortProcessingException.

                Here is the code from UIViewroot (in myfaces-api-1.2.10):

                 

                    private void _broadcastForPhase(PhaseId phaseId)
                    {
                        if (_events == null)
                        {
                            return;
                        }
                
                        boolean abort = false;
                
                        int phaseIdOrdinal = phaseId.getOrdinal();
                        for (ListIterator<FacesEvent> listiterator = _events.listIterator(); listiterator
                                .hasNext();)
                        {
                            FacesEvent event = listiterator.next();
                            int ordinal = event.getPhaseId().getOrdinal();
                            if (ordinal == ANY_PHASE_ORDINAL || ordinal == phaseIdOrdinal)
                            {
                                UIComponent source = event.getComponent();
                                try
                                {
                                    source.broadcast(event);
                                }
                                catch (AbortProcessingException e)
                                {
                                    // abort event processing
                                    // Page 3-30 of JSF 1.1 spec: "Throw an
                                    // AbortProcessingException, to tell the JSF implementation
                                    // that no further broadcast of this event, or any further
                                    // events, should take place."
                                    abort = true;
                                    break;
                                }
                                finally
                                {
                                    try
                                    {
                                        listiterator.remove();
                                    }
                                    catch (ConcurrentModificationException cme)
                                    {
                                        int eventIndex = listiterator.previousIndex();
                                        _events.remove(eventIndex);
                                        listiterator = _events.listIterator();
                                    }
                                }
                            }
                        }
                
                        if (abort)
                        {
                            // TODO: abort processing of any event of any phase or just of any
                            // event of the current phase???
                            clearEvents();
                        }
                    }
                
                    private void clearEvents()
                    {
                        _events = null;
                    }
                

                 

                Maybe I'm just not looking at the ritght place...

                • 5. Request Errors Handling - actionlistener
                  nbelaevski

                  Nicolas,

                   

                  Compare MethodExpressionActionListener#processAction(ActionEvent) in Mojarra and MyFaces. In Mojarra you'll see that they are wrapping all exceptions into AbortProcessingEvent, while MyFaces doesn't do that.

                  • 6. Re: Request Errors Handling - actionlistener
                    multanis

                    Nick,

                     

                    Many thanks for your answers !

                     

                    As I don't know how to change the MethodExpressionActionListener#processAction implementation, I've modified my CustomViewRoot as follow:

                     

                         public void processEvents(FacesContext context, EventsQueue phaseEventsQueue, boolean havePhaseEvents) {
                            FacesEvent event;
                            while (havePhaseEvents) {
                                try {
                                    event = (FacesEvent) phaseEventsQueue.remove();
                                    UIComponent source = event.getComponent();
                                    try {
                                        source.broadcast(event);
                                    } catch (AbortProcessingException e) {
                    
                                        Throwable cause = e.getCause();
                                        if (cause != null && cause instanceof AbortProcessingException) {
                                            UIComponent component = event.getComponent();
                                            String id = null != component ? component.getClientId(context) : "";
                                            logger.error("Error processing faces event for the component " + id, e);
                                        } else
                                            throw e;
                                    }
                                } catch (NoSuchElementException e) {
                                    havePhaseEvents = false;
                                }
                            }
                    
                        }
                    

                     

                    I think this is the closest I can do without redefining MethodExpressionActionListener, but if you know an easy way to do it, I will do it ;-)

                     

                    Thanks again !

                    • 7. Request Errors Handling - actionlistener
                      nbelaevski

                      Another solution can be not to use EL-expression but implement listener interface.

                      1 of 1 people found this helpful
                      • 8. Request Errors Handling - actionlistener
                        multanis

                        I'm probably a bit dumb but I don't know how to do that.

                        Is this what you are talking about ?

                         

                        <h:commandButton value="Add">  
                             <f:actionListener type="com.mycompany.MyListener" />
                        </h:commandButton>

                         

                        And com.mycompany.MyListenerListener must implements ActionListener.

                        • 9. Request Errors Handling - actionlistener
                          nbelaevski

                          Yes, that's it.

                          • 10. Request Errors Handling - actionlistener
                            multanis

                            Ok many thanks for your help !

                             

                            (I will not use the ActionListener interface because I don't want to change all my actionlistener but I keep it in mind for my next project)