6 Replies Latest reply on Jun 2, 2010 3:35 PM by ssamayoagt

    Conversation created until POST

    ssamayoagt
      Im doing some simple testing and found that if there is no POST in the WEB tier the conversation is created each time getter method runs.

      This is my BB code:

      @Named
      @ConversationScoped
      public class TestList1 implements Serializable {

           private static final long serialVersionUID = -4209869420239041827L;

           private @Inject
           Conversation conversation;

           private List<Personal> listaPersonal;

           public TestList1() {
           }

           public List<Personal> getListaPersonal() {
                System.out.println("getListaPersonal()");
                if (listaPersonal == null) {
                     System.out.println("getListaPersonal() listaPersonal == null");
                     conversation.begin();
                     System.out.println("getListaPersonal() conversation.id " + conversation.getId());
                     listaPersonal = new ArrayList<Personal>();
                     for (int i = 0; i < 20; i++) {
                          Personal p = new Personal();
                          p.setId(i);
                          p.setNombre("Empleado " + i);
                          p.setDias(15);
                          listaPersonal.add(p);
                     }
                }
                return listaPersonal;
           }
      }

      And my view is:

      <!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:f="http://java.sun.com/jsf/core"
           xmlns:ui="http://java.sun.com/jsf/facelets"
           xmlns:rich="http://richfaces.org/rich"
           xmlns:a4j="http://richfaces.org/a4j">

      <body>
      <h:form>
           <rich:dataTable var="p" value="#{testList1.listaPersonal}" rows="10"
                id="lista">
                <rich:column>
                     <f:facet name="header"></f:facet>
                     <h:selectBooleanCheckbox value="#{p.seleccionado}">
                          <a4j:support event="onclick" reRender="dias" />
                     </h:selectBooleanCheckbox>
                </rich:column>
                <rich:column>
                     <f:facet name="header">ID</f:facet>
                     <h:outputText value="#{p.id}" />
                </rich:column>
                <rich:column>
                     <f:facet name="header">Nombre</f:facet>
                     <h:outputText value="#{p.nombre}" />
                </rich:column>
                <rich:column>
                     <f:facet name="header">Dias</f:facet>
                     <h:inputText value="#{p.dias}" required="true" id="dias"
                          disabled="#{!p.seleccionado}">
                          <f:convertNumber />
                          <a4j:support event="onblur" />
                     </h:inputText>
                     <rich:message for="dias" />
                </rich:column>
                <f:facet name="footer">
                     <rich:datascroller for="lista" />
                </f:facet>
                <rich:column>
                     <a4j:commandButton value="Borrar" action="#{testList1.borrar}">
                          <f:setPropertyActionListener target="#{testList1.personalBorrar}"
                               value="#{p}" />
                     </a4j:commandButton>
                </rich:column>
           </rich:dataTable>
           <h:commandButton value="POST" />
           <rich:messages />
      </h:form>
      </body>
      </html>

      Log for data table navigation is:

      getListaPersonal()
      getListaPersonal()
      getListaPersonal()
      getListaPersonal() listaPersonal == null
      getListaPersonal() conversation.id 3
      getListaPersonal()
      getListaPersonal()
      getListaPersonal()
      getListaPersonal() listaPersonal == null
      getListaPersonal() conversation.id 4
      getListaPersonal()
      getListaPersonal()
      getListaPersonal()
      getListaPersonal() listaPersonal == null
      getListaPersonal() conversation.id 5
      getListaPersonal()
      getListaPersonal()


      Until I click on the button "POST" (which makes post...) the view uses the conversation's BB.

      Im doing this on tomcat 6.0.26 + Weld 1.0.1 + mojarra 2.0.2 + facelets 1.1.15

      Why conversation is created until POST?

      Thanks.
        • 1. Re: Conversation created until POST
          nickarls

          Hmm. The conversations are promoted to non-transients since you are able to output the ID:s. Could it be something with the cid not being appended properly for ajax requests? The navigation for that table is ajax-based, right? But one would think a request is a request and it would go down the same code path...

          • 2. Re: Conversation created until POST
            ssamayoagt
            > The navigation for that table is ajax-based, right?

            Yes.

            But ci is appended after POST, ajax request dont append it before.
            Should ajax components be aware of creation of the conversation?
            It is responsability of CDI, JSF or component?

            Regards.
            • 3. Re: Conversation created until POST
              nickarls

              Sergio Samayoa wrote on May 15, 2010 00:59:

              Should ajax components be aware of creation of the conversation?
              It is responsability of CDI, JSF or component?


              Good question. Pete? Dan? Lincoln?

              • 4. Re: Conversation created until POST
                lincolnthree

                OK, so here's what's going on.


                Keep in mind the following truths about JSF and AJAX:



                1. AJAX requests use the rendered form action=URL for all AJAX events.

                2. The form action URL is rendered before any child-components are rendered



                So on GET requests the getter method is called after the form URL is rendered, thus the conversation is not yet marked long-running, and the conversation ID is not appended to the form action URL. This means that all subsequent AJAX requests will also not have the CID, because they are using the form action URL.


                When you click POST, JSF needs to re-generate the UIViewRoot and the DataModel for the UIDataTable, meaning it calls your getter method during the RestoreView phase (and starting the conversation.)


                Because the conversation is started before RenderResponse phase, the form action URL is now properly appended with the new conversation ID, and subsequent requests will function within the boundaries of the conversation.


                To summarize, you should not begin conversations in getter methods, but rather by starting the conversation using the

                <f:event type="preRenderView" listener="#{yourBean.listener}"/>

                tag: https://javaserverfaces.dev.java.net/nonav/docs/2.0/pdldocs/facelets/index.html


                I hope this helps,
                Lincoln

                • 5. Re: Conversation created until POST
                  ssamayoagt
                  Thanks for the solution.

                  But sadly cant use f:event since Richfaces 3.3.3 + JSF 2 uses facelets 1.1.15.

                  It seems that I have to wait until richfaces 4.

                  Regards.
                  • 6. Re: Conversation created until POST
                    ssamayoagt
                    FWIW:

                    The conversation is created now with JSF1.2's <f:view beforePhase...> event, equivalent to JSF2's <f:event type="preRenderView" ...>:

                         public void beforePhase(PhaseEvent event) {
                              System.out.println("beforeView() " + event.getPhaseId().toString());
                              if (conversation.isTransient()) {
                                   conversation.begin();
                                   System.out.println("beforeView() conversation.id "
                                             + conversation.getId());
                              }
                         }


                    By the way, there still is a bug in faceletes: tag doc says that the attribute is "beforePhase" and "afterPhase" but are "beforePhaseListener" ans "afterPhaseListener", I found this (4 years old):

                    http://forums.java.net/jive/message.jspa?messageID=185593

                    Regards.