12 Replies Latest reply on Nov 13, 2007 7:26 PM by kotlusa

    FlushModeType not working in Seam 1.2.1 GA?

    kotlusa

      Environment:
      I have tried this in serveral environments...
      Seam 1.2.1
      JBoss 4.0.5 and 4.2.1
      Myfaces (JSF 1.1) and JSF 1.2 RI
      Windows XP and Solaris 10
      HSQLDB and Oracle

      Scenario:
      I have a basic situation where I want to edit an entity (and it's related entities on an edit page), go to a confirmation page and let the user either cancel or save their changes.

       @Begin(join=true, flushMode=FlushModeType.MANUAL)
       public String lookupBlah()
       {
       //lookup blah....
       return "edit";
       }
      
       public String editBlah()
       {
       em.merge(blah);
       return "edit";
       }
      
       @End
       public String cancelEdit()
       {
       return "home";
       }
      
       @End
       public String submitEdit()
       {
       em.flush();
       return "home";
       }
      


      The Problem:
      Unfortunately, this doesn't work for me. The changes are always persisted, even if the user clicks the cancel button. I am however able to manually tell the em not to flush by putting
      ((EntityManagerImpl)em.getDelegate()).getSession().setFlushMode(FlushMode.NEVER);
      at the first line of lookupBlah().

      My Questions:
      Any idea why setting the FlushModeType in @Begin isn't working? Does anyone else have it working? Does my call to the Hibernate Session's setFlushMode method break anything else?

      Sidebar/feature request:
      It would be great if @End had an optional parameter flush which defaults to true. This way you wouldn't have to call em.flush. Also, cancel methods would just have @End(flush=false) or something like that.

      Seam Rocks!
      Thank you,
      Austin

        • 1. Re: FlushModeType not working in Seam 1.2.1 GA?
          amitev

          I think that @Begin(join=true, flushMode=FlushModeType.MANUAL) works only for seam managed persistence context

          • 2. Re: FlushModeType not working in Seam 1.2.1 GA?
            kotlusa

            I believe that I am using a seam managed persistence context...

            From my components.xml

             <core:managed-persistence-context name="entityManager"
             auto-create="true"
             persistence-unit-jndi-name="java:/myEntityManagerFactory"/>
            


            From my persistence.xml:
            <property name="jboss.entity.manager.factory.jndi.name" value="java:/myManagerFactory"/>
            


            • 3. Re: FlushModeType not working in Seam 1.2.1 GA?
              pmuir

              Yes, must be an SMPC. How do you inject your SMPC?

              • 4. Re: FlushModeType not working in Seam 1.2.1 GA?
                amitev

                From his code i see that he's using wrong property name for the entity manager

                @End
                public String submitEdit()
                {
                 em.flush();
                 return "home";
                }


                • 5. Re: FlushModeType not working in Seam 1.2.1 GA?
                  kotlusa

                  I obtain a persistence context like this:

                  @PersistenceContext(type=PersistenceContextType.EXTENDED)
                   private EntityManager em;
                  


                  I changed my managed persistence context to match my code (since I use it as em in several places):
                  <core:managed-persistence-context name="em"
                   auto-create="true"
                   persistence-unit-jndi-name="java:/myEntityManagerFactory"/>


                  That didn't fix it, cancelEdit still saves the changes.

                  • 6. Re: FlushModeType not working in Seam 1.2.1 GA?
                    pmuir

                    So use an SMPC (read the docs)

                    • 7. Re: FlushModeType not working in Seam 1.2.1 GA?
                      kotlusa

                      You were absolutely correct. I didn't catch that the SMPC was actually a Seam Component and need to be retrieved with @In rather than @PersistenceContext.

                      After making this change I have learned several things and found one that I believe to be a bug.

                      SMPC's only manage entity beans for the life of the conversation. This is an important distinction between an SMPC and a persistence context obtained with @PersistenceContext(type=PersistenceContextType.EXTENDED).

                      All this is fine but I still am having difficulty realizing the promise of atomic conversations.

                      Merge and remove operations both get queued and executed when I flush. Unfortunately, persist operations do not act this way.

                      I created a sample application with a conversation that begins on a page that lists the users in the database. A nested conversation begins when you edit a user in the list. On the edit page, the user is updated (merge), another entity is delete (remove), and a third entity is created (persist). Clicking Next brings you to a confirmation screen where you can either go back (and do another merge, remove, and persist), Submit (flush, end the conversation, and return to the list), or Cancel (no flush, end the conversation, and return to the list).

                      In this example, all merges and removes are queued until flush is called (when user clicks Submit on the confirmation screen) but all persists happen right away regardless of submitting/canceling.

                      What are your thoughts?

                      Thanks again,
                      Austin

                      • 8. Re: FlushModeType not working in Seam 1.2.1 GA?
                        pmuir

                        Post your *actual* code.

                        • 9. Re: FlushModeType not working in Seam 1.2.1 GA?
                          kotlusa

                          If I could attach the code I would.... but since I see no way, here's some more inline code.

                          I modified the booking application and deployed it on both 4.2.1GA and 4.2.2GA, both of which appear to have the same FlushMode issue.

                          In addition to my changes to get it working with JSF 1.2 RI I did the following:

                          Added the following properties to persistence.xml - to create a smpc:

                           <property name="jboss.entity.manager.factory.jndi.name" value="java:/entityManagerFactory"/>
                           <property name="jboss.entity.manager.jndi.name" value="java:/em"/>
                          


                          Added the following to components.xml - to create a smpc:
                           <core:managed-persistence-context name="entityManager"
                           auto-create="true"
                           persistence-unit-jndi-name="java:/entityManagerFactory"/>
                          


                          My new HotelBookingAction (I tried to bold the changes but that didn't work because they are in a code block):
                          //$Id: HotelBookingAction.java,v 1.49 2007/03/09 01:18:21 gavin Exp $
                          package org.jboss.seam.example.booking;
                          import static javax.persistence.PersistenceContextType.EXTENDED;
                          import java.util.Calendar;
                          import javax.ejb.Remove;
                          import javax.ejb.Stateful;
                          import javax.persistence.EntityManager;
                          import javax.persistence.PersistenceContext;
                          import org.jboss.seam.annotations.Begin;
                          import org.jboss.seam.annotations.Destroy;
                          import org.jboss.seam.annotations.End;
                          import org.jboss.seam.annotations.FlushModeType;
                          import org.jboss.seam.annotations.In;
                          import org.jboss.seam.annotations.Logger;
                          import org.jboss.seam.annotations.Name;
                          import org.jboss.seam.annotations.Out;
                          import org.jboss.seam.annotations.security.Restrict;
                          import org.jboss.seam.core.Events;
                          import org.jboss.seam.core.FacesMessages;
                          import org.jboss.seam.log.Log;
                          @Stateful
                          @Name("hotelBooking")
                          @Restrict("#{identity.loggedIn}")
                          public class HotelBookingAction implements HotelBooking
                          {
                          
                           @In
                           private EntityManager entityManager;
                          
                           @In
                           private User user;
                          
                           @In(required=false) @Out
                           private Hotel hotel;
                          
                           @In(required=false)
                           @Out(required=false)
                           private Booking booking;
                          
                           @In
                           private FacesMessages facesMessages;
                          
                           @In
                           private Events events;
                          
                           @Logger
                           private Log log;
                          
                           private boolean bookingValid;
                          
                           @Begin(flushMode=FlushModeType.MANUAL)
                           public void selectHotel(Hotel selectedHotel)
                           {
                           hotel = entityManager.merge(selectedHotel);
                           }
                          
                           public void bookHotel()
                           {
                           booking = new Booking(hotel, user);
                           Calendar calendar = Calendar.getInstance();
                           booking.setCheckinDate( calendar.getTime() );
                           calendar.add(Calendar.DAY_OF_MONTH, 1);
                           booking.setCheckoutDate( calendar.getTime() );
                           }
                           public void setBookingDetails()
                           {
                           Calendar calendar = Calendar.getInstance();
                           calendar.add(Calendar.DAY_OF_MONTH, -1);
                           if ( booking.getCheckinDate().before( calendar.getTime() ) )
                           {
                           facesMessages.addToControl("checkinDate", "Check in date must be a future date");
                           bookingValid=false;
                           }
                           else if ( !booking.getCheckinDate().before( booking.getCheckoutDate() ) )
                           {
                           facesMessages.addToControl("checkoutDate", "Check out date must be later than check in date");
                           bookingValid=false;
                           }
                           else
                           {
                           bookingValid=true;
                           }
                           entityManager.persist(booking);
                           }
                          
                           public boolean isBookingValid()
                           {
                           return bookingValid;
                           }
                          
                           @End
                           public void confirm()
                           {
                           facesMessages.add("Thank you, #{user.name}, your confimation number for #{hotel.name} is #{booking.id}");
                           log.info("New booking: #{booking.id} for #{user.username}");
                           events.raiseTransactionSuccessEvent("bookingConfirmed");
                           entityManager.flush();
                           }
                          
                           @End
                           public void cancel() {}
                          
                           @Destroy @Remove
                           public void destroy() {}
                          }
                          


                          This causes the booking to be persisted when you set it's details. When you confirm the details, the entityManager is flushed.

                          To test this just create 1 booking and cancel on the confirmation page. Then create another booking and confirm it. You will see both of the bookings in your list now.

                          Thanks,
                          Austin

                          • 10. Re: FlushModeType not working in Seam 1.2.1 GA?
                            nickarls

                            The documentation for @Begin says

                            "Specifies that a long-running conversation begins when this method returns a non-null outcome without exception"

                            so I've sometimes wondered about this void selectHotel(...). Or is this only applicable to methods returning String?

                            • 11. Re: FlushModeType not working in Seam 1.2.1 GA?
                              pmuir

                               

                              "nickarls" wrote:
                              so I've sometimes wondered about this void selectHotel(...). Or is this only applicable to methods returning String?


                              Only applicable to methods returning String, void allows the conversation to start, with no return value.

                              • 12. Re: FlushModeType not working in Seam 1.2.1 GA?
                                kotlusa

                                For anyone that is interested, this bug is fixed in Seam 2.0 GA on JBoss 4.2.1 GA & 4.2.2 GA. It may also work with earlier versions of JBoss but I haven't had a need to test it.

                                Thanks again for the help,
                                Austin