1 Reply Latest reply on Mar 31, 2011 6:10 AM by ilya_shaikovsky

    Bug in RichFaces 3 <a4j:queue> can cause requests to be executed twice

    noxhoej

      Hi

       

      I think I have discovered a serious bug in <a4j:queue> which can relatively easily cause requests to be executed twice.

       

      First you need to use <a4j:queue> on your page.

      Second you need a form with an <a4j:commandButton> which is marked with <s:defaultAction/>.

      Third you need an input field, e.g. an <h:inputText>, which will fire an AJAX requests when it looses focus, i.e. with an <a4j:support event="onblur"/> (or an <a4j:support event="onchange"/> where you have typed som text).

      Fourth you need an <a4j:status> which brings up a modal panel (hence causing the input field to loose focus), and use this <a4j:status> on the <a4j:commandButton>.

      Finally, you hit "Enter" while the focus is placed in the input field.

       

      Then you will see that the AJAX request (and related action) for the <a4j:commandButton> is sent twice.

       

      The reason is that the first AJAX request (the one for the <a4j:commandButton>) is pushed onto the queue, the queues submitFirst() function is called and it immediately starts processing and sending the AJAX request. Just before A4J.AJAX.SubmitQuery() sends the actual XMLHttpRequest, it brings up the "busy" modal panel which "steals" the focus from the input field. This causes the <a4j:support> on the input field to fire and push a new AJAX request on the queue. But pushing something on the queue results in the queues submitFirst() to be called - and the first request on the queue is still the <a4j:commandButton>s request. The queues submitFirst() function does have a guard against submitting a request already sent (the submit code is surrounded by "if (!firstItem.request) {...}") but the request attribute on a queue entry isn't set until A4J.AJAX.SubmitQuery() returns - which it hasn't done yet for the <a4j:commandButton>s request. And hence the request is sent of to server. And when A4J.AJAX.SubmitQuery() finishes putting up the "busy" modal panel it sends of the request once again and you have now gotten your request submitted twice.

       

      I have attached a FireBug stack trace, which shows how the <a4j:commandButton>s request is sent when the <a4j:supports> request is pushed onto the queue.

      a4jqueue_stack.png

       

      The following XHTML page can be used to reproduce the error:

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:rich="http://richfaces.org/rich"
            xmlns:s="http://jboss.com/products/seam/taglib"
            xmlns:a4j="http://richfaces.org/a4j">
      <a4j:queue/>
      <body>
      <h:form>
          <h:inputText id="Name">
              <a4j:support event="onblur"/>
          </h:inputText>
          <a4j:commandButton id="CreateButton" value="Create" status="inProgressStatus">
              <s:defaultAction/>
          </a4j:commandButton>
      </h:form>
      <rich:modalPanel id="inProgressPanel" autosized="true" shadowDepth="0" resizeable="false">
          Working...
      </rich:modalPanel>
      <a4j:status id="inProgressStatus"
                  onstart="Richfaces.showModalPanel('inProgressPanel')"
                  onstop="Richfaces.hideModalPanel('inProgressPanel')"/>
      </body>
      </html>
      

       

      The workaround we have currently had to implement, is to wrap the code of the <a4j:status> onstart in a setTimeout(function(){...},0) so that the modal panel won't be put up until after the <a4j:commandButton>s request is actually sent...

       

      Regards,

       

      Nicholas Oxhøj