1 Reply Latest reply on Dec 16, 2011 7:11 AM by jblbecarelli

    Seam 2.2.0.GA and manual flush mode

      Hi there,


      I updated my Seam application to Seam 2.2.0.GA and stumbled into an interesting effect. On a page to edit an entity there is a h:selectOneMenu to represent an entity property. This property is bound to a Seam component via binding. This component is a backing bean for an AJAX/ICEfaces tag (selectInputText) which is intended to simplify entering this entity's property.


      The page is part of a long-running conversation which begins by displaying all the entities one can edit and ending as soon as the user navigates to another part of the application. This long-running conversation is started using @Create(flushMode=FlushModeTyp.MANUAL).


      The AJAX/ICEfaces components uses its binding to set the binding's value to the first entry matching the user's input (((ValueHolder) binding).setValue(matchingEntry);). I. e. the user enters b, an AJAX request is started, the backing bean calculates matches for b and sets the first one (say banana) as the new value of the bound tag. So the bound property has a new value.


      The problem now is, that Seam 2.2.0.GA seems to ignore the manual flush mode. Everytime the user enters a letter, the corresponding value in the database is set to the new value. This didn't happen with Seam 2.1.1.GA.


      Perhaps I should illustrate this by posting some code.


      Here is a part of the page:


      <h:panelGroup>
        <ice:setEventPhase events="ValueChangeEvent" phase="INVOKE_APPLICATION">
          <ice:selectInputText id="devUsrID_AC"
            rows="#{userAutoComplete.listLength}"
            value="#{userAutoComplete.enteredUser}"
            valueChangeListener="#{userAutoComplete.selectInputValueChanged}"
            listVar="user"
            listValue="#{userAutoComplete.matches}">
      
            <f:facet name="selectInputText">
              <ice:outputText value="#{user.ID} - #{user.name}"/>
            </f:facet>
          </ice:selectInputText>
        </ice:setEventPhase>
      
        <s:decorate id="decorate_devUsrID" template="inc/decorateField.xhtml">
          <ice:setEventPhase events="ValueChangeEvent" phase="INVOKE_APPLICATION">
            <ice:selectOneMenu value="#{testaction.devUsrID}" binding="#{userAutoComplete.binding}" id="devUsrID" converter="com.idsscheer.ytrack.view.converter.UserConverter" valueChangeListener="#{userAutoComplete.selectInputValueChanged}" partialSubmit="true">
              <s:selectItems value="#{mainSupplier.developers}" var="developer" label="#{developer.ID} - #{developer.name}" id="devUsrIDs" />
            </ice:selectOneMenu>
          </ice:setEventPhase>
        </s:decorate>
      </h:panelGroup>



      And here is the UserAutoComplete class:




      @AutoCreate
      @Stateful
      @Scope(ScopeType.SESSION)
      @Name("userAutoComplete")
      @Role(name = "userAutoComplete2", scope = ScopeType.SESSION)
      public class UserAutoComplete implements IUserAutoComplete, Serializable {
        private static final long serialVersionUID = 5406906545256206754L;
      
        private static int listLength = 20;
      
      
        @In
        private transient IUserSelector userSelector;
      
      
        private transient UIComponent binding;
      
        private String enteredUser;
        private List<SelectItem> matches;
      
      
        public void selectInputValueChanged(ValueChangeEvent event) {
          if (event.getComponent() instanceof SelectInputText) {
            SelectInputText autoComplete = (SelectInputText) event.getComponent();
      
            String newWord = (String) event.getNewValue();
      
            matches = generateMatches(newWord);
      
            User selectedUser = null;
            if (autoComplete.getSelectedItem() != null) {
              selectedUser = findUserMatch(autoComplete.getSelectedItem().getLabel());
            } else {
              selectedUser = findUserMatch(autoComplete.getValue().toString());
            }
      
            if (selectedUser != null && binding instanceof ValueHolder) {
              ((ValueHolder) binding).setValue(selectedUser);
            }
          } else {
            if (!(event.getNewValue() instanceof User)) {
              return;
            }
      
            User newUser = (User) event.getNewValue();
            enteredUser = newUser.getID();
          }
        }
        
        //some setters/getters and private methods
      }



      I also tried to switch the scope of userAutoComplete to CONVERSATION and to remove the @AutoCreate annotation. But if I do this, Seam tells me that userAutoComplete resolves to null as soon as the user enters a letter in the selectInputText tag. I don't know why this happens. This is surprising since the Seam debug page shows me that there is a long-running conversation which comprises a userAutoComplete component.


      I worked half a day on this issue and don't get a clue. Would save my day, if someone has an idea on this.


      Thanks in advance
      Jens