9 Replies Latest reply on Jun 11, 2009 4:22 PM by ohughes

    My First Pageflow

    ohughes

      Hi,


      I am writting my first pageflow, and am getting frustrated and confused.


      Firstly, I manually enter the URL of the page that starts the pageflow.  Now that the page is loaded, and the appropriate pageflow is also initiated, I need to perform some actions on this page, well basically perform a search, and then from the selection of a row from the results found, step to the next part of the pageflow (which is another search screen).


      Unfortunately, when I click on search, or any other button that I have on screen, no methods are being called in the seam component supporting the page (whereas when it is not in a pageflow, the methods are being called without any problem).


      Another slight problem I have, is to actually initiate the Pageflow, I physically have to put in the URL into the browser, because if I select the option from the menu, it doesn't appear to initiate the pageflow.  It displays the page and allows me to perform a search, etc, but it is not in the pageflow.  I have tried it with both start-state and start-page, and the only one that initiates the workflow is the start-page when I manually enter the URL.


      Any thoughts, ideas, tips?


       



      • pageflow.jpdl.xml



      <?xml version="1.0" encoding="UTF-8"?>
      <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="Error Correction Wizard">
      <!--
           <start-state>
                <transition to="dataSourceSelection"/>
           </start-state>-->
           
           <start-page name="begin" view-id="/error-correction/data-source-selection.seam">
                
                <transition name="next" to="cdrSelection">
                </transition>
                <transition name="cancel" to="cancelTest">
                </transition>
           </start-page> 
           
           <page view-id="/error-correction/data-source-selection.seam" name="dataSourceSelection">
                <redirect />
           </page>
      
           <page name="cdrSelection" view-id="/error-correction/cdr-selection.seam" redirect="true">
           
           </page>
           
           
           <page name="cancelTest" view-id="/home.seam">
                <end-conversation before-redirect="yes"/>
                <redirect />
           </page>
      
      </pageflow-definition>
      
      




      • Menu item selection (session scoped seam component)



           @Begin(pageflow="Error Correction Wizard", join=true, flushMode=FlushModeType.MANUAL)
           public final String openCDRCorrectionUtility() {
                return "/error-correction/data-source-selection.jspx";
           }






      Thanks.


      Oh, this is using SEAM 2.1.1.GA and Java 1.6

        • 1. Re: My First Pageflow
          andygibson.contact.andygibson.net

          Welcome to the wacky world of page flows.


          I think you need to make your search part of the pageflow since otherwise, depending on how your methods are working, you might get illegal navigation. Do you have an <h:messages global="true"/> in your page? Did you check the console for queued messages that are not displayed? Try making 'searchWidgets' an action in the pageflow which executes the search and transitions you back to the same page.


          As for activation, in your post, you didn't define how the pageflow is starting when you enter your URL. You probably have some pages.xml for that page which starts the conversation and the pageflow. However, what I think is happening with the menu is this :


          You are on Page A in conversation 10 and you click the link to start the flow. When you move to Page B which is the first page of the page flow, you are probably calling your @Begin annotated method somewhere which (so you think) starts the conversation and the page flow. However, it probably isn't. When you move to Page B, you are probably still in conversation 10 as it propagated over. Since join='true' it is just joining that conversation, and not starting a new one and thus, not starting the pageflow. You are accidentally propagating the conversation over and pageflows can only start when you start a conversation.
          It works when you enter the URL because it is a GET request and there is no conversation propagation. The answer is not to propagate the conversation when you go from the original page to the first page of the pageflow.


          If in doubt, add this to your template :




          <h:outputText value="Conversation ID : #{conversation.id}" /><br/>
          <h:outputText value="Is Long Running : #{conversation.longRunning}" />



          This will show you which conversations are running in which pages and which are long running.


          Cheers,


          Andy Gibson

          • 2. Re: My First Pageflow
            ohughes

            Hi Andy,


            I've been busy debugging the whole thing to see if it was queing my actions at least, and yes, it is giving me an 'Illegal navigation' error. (which now I look in the log file it was there all along, my bad)


            So are you saying that I should map in the search, reset, etc. buttons into the pageflow?  I have tried this, but the command link that should be executed isn't being called, because the 'Illegal navigation' is being thrown before it gets a chance to execute the command link and find the next step, for example search.


            Here is what I tried to do to map in the search (if this is going down the correct route):


            <?xml version="1.0" encoding="UTF-8"?>
            <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="Error Correction Wizard">
            <!--
                 <start-state>
                      <transition to="dataSourceSelection"/>
                 </start-state>
                 
                 
                 <page view-id="/error-correction/data-source-selection.seam" name="dataSourceSelection">
                      <redirect />
                 </page>
                 -->
                 
                 <start-page name="begin" view-id="/error-correction/data-source-selection.seam">
                      
                      <transition name="next" to="cdrSelection">
                      </transition>
                      <transition name="cancel" to="cancelTest">
                      </transition>
                      <transition name="search" to="searchDataSource"/>
                 </start-page> 
                 
                 <page view-id="/error-correction/data-source-selection.seam" name="searchDataSource">
                      
                 </page>
                 
                 <page name="cdrSelection" view-id="/error-correction/cdr-selection.seam" redirect="true">
                 
                 </page>
                 
                 
                 <page name="cancelTest" view-id="/home.seam">
                      <end-conversation before-redirect="yes"/>
                      <redirect />
                 </page>
            
            </pageflow-definition>




            And with regards to the starting of conversations, do you have an example of how I should start the conversation?  Because, if for example I return the url, /error-correction/data-source-selection.jspx, it automatically continues in the conversation from the previous page, as you mentioned.


            I believe there is light at the end of the tunnel.


            Thanks again,
            Osh

            • 3. Re: My First Pageflow
              andygibson.contact.andygibson.net

              Osh, try this instead :


              <start-page name="begin" view-id="/error-correction/data-source-selection.seam">
                 ...
                <transition name="search" to="begin">
                  <action expression="#{method to invoke the search results i.e. myBean.performSearch()}"/>
                </transition>
                ...
              </start-page>
              


              I'm not sure from your example how you are performing the search, but I assume you left it out. (You may also want to rename the first page from 'begin' to something more meaningful)


              As for starting the conversation, there are a few ways of doing it depending on how you are hitting the initial page.


              Personally, I put everything in pages.xml (or one of the other pages.xml files), so that when I hit that page (however I got there) I start the conversation. I then just make sure that any links to that page doesn't propagate the conversation by using a straight link, or setting propagation to none.



              Cheers,


              Andy




              • 4. Re: My First Pageflow
                ohughes

                Hi Andy,


                Well, I have the new conversation started as you mentioned through the use of pages.xml, the only problem I have now, is the fact that my action takes parameters due to the code implementation.  I can modify this, but I need the generic action button I have on screen to simulate a call through its backing bean to the new parameterless method.


                Ok, to put it simply, I now need to, from a backing bean, execute the method found through the EL of


                #{dataSource2.performSearch()}



                .  I'm not sure if I should be using something like SeamELResolver?  or do you have any ideas on how to execute a method through EL in code?


                Thanks again,
                Osian

                • 5. Re: My First Pageflow
                  ohughes

                  Silly me, ignore the last post, I've figured out that I can use the full EL path (doh doh), i.e.



                       <start-page name="begin" view-id="/error-correction/data-source-selection.seam">
                            
                            <transition name="next" to="cdrSelection">
                            </transition>
                            <transition name="cancel" to="cancelTest">
                            </transition>
                            <transition name="search" to="begin">
                                 <action expression="#{errorDataSourceSearch2.searchButton.notifyOfSelection}"/>
                            </transition>
                       </start-page> 




                  But even with this, I'm still having trouble with the conversation starter/killer.  So, now in my pages.xml file I have:



                      <page view-id="/error-correction/data-source-selection.jspx">
                                <begin-conversation join="true" flush-mode="MANUAL" pageflow="Error Correction Wizard"/> 
                      </page>



                  And I tried it with join as false but then when the selection is made to search and it returns to this page, it throws an exception:




                  Caused by java.lang.IllegalStateException with message: "begin() called from long-running conversation, try join=true"
                  





                  and it still isn't calling the method in my backing bean that it should :-( i.e. errorDataSourceSearch2.searchButton.notifyOfSelection

                  • 6. Re: My First Pageflow
                    andygibson.contact.andygibson.net

                    You pretty much always need join="true" when starting a conversation.
                    The page.xml you have in your post is correct, now when you go to that page, you will start the conversation and the page flow.


                    I'm not sure exactly what your code is supposed to be doing. I assumed that your 'search' button should be performing the search, but your method  seems to indicate that it is the notification of selection. It shouldn't really matter, but what is the function of the search action, and how do you know it is not being executed? Do you have log statements in there to indicate that the method is being executed?


                    Cheers,


                    Andy Gibson


                    • 7. Re: My First Pageflow
                      ohughes

                      Hi Andy,


                      The search button is performing the search, but it is a custom component that I have written, which is an action button (there is one for clear, select, etc.), and when the action button is pressed, it internally calls notifyOfSelection on its backing bean, which in turn goes through an interface to inform the listener class (in this case errorDataSourceSearch2) that an action has been performed, then through this interface the search is performed and a string is returned to say that the search happened, i.e. 'search', which is returned to the commandLink component.


                      The reason I know this method isn't being called when I am in the pageflow, is because of some breakpoints that i have in the code.  I traced the code earlier today, and when it is going through its phases, it is only executing the SeamPhaseListener phase, and through evaluating this phase, it indicates that the 'illegal navigation' has taken place, and therefore doesn't carry on to the following phases to actually execute the required method call.


                      I can't recall fully the actual code, because I am not at my desk at the moment, but I recall that there are a series of Listeners that are cycled through, and the SeamPhase is the first one in the list.


                      Any ideas?  For example, for pageflows, do the components have to be seam components? or can they be richfaces commandlinks, or another implementation that you use to navigate?


                      Thanks,


                      Osh

                      • 8. Re: My First Pageflow
                        ohughes

                        I have just done some quick testing, and have found that it does need to be the s:link that is used to initiate the call (or at least I hope so), but I have encountered a problem.


                        I have a facelet component which represents an action button so that it can easily be re-used everywhere in the app, and here is a snippet from it:




                             <ui:param name="actionButton" value="#{actionButton}"/>
                             <ui:param name="disabled" value="#{disabled}"/>
                        
                             <s:link rendered="#{actionButton.seam}" action="#{actionButton.notifyOfSelection}" style="text-decoration: none;" disabled="#{actionButton.disabled or disabled}" >
                                  <ui:define name="seamLinkParams" />
                                  <medComp:graphicImage 
                                       visible="#{not actionButton.hidden}" 
                                       style="border: 0; padding: 2px;" 
                                       actionButton="#{actionButton}" 
                                       url="#{actionButton.getImagePath(disabled)}" 
                                       fullImageURL="#{actionButton.getFullImagePath(disabled)}"
                                       title="#{messages[actionButton.imageDescription]}"/>
                             </s:link>





                        and the 'actionButton' is a bean which is passed into the component through:




                             <medComp:actionButton actionButton="#{errorDataSourceSearch2.searchButton}" disabled="false"/>





                        but when the SeamPhaseListener evaluates this, it complains that the actionButton is null:


                        Caused by javax.el.PropertyNotFoundException with message: "Target Unreachable, identifier 'actionButton' resolved to null"
                        org.jboss.el.parser.AstValue.getTarget(AstValue.java:38)
                        org.jboss.el.parser.AstValue.invoke(AstValue.java:95)



                        Whereas when I use the ice:commandLink, this is executed during the InvokeApplicationPhase, which is part of the LifecycleImpl class.


                        Is it not possible to use facelet components with the s:link?  If not, then this is how I have developed most of my application for easy re-use of components, and if this is not possible, then.......


                        Thanks

                        • 9. Re: My First Pageflow
                          ohughes

                          If I now embedd the s:link within the main page, and not within a facelet component, I am able to perform the search and navigate to another page, but it still shows the 'Illegal Navigation' error in the background, but at least the navigation and searching is done.


                          My question now is, how do I create a facelet component, or similar, to manage my s:link's, like I have for my standard commandLinks? Because I want to put this kind of functionality into a component, and not have to write s:link's all over my application, so that the look and feel is 100% guaranteed to be the same (and the amount of code to write is less).


                          I don't mind if this is a normal JSF tag which extends the s:link (org.jboss.seam.ui.component.html.HtmlLink I think), because I can then embedd those into a facelet and ensure that they have the appropriate ActionButton bean passed to them.


                          Any hints or tips on this? or is this a no no??


                          Thanks,


                          Osian