2 Replies Latest reply on Apr 1, 2008 12:02 AM by gallowaym

    Need some explanation of @Begin in JBoss Tools Generated Code

    gallowaym

      Howdy all.  I'm new to Seam and more or less new to Jave EE. I'm very excited about the potential though but am having some problems getting out of the gate.  I'm using Seam 2.0.1.GA, JBoss 4.2.2.GA, and JBoss Tools 2.0.0.GA.


      I am very interested in using code generation tools in Eclipse.  I have created an Eclipse project using File->New->Seam Web Project.  I then added two entities with File->Add->Seam Entity.  The entities are OneFish and TwoFish.


      The JBoss Tools code generator creates a class extended from the seam framework EntityHome for each entity.  Here's the one from OneFish (called OneFishHome):




      package com.thebasement.SampleForTom.session;
      
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Begin;
      import org.jboss.seam.annotations.web.RequestParameter;
      import org.jboss.seam.framework.EntityHome;
      
      import com.thebasement.SampleForTom.entity.OneFish;
      
      @Name("oneFishHome")
      public class OneFishHome extends EntityHome<OneFish>
      {
      
          @RequestParameter 
          Long oneFishId;
          
          @Override
          public Object getId() 
          { 
              if (oneFishId==null)
              {
                  return super.getId();
              }
              else
              {
                  return oneFishId;
              }
          }
          
          @Override @Begin
          public void create() {
              super.create();
          }
            
      }



      I added both of these Entity List pages created for each Entity to the menu.xhtml layout file like so:



              <s:link view="/oneFishList.xhtml" value="One Fish"/>
              <s:link view="/twoFishList.xhtml" value="Two Fish"/>
      



      The application works fine, unless I create one entity (say a OneFish entity) and then go and add an entity of the other type (say a TwoFish Entity. Once you click the Create buttin for the second entity you get the following error:


      java.lang.IllegalStateException: begin method invoked from a long-running 
      conversation, try using @Begin(join=true) on method: create
      



      This got me thinking about Conversations.  I started wondering where the Conversation began and ended (or was suppose to end) but I could find no @End (or other end mechanism) anywhere in the code.  I assumed the error was because I was trying to start another conversation before the first one ended.  When I added (join=true) to @Begin in both Entities the problem went away.


      But the question stood where's the @End?  I then added some Conversation List code to the footer of the xhtml template. Like so:


      <h:dataTable value="#{conversationList}" var="entry">
          <h:column>
              <f:facet name="header">Workspace</f:facet>
              <h:commandLink action="#{entry.select}" value="#{entry.description}"/>
              <h:outputText value="[current]" rendered="#{entry.current}"/>
          </h:column>
          <h:column>
              <f:facet name="header">Activity</f:facet>
              <h:outputText value="#{entry.startDatetime}">
                  <f:convertDateTime type="time" pattern="hh:mm a"/>
              </h:outputText>
              <h:outputText value=" - "/>
              <h:outputText value="#{entry.lastDatetime}">
                  <f:convertDateTime type="time" pattern="hh:mm a"/>
              </h:outputText>
          </h:column>
      </h:dataTable>



      But no matter what page I was on or how many times I went through the process of creating or editing a OneFish or a TwoFish entity, no conversations ever showed up on the list.


      Shouldn't I see at least one conversation - especially after the @Begin annotation?


      So then I began to think that the @Begin didn't do anything in this context.  After all OneFishHome wasn't even a session ELB - it's just a POJO (as best I can tell).  So I took out the @Begin annotations and reran the application.


      This time when I created an entity it seemed to work fine. When the entity is saved the app returns to the edit page - except there are now more buttons because the entity is now "persistent".  I click "Save" again (this time it invokes "oneFishHome.update" instead of a "oneFishHome.persist" because now it's managed.)  The page reloads but this time... the button indicate (namely no "Delete" button) that the oneFish object is no longer being managed.  Click "Save" again and a SECOND record is added to the database.  When the page reloads, it's managed again (the "Delete" button is back) but you are working with the new (second) entity. Clicking "Save" this time will update but the next "Save" will create yet another new entity and so on. 


      So, somehow, @Begin make the managed objects stay managed once they are create across multiple page loads, but it doesn't seem to create a Conversation that I can detect and doesn't seem to use an @End.


      Can anyone offer any insight here? What exactly is @Begin doing in this case? Can the JBoss Tools code generators be used reliably?  Should I be looking at writing code from scratch instead (this would be a shame - the code generators have real promise I think.)


      Thanks in advance.


      Matt Galloway

        • 1. Re: Need some explanation of @Begin in JBoss Tools Generated Code
          nickarls

          You could put an outputText showing the current conversation id and the long-running status, helps you see how your conversations are doing.


          You can end the conversation explicitly at a method with the @End annotation or end/stop propagating with a conversationPropagation in a link etc, whatever is appropriate.

          • 2. Re: Need some explanation of @Begin in JBoss Tools Generated Code
            gallowaym

            Thanks Nicklas, that gets me a little closer to understanding.


            I added the following in my template.xhtml file:


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



            This enabled me to see the current conversation id and Long Running status (true/false).


            This also allowed me to finally find the end which was in the twoFish.xhtml file in the s:button for the Done button as can be seen here (propagation=end):



                       <s:button propagation="end" 
                                           id="done" 
                                        value="Done"
                                         view="/twoFishList.xhtml"/>
            
            



            This lead me to the epiphany that (and I'm new to annotations too) when you override a method in an inherited class that you can also override the annotation.  So in all of the EntityHome examples I saw, there was no @Begin but that was because they didn't overwrite the create() method.  I'm guessing (anyone please validate) that the create() method of EntityHome is annotated with @Begin.  When I removed the annotation in the overriding definition, I essentially broke the EntityHome behavior. From twoFishHome:



                @Override 
                @Begin(join=true) //needed to make EntityHome functionality work
                public void create() {
                    super.create();
                }




            This also allowed me to see that the conversation Id and long running status stay the same after I saved a oneFish entity and selected the twoFishList from the menu.  When I click Create form the twoFishList I get begin method invoked from a long-running conversation, try using @Begin(join=true) on method: create.


            When I add (join=true) to both classes the error goes away. However when I navigate back through the menu and click New I'm really editing the last entity I added (since I'm in the same conversation.)


            So, for who ever is writing the code generators for JBoss Tools (is this seam-gen under the hood) - this could be more intuitive.   My suggestion would be to make the Save and Delete button end the conversation and take you back to the list view.  Also the Home button should end the conversation (which serves as an example when people add more menu buttons.)


            So, here's an unanswered question why do I still get an empty list when this code executes:


            <h:dataTable value="#{conversationList}" var="entry">
                <h:column>
                    <f:facet name="header">Workspace</f:facet>
                    <h:commandLink action="#{entry.select}" value="#{entry.description}"/>
                    <h:outputText value="[current]" rendered="#{entry.current}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">Activity</f:facet>
                    <h:outputText value="#{entry.startDatetime}">
                        <f:convertDateTime type="time" pattern="hh:mm a"/>
                    </h:outputText>
                    <h:outputText value=" - "/>
                    <h:outputText value="#{entry.lastDatetime}">
                        <f:convertDateTime type="time" pattern="hh:mm a"/>
                    </h:outputText>
                </h:column>
            </h:dataTable>




            I now know that at least sometimes, I have a long running conversation, why doesn't it show up on the list?