3 Replies Latest reply on Apr 17, 2008 3:55 PM by aymane2006

    Pageflow with jPDL

    sleroux

      Hi there.


      I continue my journey through the features of Seam. That leads me to jPDL/jBPM.


      I've never used any BPM tool before, but I like the concept of  pageflow as describe on chapter 7 of the doc.
      The one thing I find very attractive is the isolation between the business logic handled by the session bean, and the navigation which is completely defined by the business rules.


      My application


      My application is a toy application for managing a public library.


      There's one page that show the subscribers list, and from this table, the user is able to start several (business?) tasks by clicking on buttons. Here's an ASCII Art drawing of the layout:


      Name          Adress
      -----------------------------------------------
      John          Here           (edit)  (checkout)
      Paul          There          (edit)  (checkout)
      ...
      



      For now, there's only the (checkout) button. Here's the relevant part of my xhtml source for this page:


          <h:messages />
          <h:form> 
          <h:dataTable value="#{subscriberManager.getEntities()}" var="subscriber">
              <h:column>#{subscriber.name}</h:column>
              <h:column>#{subscriber.address}</h:column>
              <h:column>
                      <h:commandButton value="Checkout" 
                            action="#{checkoutManager.startWithSubscriber(subscriber)}" />
              </h:column>
          </h:dataTable>
          </h:form>
      



      I designed the following pageflow for the checkout process:


      <pageflow-definition 
              xmlns="http://jboss.com/products/seam/pageflow"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation=
                  "http://jboss.com/products/seam/pageflow http://jboss.com/products/seam/pageflow-2.0.xsd"
              name="checkout">
      
              <start-state name="start">
                      <transition to="has book?" />
              </start-state>
           <decision name="has book?" expression="#{checkoutManager.subscriber.hasBook}">
                      <transition name="true" to="rejected" />
                      <transition name="false" to="enter ISBN" />
              </decision>
              <page name="rejected" view-id="/checkout/red-light.xhtml">
                      <redirect/>
                      <end-conversation />
              </page>
              <page name="enter ISBN" view-id="/checkout/enter.xhtml">
                      <redirect/>
                      <transition name="submit" to="is valid ISBN?"/>
              </page>
              <decision name="is valid ISBN?" expression="#{checkoutManager.checkISBN()}">
                      <transition name="true" to="confirm checkout" />
                      <transition name="false" to="enter ISBN" />
              </decision>
              
              <page name="confirm checkout" view-id="/checkout/confirm.xhtml">
                      <redirect/>
                      <transition name="confirm"  to="confirmed">
                              <action expression="#{checkoutManager.confirm()}"/>
                      </transition>
                      <transition name="cancel" to="enter ISBN"/>
              </page>
              <page name="confirmed" view-id="/checkout/green-light.xhtml">
                      <redirect/>
                      <end-conversation />
              </page>
      </pageflow-definition>
      



      You noticed that the start of this pageflow is a start-state not a start-page since there is two cases:



      • The subscriber has already checked out a book (and not checked it in). In that case, the process abort and the user is redirected to red light page that informs him that the operation was rejected.

      • Otherwise, the process go through several steps: asking the ISBN of the book, validation of this ISBN (in terms of presence in the database), confirmation, and if the user goes to the end of the process, it ends with a green light page that informs the user that the operation was accepted.



      The pageflow start when the user click on the checkout button, whom action is #{checkoutManager.startWithSubscriber(subscriber)}.


      @Stateful
      @Scope(ScopeType.CONVERSATION)
      @Name("checkoutManager")
      public class CheckoutManagerAction implements CheckoutManager {
      ...
          @Begin(join=true,pageflow="checkout")
          public void startWithSubscriber(Subscriber s) {
           subscriber = em.merge(s);
          }
      
      ...
      }
      



      So, what's the problem?


      Ok: everything works fine. Well almost. My first problem is when I try to switch from the Java annotation @Begin(pageflow=) to the corresponding <begin-conversation ... > element in the pages.xml file.
      The second is when I validate the ISBN entered by the user.


      @Begin vs begin-conversation


      So, I wasn't able to replace the Java annotation @Begin(pageflow=) by the corresponding <begin-conversation ... > element in the pages.xml file.


      If I change my STSB code like that:


      @Stateful
      @Scope(ScopeType.CONVERSATION)
      @Name("checkoutManager")
      public class CheckoutManagerAction implements CheckoutManager {
      ...
      
          public void startWithSubscriber(Subscriber s) {
           subscriber = em.merge(s);
          }
      
      ...
      }
      



      And add the following lines in pages.xml


      <?xml version="1.0" encoding="UTF-8"?>
      <pages xmlns="http://jboss.com/products/seam/pages"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd"
             >
          <page view-id="/subscribers.xhtml">    
              <navigation from-action="#{checkoutManager.startWithSubscriber(subscriber)}">
                  <begin-conversation join="true" pageflow="checkout" />
              </navigation>
          </page>
      </pages>
      



      It no longer works. I've got an error:


      Exception during request processing:
      Caused by java.lang.IllegalStateException with message: "pageflow is not currently at a <page> or <start-page> node (note that pageflows that begin during the RENDER_RESPONSE phase should use <start-page> instead of <start-state>)"
      



      By exploring the log, I saw that the pageflow has started, and is at the start-state. Everything worked as



      • if with the annotation, the process goes through the BPM graph to the first page node,

      • but with the rule is pages.xml, the process stayed at the start node. Letting the software (Seam? jBPM?) without any page to display.



      That's puzzling because the doc says:



      But if the pageflow is begun as the result of an action listener invocation, the outcome of the action listener determines which is the first page to be rendered. In this case, we use a <start-state> as the first node in the pageflow, and declare a transition for each possible outcome:

      Moreover, it works with the annotation. Is there a subtle problem I missed?


      FaceMessage lost in the pageflow?


      My second problem is different. As I have said, at some point, I check if the ISBN entered by the user has a corresponding book in the database. Here's the corresponding code:


      @Stateful
      @Scope(ScopeType.CONVERSATION)
      @Name("checkoutManager")
      public class CheckoutManagerAction implements CheckoutManager {
      ...
          @In
          private FacesMessages facesMessages;
      
          @Override
          public Boolean checkISBN() {
           book = em.find(Book.class, ISBN);
           if (book == null) {
               FacesMessage message = new FacesMessage("No such book: "+ISBN);
               facesMessages.add(null, message);
               return false;
           }
           
           return true;
          }
      
      ...
      }
      



      It worked when I used JSF style navigation: with navigation rules in navigation.xml and checkISBN returning a string success or failure. Now that I switched to jPDL rules, when checkISBN returns false, the enter ISBN page is redisplayed,as specified by the following rules:


              <page name="enter ISBN" view-id="/checkout/enter.xhtml">
                      <redirect/>
                      <transition name="submit" to="is valid ISBN?"/>
              </page>
              <decision name="is valid ISBN?" expression="#{checkoutManager.checkISBN()}">
                      <transition name="true" to="confirm checkout" />
                      <transition name="false" to="enter ISBN" />
              </decision>
      
              <page name="confirm checkout" view-id="/checkout/confirm.xhtml">
                      <redirect/>
                      <transition name="confirm"  to="confirmed">
                              <action expression="#{checkoutManager.confirm()}"/>
                      </transition>
                      <transition name="cancel" to="enter ISBN"/>
              </page>
      



      But the message registered with FaceMessages.add is not displayed! I'm sure I missed something stupid, but I cannot find what it is (I've tried to to inject FaceContext instead of FaceMessages, without any change)...



      Well, if anyone has courage to read this message til the end, thanks in advance!

      Sylvain

        • 1. Re: Pageflow with jPDL
          aymane2006

          Hello,
          Well!!I have the same problm with my pageflow, It's seams like the pageflow starts and stay on the start-page.


          Exceptions:


          pageflow is not currently at a <page> or <start-page> node (note that pageflows that begin during the RENDER_RESPONSE phase should use <start-page> instead of <start-state>)
                  at org.jboss.seam.pageflow.Pageflow.getPage



          and in the web navigator I have isclient.xhtml page body with salehome.xhtml link in the address!!!


          Pageflow:


          <pageflow-definition
            name="SalerProcess_option1">
          
                  <start-state name="SaleHome"  view-id="/salehome.xhtml">
                          <redirect/>
                          <transition name="toIsClient" to="IsClient"></transition>   
                  </start-state>
                  
                  <page name="IsClient" view-id="/isclient.xhtml">
                          <transition name="toDecisionIsClient" to="DecisionIsClient"></transition>
                  </page>
                  
                  <decision name="DecisionIsClient" expression="#{ticket.isClient}">
                          <transition name="false" to="QualificationStart"></transition>
                          <transition name="true" to="FindClient"></transition>
                  </decision>
                  
                  <page name="QualificationStart" view-id="/qualificationstart.xhtml">
                          <transition to="TypeOfPb"></transition>
                  </page>
          ....
          



          Invokate in salehome.xhtml by:


          <h:form><h:commandButton action="toIsClient" value="Start Sale"></h:commandButton></h:form>"
          
          Pages.xml:
          " <page view-id="/salehome.xhtml">
                <begin-conversation join="true" pageflow="SalerProcess_option1"/>
             </page>




          thanks for your help.
          Aymane QODAD

          • 2. Re: Pageflow with jPDL
            jmoreira

            I believe i had a similar problem. I can't remember exactly what i was but it was related to the conjugation of conversation begin's and propagation through the jsf links/commands that started the process

            • 3. Re: Pageflow with jPDL
              aymane2006

              I resolve the problm of displaying pages with the apropriate link...
              I still fight with the problm of :



              pageflow is not currently at a <page> or <start-page> node (note that pageflows that begin during the RENDER_RESPONSE phase should use <start-page> instead of <start-state>)
                      at org.jboss.seam.pageflow.Pageflow.getPage




              I think that the problm is caused at the decision step ...
              Gavin?Pete?


              thanks for help.