4 Replies Latest reply on Jun 11, 2013 1:27 AM by Brian Leathem

    How to make a better splash screen changing the message dinamically?

    Edilmar Alves Expert

      I have a test.xhtml like this:

       

      <h:body>

          <a4j:status name="statusSplash" onstart="#{rich:component('splash')}.show()" onstop="#{rich:component('splash')}.hide()" />

          <h:form id="formCad">

              <rich:popupPanel id="splash" modal="true" autosized="true" moveable="false" resizeable="false">

                  <f:facet name="header"><h:outputText value="Some title" /></f:facet>

                  <h:graphicImage value="/imagens/splash.gif" alt="Aguarde" />

                  <h:outputText value="#{t.msgSplash} ..." id="msgSplash"/>

              </rich:popupPanel>

              <a4j:poll id="pollSplash" enabled="#{t.pollEnabled}" interval="1000" execute="nenhum" render="pollSplash,splash,msgSplash"/>

              <a4j:commandButton id="buttonSplash" value="Open Splash"

                                                      action="#{t.openSplash}" status="statusSplash"

                                                      execute="pollSplash"

                                                      />

          </h:form>

      </h:body>

       

      When the user press button, a4j:status shows the popupPanel. I would like to change dinamically the outputText (with t.msgSplash) while some "slow" process occurs in the server. Something like: "Processing step 1...", "Processing step 2...", ... "Processing step X...".

       

      Then, I made TesteController.java like this, setting msgSplash = actual datetime, just to test the environment:

       

      package control.testes;

       

      import SubMacroUtils.FormatDate;

      import java.io.Serializable;

      import javax.inject.Named;

      import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.ConversationScoped;

       

      @Named(value="t")

      @ConversationScoped

      public class TesteController implements Serializable {

        private boolean pollEnabled;

        private String msgSplash;

       

        public boolean isPollEnabled() {

          return pollEnabled;

        }

       

        public void setPollEnabled(boolean pollEnabled) {

          this.pollEnabled = pollEnabled;

        }

       

        public String getMsgSplash() {

          msgSplash = FormatDate.getDateTime();

          System.out.println(msgSplash);

          return msgSplash;

        }

       

        public void setMsgSplash(String msgSplash) {

          this.msgSplash = msgSplash;

        }

       

        public String openSplash() {

          try {

            pollEnabled = true;

            Thread.sleep(10000);

            pollEnabled = false;

          } catch (Exception e) {

            e.printStackTrace();

          }

          return null;

        }

       

      }

       

      However, popupPanel shows just the first setup of msgSplash datetime, and never more change it. The a4j:póll didn't help too.

       

      Any ideas to solve this?

        • 1. Re: How to make a better splash screen changing the message dinamically?
          Edilmar Alves Expert

          I think the problem is that the main Thread of the TesteController becomes sleeping 10s, and it doesn't enable the JSF to call getMsgSplash to get a new value.

          But if I create a new Thread to run the "slow process", the main Thread returns null to the browser and the popupPanel is closed, because JSF understands main process finished.

          • 2. Re: How to make a better splash screen changing the message dinamically?
            Brian Leathem Master

            I'd have to play with this myself to be sure, but I would think Sleeping the thread for 10 seconds is likely to cause a timeout issue.

             

            Rather than thread.sleep, you should use a thread/executor to perform your business logic, then use a callback with RichFaces push to indicate when the process is complete.  Alternatively you could use a poll to check if the forked process is complete.

            • 3. Re: How to make a better splash screen changing the message dinamically?
              Edilmar Alves Expert

              This test I made to show the problem really has this problem. At the real application I created a Thread subclass, call myThread.start() to process and return null in JSF controller method. Then, the a4j:status disappeared and I only got to use the messages+a4j:poll to display the process status. The problem with this solution is that the user may click again the button to reprocess and made other interface interactions, because a4j:status disappeared.

               

              I have other project that is a Swing app (desktop). Then, I have full control of interface and internal process. I use the class SwingWorker to display a splash window + progress bar + labels showing the status. Then, the splash window is modal, and it doesn't allow the user to interact to the interface until the full thread background process ends. But the user doesn't have the doubt about what is happening, the messages are clear for him. In the web world, I didn't get to program the same behaviour.

              • 4. Re: How to make a better splash screen changing the message dinamically?
                Brian Leathem Master

                In your backing bean, use an Executor and a FutureTask to set a callback.  In your callback update a property of your backing bean, and use a4j:poll (or even better, invoke an a4j:push notification from your callback) to update your page.

                 

                Even better, if you are using Java EE use the Java EE 6 @Asynchronous annotation to take care of the threads for you, and guarantee application portability.