Howto avoid concurrent call to conversation problem in Seam


It’s very common that in your Seam web-application you will get “HTTP Status 503 – Concurrent call to conversation” error and an exception stacktrace if you in debug-mode.

That can be caused by several reasons, one of them is double click on the ajax-link like <a4j:commandLink action=”#{myAction.action} value=”Simple link”/>
A4J/RichFaces allow the solultion for that problem – you have just to specify eventsQueue attrbute
<a4j:commandLink action=”#{myAction.action} value=”Simple link” eventsQueue=”myQueue” />
In that way even if user will click on that link twice – the events (requests) will be sent only one-by-one

As a side-note it worth also to specify “requestDelay” (specify the time the request will wait in queue before send) and ignoreDupResponses=”true” (A4J will ignore ajax response if another “similar” request is in queue). It’s worth for everyone to read that in RichFaces docs

But, it not always solve your problem – users are unpredicted creatures and they can click on your h:commandLink (which is not ajax and can’t be set to queue) or even on some link which actually triggers an action.  So,  you are still not safe since user have a lot of ways to break your application by click on another element which will trigger action inside current conversation.

Besides the fact that using a4j-queues is a good practice (it improve the overall perfomance of application also) – to be absolutely safe you have to disable ALL THE LINKS in the document or make them inaccessible for the user. And the solution exists, it rather simple but very powerful. So what you have to do – is to show <rich:modalPanel> once user is click on the link (or start ajax request with <a4j:support>) and hide it after ajax-response is complete. For h:commandLink or h:commandButton – you don’t have to worry about hiding it, since once new page will be loaded rich:modalPanel will be disappeared automatically (since it belongs to previous page/DOM-document). Once rich:modalPanel is shown – it makes impossible to use any navigation elements on the page except the elements on that form itself.

You can even automatically enable it for all your ajax-request’s with help of <a4j:status> and “onstart” “onstop” handlers.  In the example below the onRequestStart() function is called by onstart handler of aj4:status component. In the example below

//javascript
var waitDialogShown = false;
var useTimerBeforeShowWaitDialog = true;
var waitDialogTimeout = 50;
var waitDialogTimer;

function showWaitDialog() {
    //avoid attempt to show it if it is already shown
    if (!waitDialogShown) {
        Richfaces.showModalPanel('wait-dialog');
        waitDialogShown = true;
    }
}

function onRequestStart() {
    if (useTimerBeforeShowWaitDialog) {
        waitDialogTimer = setTimeout("showWaitDialog();", waitDialogTimeout);
    } else {
        showWaitDialog();
    }
}
function onRequestEnd() {
    if (waitDialogShown) {
        Richfaces.hideModalPanel('wait-dialog');
        waitDialogShown = false;
    } else if (useTimerBeforeShowWaitDialog && waitDialogTimer) {
        clearTimeout(waitDialogTimer);
    }
}
<a4j:status onstart="onRequestStart()" onstop="onRequestEnd()"/>

<rich:modalPanel id="wait-dialog" resizeable="false" autosized="false" width="200" height="65" moveable="false" shadowOpacity="0">
  <f:facet name="header">One moment please..</f:facet>
  <h:outputText value="Your request is being processed."/>
</rich:modalPanel>

<!-- Your wait dialog can be invisible for the users if you don't want your screen blink with that dialog on each request -->
<rich:modalPanel id="wait-dialog-invisible" resizeable="false" autosized="false"
width="10" height="10" moveable="false" left="-100" top="-100" shadowOpacity="0"/>

And if you don’t want to apply that for every component or want to modify prevention behavior you can do one of the:

  1. Explicitly define onclick function of your links/buttons
    <h:commandButton onclick=”onRequestStart();” value=”Button”/>
    for ajax you also have to define oncomplete to hide the modalPanel, otherwise your browser-page will be blocked
    <a4j:commandButton onclick=”onRequestStart();” oncomplete=”onRequestEnd();” value=”Button”/>
  2. Define a4j:status with id and forceId=”true” and use status attribute of your ajax components to specify the a4j:status component they will use.
   <a4j:status id="waitStatus" forceId="true" onstart="onRequestStart()" onstop="onRequestEnd()"/>
   <a4j:commandLink status="waitStatus"/>

In reality things are more complex than we think about them – you may also take a look at the related article
How to avoid primary page conversation timeout on background requests in Seam. Hacking around Seam request lifecycle – it describe another problem and solution to it. When on the page you have background process (periodically executed ajax requests) – they can also lead to conversation timeout and kill your primary conversation.

https://www.facebook.com/achorniy

Tagged with: , , , , , ,
Posted in Software Development, Tips and Tricks
36 comments on “Howto avoid concurrent call to conversation problem in Seam
  1. nmatrix9 says:

    Thank you.

  2. nmatrix9 says:

    What about a seam button or s:button? What if I don’t want to explicitly state in the attribute to use waitstatus?

    • Andrey Chorniy says:

      It’s interesting question,
      s:button like s:link and h:commandLink require you to define onclick listener to show the prevention-dialog.
      I think it is possible to define onclick handler-function for all elements in your HTML-DOM, for example with JQuery

      jQuery(document).ready(function () {
        var elements_selector = "a, :button";
        jQuery{elements_selector}.click( function(){ 
            onRequestStart();
          }
        );
      }
      // elements_selector can be modified, 
      //for example if you want to mark the elements you want to have such prevention 
      //you can define extended JQuery selector, like
      var elements_selector = "a .prevented, :button .prevented";
      //and add "prevented" class to the elements on which you want the to have that onclick-handler
      // <s:button styleClass="prevented" ... />
      
      • Shivam says:

        I have applied

        and

        One moment please..

        and the javascript as described.
        Surprised it is working in Mozilla and Chrome but not in IE. There is no wait dialog panel. And again 2 request are getting submitted on fast clicks. In result getting the exception:
        java.lang.IllegalStateException: duplicate Id for a component .

        Could you please help me?

  3. Chris says:

    Hi

    Im getting this error when eg. do filtering rich:extendedDataTable’s column with onkeypress event support, any idea how avoid this behavior? changing concurrent-request-timeout parameter doesn’t help.

    • Andrey Chorniy says:

      Chris, could you please post your code ?
      I suppose you have to define ajax-attributes “eventsQueuse”, “requestDelay” and “ignoreDupResponses”. Please take a look at the description of that ajax-attributes and some more details and examples of ajax attirbutes here
      In the shoort – just define them all for your

      <rich:extendedDataTable eventsQueue="myTableQueue" requestDelay="100" ignoreDupResponses="true">
      </rich:extendedDataTable>

      or inside your

      <a4j:form eventsQueue="myFormQueue" requestDelay="100" ignoreDupResponses="true">
      </a4j:form>
      

      and it will be applied for all form components

  4. nmatrix9 says:

    Hey Andrey,

    Just realized that there may be some issues where you may want to have the waitstatus be skipped for certain richfaces jsf components, i.e. (maybe a radiobutton, inputtext). How would you implement a flag where the wait status ignores those components or maybe a certain “family of components”?

    • Andrey Chorniy says:

      If we want to support “familty of components” we will need to put an family-identifier on each richfaces component.
      So, if we are talking about richfaces components it could be done with the “status” attribute

      <a4j:status id="waitStatus" forceId="true" onstart="onRequestStart()" onstop="onRequestEnd()"/>
      <a4j:commandLink status="waitStatus"/>
      

      if we are talking non-jsf or non-richfaces components we could bind onclick handlers automatically with jQuery. To define component-families we also have to define family-identifier for each element (for example by defining “class” attribute and using it as additional filter in jQuery selector or code).
      That way you may define a lot of families like “block-onclick” (and display blocking popup) “show-notfication-onclick” and display non-blocking notfication status
      So, the approach in short is simple

      1. define the family identifier
      2. Use that identifier in the code which binds the onclick listener to exclude or include components in the set of binded elements

      See also JQuery attribute selectors

  5. Hi i got a question. The script etc works fine.

    However if i have the script run on a link, goes to a page and then hit the browser backbutton. the modalPanel is shown. even thou it were closed by the script before.

    Got any solution to this?

    • Andrey Chorniy says:

      Hmm, intresting side effect, I never experience (and actually I never reproduce it before)
      Does it happens in all browsers ? IE/FF/Safari ?

      I think it is possible to define “ondocumentload” dispatcher with JQuery on the page template, so it will be executed every time page is loaded by the browser
      for example

      <script type="text/javascript">
      jQuery(document).ready(function(){
          hideBlockingModalPanel();
      });
      </script>
      
      
  6. Sorry i just have the problem in Firefox. However the java script didn’t work there.

    Tried other java script and other stuff to reload the page but seam like it everything is disabled and nothing runs while the window is inactive.

    //Joachim

    • Andrey Chorniy says:

      Yeah, it looks like it is FF, Opera and Safari issue
      They just not trigger document.onload for back and forward button and restore the cached state of the page, that’s why you see the modal-panel. At least I understand why now 😉
      Take a look at the page http://www.thomasfrank.se/when_onload_fails.html
      They describe this issue in details and provide a solution to it. Things become a bit more complicated, but at least it should be developed only once 🙂

  7. Santiago says:

    Hi everyone,
    I get a concurrent call to conversation problem in Seam, when I tried to sort a column. I had many tables, so I created a generic table component.
    Before to migrate my tables to the new component I had something like this:

    And the multiple clicks on a sortable column worked well.
    After the migration of the tables to the new table component, I have something like this:

    a rich table
    column
    dataColumn
    sortableDataColumn
    rich column

    And the sortableDataColumn is the following:

    The sortByExpression indicates the property name to sort.
    And when I tried multiple clicks on the a sortable column, then I get a call to conversation problem.
    I also tried to change the h:form on the generic table component to a a4j:form:

    but it did not work.
    And when I tried adding a ajax support on the sortableDataColumn:

    it also did not work.

    Thanks in advance!!

    • Andrey Chorniy says:

      Hi Santiago,
      could you please show your code (whole code, so your example could be easily started) ? I can’t suggest anything without it, since i don’t see how it organized and what can cause the problem.
      As well – could you include another page which also show the previous solution which works for you?

  8. EswaraMoorthyNEC says:

    Hi everyone,

    I want to call rich:modalPanel every ajax request. But in my application more than 50 pages. Each pages have minimum 5 to 10 component.

    Suppose i follow the above procedure, in my application
    i want to add status=”” attribute for every component.

    But i feel, its difficult one.

    because, in future, suppose i don’t want this wait modalpanel process
    then that time, i want to delete status=”” attribute to all component.

    Is there any otherway to call this rich:modalPanel like ‘your request is processing….’ for every ajax request?

    otherwise, is possible to call this rich:modalPanel from listener?

    Help me about this?

    • Andrey Chorniy says:

      You can just put <a4j:status onstart=”onRequestStart()” onstop=”onRequestEnd()”/> in your template.xhtml (used by all your pages) – so it will be automatically used for all your ajax-requests. you actually don’t need to add “status” attribute with that approach and in the future you can just remove that “a4j:status” from your template (probably use it only for particular pages)

      You only need to set the “status” attribute for ajax-components if you want to change the behavior for particular components or want to enable only “several” ajax-components to show that status/modalPanel
      <a4j:status id=”waitStatus” forceId=”true” onstart=”onRequestStart()” onstop=”onRequestEnd()”/>
      <a4j:commandLink status=”waitStatus”/>

      Please check this a4j:status LiveDemo and this a4j:status DeveloperGuide for more details on a4j:status

  9. Enrico says:

    Very useful article, but i’ve got a few questions

    1) i have some pages that update the data shown in the pages by calling void or null returning actions. using this method the pages are not refreshed when the request ends and i can’t figure how to refresh them

    2) i’ve some very basic js function on a button, onclick=”javascript: return controlArea();” showing the user a modal confirm box. If i use a a4j:commandButton i ged a weird error, looks like the page redirecs to http://localhost:8080/myApp/myModule/undefined“. i have no clue how to fix this too.

    Thanks for your answers

    Enrico

    • Andrey Chorniy says:

      Hi Enrico,
      uhmm…
      1) looks like your are doing something wrong with your JSF/backing-code. the approach described doesn’t change the way your page is being refreshed, so you still can have . Your action should have “void” return type (most typical usage)
      2) you probably have to show rich:modalPanel in your button which will show the confirm fialog (rich modal-panel) in which you may have a confirm button which will actually call the server-action, close itself (and probably block the screen). You also may use java-script to emulate a click on any element(button)

  10. […] Posts Howto launch android camera using intentsHowto avoid concurrent call to conversation problem in SeamHow to use autofocus in Android « Free […]

  11. Oscar says:

    Excellent, very explained, thanks

  12. monye says:

    How about users clicking on a tab? How to you deal with this scenario?

  13. togotutorRob says:

    Hi Andrey,

    One moment please..

    I tried this code but I see the progress modal panel (very first time ONLY), whenever I restart the server, else i dont see it. I have tried and got the same result on all browsers.

    • Andrey Chorniy says:

      it’s interesting issue, could you inspect the problem in details ? Debug app in firebug and see who show the modal-panel ?
      it is shown in the javascript function showWaitDialog()

  14. Andrey Chorniy says:

    In reality things are more complex than we think about them – you may also take a look at the related article
    How to avoid primary page conversation timeout on background requests in Seam. Hacking around Seam request lifecycle – it describe another problem and solution to it. When on the page you have background process (periodically executed ajax requests) – they can also lead to conversation timeout and kill your primary conversation.

  15. Raj says:

    Hi,

    I am using JSF and SEAM, I am facing problem. Lots of pages in application and menu also in application. One page having one or more than button and links in jsf xhtml. If user click on any link or button and then click on other link on button, whereas first request not yet complete. In this condition page crashed and throw “No active conversation” stack trace error. Please help me, how can handle this problem,

    • Andrey Chorniy says:

      your problem looks very similar to the problem described in that article, however in my case I see “concurrent call to conversation”
      The solution shown in the article is the solution which prevents user to make click on one link, and after that on another (so two concurrent requests in same conversation exists). I believe it also should work for your case (since you will remove the root of problem)
      Could you please show the code used for that two buttons ? (JSF and java if possible)

  16. Rodrigo Rosa says:

    Thanks, man! This helps me a lot!

  17. Patrick Tolentino says:

    worked like magic 🙂 thanks!!

  18. Valentin Lucchini says:

    Hi,

    I may be digging up an old post but I have a problem using your solution…
    I’m kinda new to richfaces and I don’t know if there is any way around my problem.
    Please excuse my poor english, I’m French !

    Here it is :
    I have a suggestionBox and I use the modalPanel to avoid concurrent calls on this component. My problem is : the columns of the suggestionBox does not appear after the request has stopped. I mean, I type my words, the modalPanel just appears, it loads, and when the modalPanel disappears, my suggestionBox is the same as before.

    I know my request is good because it was working perfectly before I add the modalPanel.

    I’ve read on the internet that it might be a question of focus on the suggestionBox but I can’t fix this issue even when I keep the focus on the input.

    Do you know any way around this ?

    Thanks

    • Hm, i believe you shouldn’t use modal panel to prevent it for suggestion box – at least it kill ui experience for user
      It worth to set the requestDelay, ignoreDupResponses and minChars for it

  19. Ambose says:

    Or, on the form :
    onsubmit=”$(document).ajaxStop(function() {return true;});”

  20. Lashonda says:

    Oh my goodness! Amazing article dude! Thanks, However
    I am having difficulties with your RSS. I don’t know why I
    am unable to join it. Is there anybody else having the
    same RSS issues? Anybody who knows the answer will you kindly respond?
    Thanx!!

Leave a reply to Andrey Chorniy Cancel reply