2 Replies Latest reply on Mar 23, 2011 1:09 PM by pediddle

    Bug in Seams Page Context?

    noxhoej

      Hi


      I seem to have run into a bug in the way Seams Page context works. Or at least a very bug-like behavior.


      It seems that if a page scoped Seam Component is not required until the IncokeApplication phase, but is then needed several times during this phase, a new instance is created every time, and only the last one survives in the page context!?!?


      To illustrate this behavior with a reasonable small amount of code, I have had to create the very contrived example below - but it illustrates the behavior.


      If you



      1. Load a fresh test.xhtml in your browser

      2. Press the Update Controller Value without rules check button

      3. Press the Assign Controller Value to Model



      you will see that the model value correctly ends up being New controller value - just as I would expect.


      If instead, you



      1. Load a fresh test.xhtml in your browser

      2. Press the Update Controller Value with rules check button

      3. Press the Assign Controller Value to Model



      you will see that the model value now ends up being Initial controller value.


      In both cases, the testController Seam Component, is not created until the Invoke Application Phase, when you click the Update Controller Value ... button in step 2.


      But in the second case, the component is created twice!



      • First, a new testController is created (and stored in the page contest) during the resolving of the target attribute of the setPropertyActionListener. Then the setPropertyActionListener sets the New controller value on the testController.

      • Second, when the action attribute of the <h:commandButton> is resolved, the testController is needed again - and the page context doesn't find the previously created instance. So it creates a new instance - which of course contains the Initial controller value, and proceeds to store it in the page context overwriting the already created instance.



      The reason that the page context doesn't find the testController the second time around, is actually documented in the PageContext javadoc:



      During the INVOKE_APPLICATION phase, set() and remove() manipulate the context of the page that is about to be rendered, while get() returns values from the page that was the source of the request.

      but I can't believe, that the resulting behavior is what was intended?


      Maybe get() needs to look at not only the old page context, but the newly created entries as well...?


      Regards,

      Nicholas Oxhøj




      TestModel.java:
      @Name("testModel")
      @Scope(ScopeType.PAGE)
      @AutoCreate
      public class TestModel
      {
           private String value = "Initial model value";
      
           public String getValue()
           {
                return value;
           }
      
           public void setValue( String aValue )
           {
                value = aValue;
           }
      }


      TestController.java:
      @Name("testController")
      @Scope(ScopeType.PAGE)
      public class TestController
      {
           private String valueToAssign = "Initial controller value";
      
           @In
           private TestModel testModel;
      
           public void checkRules() {
              // Check some business rules or something...
           }
      
           public String getValueToAssign()
           {
                return valueToAssign;
           }
      
           public void setValueToAssign( String aValueToAssign )
           {
                valueToAssign = aValueToAssign;
           }
      }


      test.xhtml:
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE html
           PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
             xmlns:h="http://java.sun.com/jsf/html"
             xmlns:f="http://java.sun.com/jsf/core"
             xml:lang="en" lang="en">
      <body>
      <h:form>
           <h:commandButton value="Update Controller Value without rules check">
                <f:setPropertyActionListener value="New controller value"
                                                    target="#{testController.valueToAssign}"/>
           </h:commandButton>
           <h:commandButton value="Update Controller Value with rules check" action="#{testController.checkRules}">
                <f:setPropertyActionListener value="New controller value"
                                                    target="#{testController.valueToAssign}"/>
           </h:commandButton>
           <br/>
           <h:commandButton value="Assign Controller Value to Model">
                <f:setPropertyActionListener value="#{testController.valueToAssign}"
                                                    target="#{testModel.value}"/>
           </h:commandButton>
           <br/>
           Model Value: <h:outputText value="#{testModel.value}"/>
      </h:form>
      </body>
      </html>


        • 1. Re: Bug in Seams Page Context?
          roman.mandeleil1

          Also have have a problem with page context in combination with mediaOutput




            <a4j:mediaOutput id="uploadIDMediaOutput" element="img" 
            cacheable="false" session="true" 
            createContent="#{fileUploadManager.paintUploadValidId}">
                                                          
          <f:param value="#{fileUploadManager.timeStamp}" name="time"/>             
                    
            <rich:componentControl 
              for="uploadValidIdModalPanel" 
              attachTo="uploadIDMediaOutputPanel" 
              operation="show" event="onclick"/>
                    
                                                          
            </a4j:mediaOutput>
          



          each call to fileUploadManager been performed from different object.


          • 2. Re: Bug in Seams Page Context?
            pediddle

            I'm also having this problem with any component that is not created until INVOKE_APPLICATION.  The component is re-instantiated every time it is accessed.


            Any feedback on this bug?


            As it is, I am unable to use PAGE scope for my beans.


            public class PageContext ...
            
               private Map<String, Object> getCurrentReadableMap()
               {
                  if ( !isInPhase() )
                  {
                     return Collections.EMPTY_MAP;
                  }
                  else
                  {
                     return isRenderResponsePhase() ?
                           nextPageMap : previousPageMap;
                  }
               }
            
               private Map<String, Object> getCurrentWritableMap()
               {
                  return isBeforeInvokeApplicationPhase() ?
                        previousPageMap : nextPageMap;
               }
            



            getCurrentReadableMap() should return a combination of both maps during INVOKE_APPLICATION.