12 Replies Latest reply on Aug 14, 2007 5:56 PM by ellenzhao

    feature idea - conversation names

    matt.drees

      Does anyone else think it'd be useful to let conversations have a logical name?
      e.g.

      <begin-conversation name="book room"/>
      or
      @begin(name="book room")
      


      Then you could restrict which conversations components can run in.
      e.g.
      @Conversational(legalConversations={"book room", "modify booking"})
      or maybe
      <page>
       <legal-conversations>
       <name>book room</name>
       <name>modify booking</name>
       <legal-conversations>
      ...
      </page>
      


      This would be particularly helpful for nested conversations. E.g., say 'book room' sometimes has a child conversation 'room preferences', and say you don't want users to access roomPreferences.xhtml unless they're in the 'room preferences' conversation. Note that conversation-required isn't helpful here, because there *is* a conversation, but it's the wrong one. In this case, you could redirect to no-conversation-view-id, or maybe make a wrong-conversation-view-id attribute.


      Note that this is just an idea I was thinking about; I haven't run into a business requirement for this. And I think you could probably imitate most of this already with a conversation-scoped ConversationName component and page actions. But the syntax seems handy. And it seems like your code might be more self-documenting this way, and it would probably help identify programmer errors more quickly (I've had some frustrating debugging sessions resulting from components being put in a parent conversation instead of the child one).


        • 1. Re: feature idea - conversation names
          monkeyden

          Sounds good to me, but one man's self-documenting code is another man's verbosity. Some people dislike this about the Java language in general. I find it helpful but the Perl kiddies can't stand it.

          • 2. Re: feature idea - conversation names
            matt.drees

            Yeah, definitely true. At least it'd be optional.

            • 3. Re: feature idea - conversation names
              pmuir

              This is implemented (not "officially" as there is no docs) in Seam (1.2.1.GA onwards). Gavin/Shane know about.

              • 4. Re: feature idea - conversation names
                matt.drees

                Hmmm... I wonder if you're talking about "natural conversation ids." I thought that was mostly about customizing the cid parmeter name/value, which is different than what I'm talking about here, I'm pretty sure.

                • 5. Re: feature idea - conversation names
                  pmuir

                  Yes I am. I thought it was about both customising the cid and giving a conversation a logical name, but tbh, I really don't know. I'll point Shane at this thread and we shall be wiser :)

                  • 6. Re: feature idea - conversation names

                    We already support named conversations, but I'd agree that it would be nice to support the notion of needing to be in a specific conversation to access a resource rather than just saying "requires conversation". I've argued for this for quite some time.

                    • 7. Re: feature idea - conversation names
                      matt.drees

                      I guess I don't like how named conversations work right now - you have to use ELConversationIdParameter, which means you can't do nested conversations.

                      • 8. Re: feature idea - conversation names
                        ellenzhao

                        This is a nice feature, would be very useful for people who are doing a lot of view templating. I have a page called foo-detail.xhtml. This foo-detail page has CRUD buttons, has its own (nested=true) conversations and the page accessable from many different sources like all-foos.xhtml, all-bars.xhtml --> a-use-case-which-has-foo.xhtml-->foo-detail.xhtml, yet-another-use-case.xhtml --> foo-detail.xhtml, etc. Each source page semantically maps a use case (long-running conversation). When the user click "foo stuff done" button on the foo-detail.xhtml, I'd like it to redirect to the source page which directed to foo-detail.xhtml. It's not that straight forward to do with pages.xhtml, since the button is always on the same page (foo-detail.xhtml) and the action is always from the same conversation bean (fooManager). For now the workaround is that I keep a mother conversation name as a private String field in the fooManager, then use the navigation rule in the pages.xhtml to redirect to right mother page.

                        If would be great if I could say something like:

                        <page view-id="foo-detail.xhtml">
                        <navigation from-action="#{fooManager.fooStuffDone}">
                        <rule if mother conversation is not null>
                        <redirect to the page where the mother conversation was at />




                        without manually writing the references in my manager beans.

                        But then, it's a bit like jPDL ....

                        • 9. Re: feature idea - conversation names
                          christian.bauer

                          Didn't read the whole thread, but what the last poster is looking for is not named conversations. This "exit to the entry point" conversation handling is actually already available with a slightly different model (but Gavin convinced me it is better) in any seam-gen produced application.

                          • 10. Re: feature idea - conversation names
                            delphi'sghost

                             

                            This "exit to the entry point" conversation handling is actually already available with a slightly different model (but Gavin convinced me it is better) in any seam-gen produced application.


                            Just curious, but how? I posted about it a while back, and I think Gavin pointed me to the captureCurrentView / returnToCapturedView methods on the redirect component.



                            • 11. Re: feature idea - conversation names
                              matt.drees

                               

                              "christian.bauer@jboss.com" wrote:
                              (but Gavin convinced me it is better)


                              Hi Christian,

                              Would you mind summarizing why it's better?

                              Thanks

                              • 12. Re: feature idea - conversation names
                                ellenzhao

                                The more I think about it, the more I'd like to have named conversation. Since I can mentally map a named conversation to a use case. What I get from named conversation is more than just "exit to the entry point".

                                For now, in my own application, the "named conversation (use case)" is implemented this way:

                                The application scoped enum UseCase

                                public enum UseCase {
                                 doANewPlan, viewPastPlans, viewAllRecipes, viewAllFoods,....
                                }
                                


                                although the "viewPastPlans", "viewAllRecipes", "viewAllFoods" ... have only "view" as a verb but in fact these use cases are deep having many sub usecases. From the "viewPastPlans", user can click a recipe link and enter the "recipe-detail.xhtml", there are CRUD option buttons/links which would be rendered according to the current use case and user permssions on the recipe-detail page. From the recipe-detail page user can enter the food-detail.xhtml and again there are CRUD options available according to use cases and user permissions. If I want to implement it, from the food-detail.xhtml page a user can enter the nutrient-detail.xhtml...... All my conversation beans such as planManager, recipeManager, foodManager ...... has code like this inside the impl classes:

                                private UseCase currentUseCase;
                                
                                public UseCase getCurrentUseCase(){return this.currentUseCase}
                                public void setCurrentUseCase(UseCase motherUseCase){
                                 this.currentUseCase = motherUseCase;
                                }
                                


                                Here is some code example from my view code and pages.xhtml just to demonstrate why knowing current use case is very useful

                                Code from the plan-detail.xhtml using use case information:
                                <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                                 xmlns:s="http://jboss.com/products/seam/taglib"
                                 xmlns:ui="http://java.sun.com/jsf/facelets"
                                 xmlns:f="http://java.sun.com/jsf/core"
                                 xmlns:h="http://java.sun.com/jsf/html"
                                 xmlns:rich="http://richfaces.ajax4jsf.org/rich"
                                 xmlns:a="https://ajax4jsf.dev.java.net/ajax"
                                 xmlns:p="http://jboss.com/products/seam/pdf">
                                
                                 <!-- check loggedIn and permission-->
                                 ... ... ...
                                 ... ... ...
                                
                                 <!-- ########### render shopping list on screen ############## -->
                                 <div class="section"><s:fragment
                                 rendered="#{recipePlanner.weeklyCookingPlan.renderShoppingList}">
                                 <h:outputText
                                 value="Amount in gram, price in Euro. Check the items you want to
                                 remove."
                                 class="message"
                                 rendered="#{recipePlanner.currentUseCase == useCases['doANewPlan']}" />
                                 <h:form>
                                 <rich:dataTable id="weeklyShoppingList"
                                 value="#{recipePlanner.weeklyCookingPlan.foods}" var="wf">
                                 <rich:column
                                 rendered="#{recipePlanner.currentUseCase == useCases.['doANewPlan']}">
                                 <f:facet name="header">
                                 <h:outputText value="Option" />
                                 </f:facet>
                                 <h:commandButton value="Remove" action="#{recipePlanner.weeklyCookingPlan.removeAShoppingItem(wf)}" />
                                 </rich:column>
                                
                                 <rich:column>
                                 <f:facet name="header">
                                 <h:outputText value="Food" />
                                 </f:facet>
                                 <h:outputText value="#{wf.food.longDesc}" />
                                 </rich:column>
                                
                                 <rich:column>
                                 <f:facet name="header">
                                 <h:outputText value="Amount in gram" />
                                 </f:facet>
                                 <h:outputText value="#{wf.amountInGram}">
                                 <f:convertNumber type="number" maxFractionDigits="2" />
                                 </h:outputText>
                                 <h:outputText value=" g" />
                                 </rich:column>
                                
                                 <rich:column>
                                 <f:facet name="header">
                                 <h:outputText value="Price per 100g" />
                                 </f:facet>
                                 <h:outputText value="#{wf.price}">
                                 <f:convertNumber pattern="? ###0.00" />
                                 </h:outputText>
                                 </rich:column>
                                
                                 <rich:column>
                                 <f:facet name="header">
                                 <h:outputText value="Actual cost" />
                                 </f:facet>
                                 <h:outputText value="#{wf.amountInGram / 100 * wf.price}">
                                 <f:convertNumber pattern="? ###0.00" />
                                 </h:outputText>
                                 </rich:column>
                                 </rich:dataTable>
                                 </h:form>
                                 <div class="section"><h:outputText value="Total cost: " /> <h:outputText
                                 value="#{recipePlanner.weeklyCookingPlan.getTotalPrice()}">
                                 <f:convertNumber pattern="? ###0.00" />
                                 </h:outputText></div>
                                 </s:fragment></div>
                                 <!-- ####### end of render shopping list on screen ############## -->
                                ... ... ...
                                ... ... ...
                                </ui:composition>
                                


                                UseCase flags used in pages.xhtml:
                                <page view-id="/recipe-detail.xhtml">
                                 <navigation from-action="#{recipeManager.quitRecipeDetail}">
                                 <rule if="#{recipeManager.currentUseCase == 'viewAllRecipes'}">
                                 <redirect view-id="/all-recipes.xhtml" />
                                 </rule>
                                 <rule if="#{recipeManager.currentUseCase == 'doANewPlan'}">
                                 <redirect view-id="/weekly-planner.xhtml" />
                                 </rule>
                                 <rule if="#{recipeManager.currentUseCase == 'viewPastPlans'}">
                                 <redirect view-id="/my-past-plans.xhtml" />
                                 </rule>
                                 </navigation>
                                 </page>
                                


                                The conversation beans (in my application they are manager beans) set each other's the currentUseCase whenever there is any dependency between the managers.....

                                This way the entity-oriented view code is very reusable. (a xxxx-detail.xhtml page is in fact a view representation of an entity bean. There the basic CRUD operation happens) Each useCase's view is simply composed with xxxx-detail.xhtml pages with additional information. So far my code for the views of useCases is very short. So I think syntax sugars for named conversation would be very nice.

                                Regards,
                                Ellen