5 Replies Latest reply on May 13, 2010 3:17 AM by Nikolay Elenkov

    Separate Thread Assistance

    Osian Hughes Newbie

      Hi,


      I have a situation where I need to, in a separate thread, create lots of new objects (hibernate), and then once complete, redirect the user to a new page.


      I can think of doing this in a separate thread, so that I can show a progress bar on screen, and then once complete, redirect the user, but I am not sure of how to do this in Seam.  Should I use Observer, Asynchronous?? or any other ways, or just simple Runnable threads?


      I am basically looking for ways to be able to achieve this, so any pointers, or preferably examples, are more than welcome,


      Thanks,


      Osian

        • 1. Re: Separate Thread Assistance
          Nikolay Elenkov Master

          Use an @Asynchronous method. That way you can take advantage of (most) Seam features. Once you start a separate thread though, you cannot access session/conversation. Depending on your concrete requirements, you can use and application-scoped event/observer to notify clients or just poll at client side. Search the forum for details.


          HTH

          • 2. Re: Separate Thread Assistance
            Osian Hughes Newbie

            Hi,


            I didn't see the reply until now, but I have been playing with the @Asynchronous and @Observer stuff, and this replaces the thread implemtation that I was working with. 


            My only problem now, is that the seam component who initiated the asynchronous call now needs to be told that the method has been completed (i.e. stop the progress bar and display a popup or simply redirect the user to a new page), I have tried a few different things, but I can't seem to get it to work. 


            It is a little dangerous for me to have application scoped observers/events, because there may be other users on the same page and wanting to perform the same thing.


            Any ideas how I can get the instance of the component that initiated the call who is in Conversation scope?


            Thanks,


            Osh

            • 3. Re: Separate Thread Assistance
              Nikolay Elenkov Master

              Osian Hughes wrote on May 11, 2010 14:59:


              It is a little dangerous for me to have application scoped observers/events, because there may be other users on the same page and wanting to perform the same thing.



              The idea is that the application-scoped observer will relay the result to interested parties with another event.



              Any ideas how I can get the instance of the component that initiated the call who is in Conversation scope?


              You can't, but you can use richfaces push or similar to notify the UI. There are examples on the forum of how to do it.


              • 4. Re: Separate Thread Assistance
                gonzalad Apprentice

                What about something like this code ?


                Your Jsf action component calls a conversation scoped component.


                This component calls an asynchronous component and passes itself as method argument.


                Limitations I know :



                • you cannot access conversation / session / page scoped from handler component (where I used Asynchronous annotation).

                • don't handle loadbalancing with non sticky session or failover scenario.




                Here's the code :


                @Name("progressBarBean");
                @Scope(ScopeType.CONVERSATION)
                public class ProgressBarBean implements Serializable {
                     @In
                     private ProgressBarHandler progressBarHandler
                     private int currentValue=-1;
                     
                     public void startProcess () {
                          progressBarHandler.startProcess (this);
                     }
                     
                     public int getCurrentValue() {
                          return currentValue;
                     }
                     
                     public void setCurrentValue(int value) {
                          this.value=value;
                     }
                }
                




                @Name("progressBarHandler");
                public class ProgressBarHandler implements Serializable {
                     @Asynchronous
                     public void startProcess (ProgressBarBean progressBarBean) {
                          for (int i=1; i<101; i++) {
                               try {
                                    Thread.currentThread().sleep(100L);
                               } catch (Exception err) {
                               }
                               progressBarBean.setCurrentValue(i);
                          }
                     }
                }
                





                <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                    xmlns:ui="http://java.sun.com/jsf/facelets"
                    xmlns:h="http://java.sun.com/jsf/html"
                    xmlns:f="http://java.sun.com/jsf/core"
                    xmlns:a4j="http://richfaces.org/a4j"
                    xmlns:rich="http://richfaces.org/rich">
                
                    <h:form>
                        <a4j:outputPanel id="progressPanel">
                            <rich:progressBar value="#{progressBarBean.currentValue}"
                                interval="2000" label="#{progressBarBean.currentValue} %"
                                enabled="#{progressBarBean.enabled}" minValue="-1" maxValue="100"
                                reRenderAfterComplete="progressPanel">
                                <f:facet name="initial">
                                    <br />
                                    <h:outputText value="Process doesn't started yet" />
                                    <a4j:commandButton action="#{progressBarBean.startProcess}"
                                        value="Start Process" reRender="progressPanel"
                                        rendered="#{progressBarBean.buttonRendered}"
                                        style="margin: 9px 0px 5px;" />
                                </f:facet>
                                <f:facet name="complete">
                                    <br />
                                    <h:outputText value="Process Done" />
                                    <a4j:commandButton action="#{progressBarBean.startProcess}"
                                        value="Restart Process" reRender="progressPanel"
                                        rendered="#{progressBarBean.buttonRendered}"
                                        style="margin: 9px 0px 5px;" />
                                </f:facet>
                            </rich:progressBar>
                        </a4j:outputPanel>
                    </h:form>
                </ui:composition>
                






                • 5. Re: Separate Thread Assistance
                  Nikolay Elenkov Master

                  Gonzalez Adrian wrote on May 12, 2010 23:05:


                  What about something like this code ?

                  Your Jsf action component calls a conversation scoped component.

                  This component calls an asynchronous component and passes itself as method argument.

                  Limitations I know :


                  • you cannot access conversation / session / page scoped from handler component (where I used Asynchronous annotation).

                  • don't handle loadbalancing with non sticky session or failover scenario.






                  • if the conversation ends before the async method finishes, the progressBarHandler handler will be destroyed, and you will get an error.