3 Replies Latest reply on Jul 18, 2011 10:30 PM by Tom Bryan

    Conversation promoted during render ignores flushMode

    michael haefele Newbie

      Hello,


      I'm experiencing an interesting side effect while promoting a conversation during the rendering phase and wondering what the expected behavior should be.
      This is in Seam 2.2.0


      What I have is a seam bean with a seam managed entity manager.
      This bean promotes the conversation to long running when it is created.


      @Name("myBean")
      @Scope(ScopeType.CONVERSATION)
      public class MyBean
      {
          @Begin(flushMode = FlushModeType.MANUAL)
          @Create
          public void create()
          {
              //  initialize
          }
      
          public String getSomeInfo()
          {
              return "Some info";
          }     
      }
      




      This will create the bean and promote the conversation when getSomeInfo() is called.


      This works fine if getSomeInfo() is called before the rendering phase.


      On the other hand, if getSomeInfo() is called during the rendering phase (say, from a facelets xhtml file), the flushMode = FlushModeType.MANUAL only is used during the rendering phase and is discarded at the end of the rendering phase.


      Effectively it looks like flushMode = FlushModeType.MANUAL is ignored (this isn't quite what happens, see below).


      I'm wondering if this is a bug or incorrect expectations on my part.



      The class that does not behave as I expected it to is org.jboss.seam.persistance.PersistenceContexts
      It has two fields and 3 methods that affect the flushmode.


      public class PersistenceContexts extends AbstractMutable implements Serializable
      {
         /* ... */
         private FlushModeType flushMode;
         // the real flush mode is a backup of the flush mode when doing a temporary switch (such as during render)
         private FlushModeType realFlushMode;
      
         @Create
         public void create()
         {
            FlushModeType defaultFlushMode = Manager.instance().getDefaultFlushMode(); 
            if (defaultFlushMode != null)
            {
               flushMode = defaultFlushMode;
            }
            else
            {
               flushMode = FlushModeType.AUTO;
            }
         }
      
         /* ... */
      
         public void changeFlushMode(FlushModeType flushMode)
         {
            changeFlushMode(flushMode, false);   
         }
      
         public void changeFlushMode(FlushModeType flushMode, boolean temporary)
         {
            if (temporary) {
               realFlushMode = this.flushMode;
            }
            this.flushMode = flushMode;
            changeFlushModes();
         }
      
         /**
          * Restore the previous flush mode if the current flush mode is marked 
          * as temporary.
          */
         public void restoreFlushMode() {
            if (realFlushMode != null && realFlushMode != flushMode) {
               flushMode = realFlushMode;
               realFlushMode = null;
               changeFlushModes();
            }
         }
      
         /* ... */
      
      }
      




      Below is what actually occurs in PersistanceContexts before, during, and after the rendering phase.



      1. create() is called



      •   flushMode = FlushModeType.AUTO

      •   realFlushMode = null



      2. changeFlushMode(FlushModeType.MANUAL, temporary = true) is called before render phase, this backs up the flush mode to realFlushMode



      • flushMode = FlushModeType.MANUAL

      • realFlushMode = FlushModeType.AUTO



      3. changeFlushMode(FlushModeType.MANUAL) is called because MyBean has been referenced and promoted the conversation (this is equivilent to changeFlushMode(FlushModeType.MANUAL, temporary = false)



      • flushMode = FlushModeType.MANUAL

      • realFlushMode = FlushModeType.AUTO



      4. restoreFlushMode() is called after render.  This replaces flushMode with realFlushMode and nulls out realFlushMode.  Our MANUAL flush mode is wiped out.



      • flushMode = FlushModeType.AUTO

      • realFlushMode = null




      So my expected result is:
      Throughout the entire rendering phase the flush mode is MANUAL.
      At the end of the rendering phase, the flush mode becomes whatever the @Begin called for.



      The actual result is:
      Halfway through the rendering phase, the flush mode is switched from MANUAL to whatever the @Begin called for.
      At the end of the rendering phase, the flush mode is reset to AUTO.



      Does the expected result seem correct?



      Possible solution



      I believe the code change below would give my expected results.


         public void changeFlushMode(FlushModeType flushMode, boolean temporary)
         {
            boolean currentlyTemporary = realFlushMode != null;
            
            if (currentlyTemporary) {
               if (temporary) {
                  //  TODO:  This should probably be a more specific exception.
                  throw new RuntimeException("Already in a temporary render mode");  // Nested temporary flushmodes not supported.
               } else {
                  // Trying to set the "permanent" flushmode, but currently in temporary mode.
                  // Set the realFlushMode and it will take effect when we exit temporary mode. 
                  realFlushMode = flushMode;
               }
            } else {  // !currentlyTemporary
               if (temporary) {
                  //  Push a new temporary flushMode (which puts this in "temporary" mode).
                  realFlushMode = this.flushMode;
                  this.flushMode = flushMode;
               } else {
                  //  We're in "permanent" mode, overwrite the current flushmode
                  this.flushMode = flushMode;
               }
            }
      
            changeFlushModes();
         }
      



      Basically it only puts temporary flushmodes in the temporary box and permanent ones in the permanent box.