8 Replies Latest reply on May 23, 2011 6:09 AM by Craig

    Multiple UIInputContainer lose values ?

    Craig  Newbie

      Hi I have defined a number of wrapper components on a page using UIInputContainer


      The problem I have is that if one input value fails validation because it is required and the field is empty, the other valid values are not submitted.


      When the page section is updated it clears the valid values and the getters on the bean return null, as their values were never set.



      Anyone any ideas how I can get this to work?


      Cheers


      Craig

        • 1. Re: Multiple UIInputContainer lose values ?
          Sebastian Sachtleben Novice

          I have also the same problem and just put all validation stuff into my bean then it works fine but if I use jsf components as UIInputContainer in combination with jsf validators the error message comes up but all input fields are empty. If I dont use that jsf validator and do the validation in my bean the error message comes up and the input fields are still filled.


          Well I think its not a seam problem sounds more like an jsf problem.

          • 3. Re: Multiple UIInputContainer lose values ?
            Jose Freitas Newbie

            Yeap, it's seems to be a JSF bug.
            we might create a temporaty component as a workaround, but it'd be nice if you vote for the JSF issues:


            http://java.net/jira/browse/JAVASERVERFACES-1991


            http://java.net/jira/browse/JAVASERVERFACES-2040

            • 4. Re: Multiple UIInputContainer lose values ?
              Craig  Newbie

              That would be great if you could, else it's pretty useless!


              I'll vote for the issues


              BTW I changed the template to be



              <h:panelGroup>
                   <cc:insertChildren />
              </h:panelGroup> 
              





              but still cant get it to work?


              Any ideas?


              Cheers


              Craig

              • 5. Re: Multiple UIInputContainer lose values ?
                Sebastian Sachtleben Novice

                Well I prefer to keep all validation stuff in the main action instead of split the action and validation. It works fine the fields still contains input. Once the fix it out you can put the validation stuff back in the validator action.

                • 6. Re: Multiple UIInputContainer lose values ?
                  Craig  Newbie

                  Hi Sebastian,


                  My validation is annotations either on the model objects or the bean methods.  Is this where yours is, or do you validate in the action method then manually add the messages to an id in the facesContext ?


                  Thanks for your help


                  Craig

                  • 7. Re: Multiple UIInputContainer lose values ?
                    Sebastian Sachtleben Novice

                    I had also annotation based validation and these validation jsf beans but I removed all that for now and worked it out in the good old way:


                    /**
                     * @author Sebastian Sachtleben
                     */
                    @Named("registerAction") @Stateful @RequestScoped @MessureCalls
                    @URLMapping(id = "login", pattern = "/login.html", viewId = "/pages/login/login.seam")
                    public class RegisterActionImpl implements RegisterAction, Serializable 
                    {
                         private static final long serialVersionUID = -1662395892339047313L;
                    
                         private Logger log = Logger.getLogger(RegisterActionImpl.class);
                         
                         @PersistenceContext 
                         private EntityManager em;
                         
                         @Inject 
                         private List<DateTimeZone> timeZones;
                         
                         @Inject
                         private Credentials credentials;
                         
                         @Inject
                         private Identity identity;
                         
                         @Inject
                         private Registrar registrar;
                    
                         @Inject
                         private Messages messages;
                      
                         @Inject
                         private Event<UserCreatedEvent> createEvent;
                         
                         ///////// METHODS /////////     
                              
                         public String register() 
                         {
                              log.debug("register()");
                              if (isValid()) {
                                   return saveUser();
                              }
                              return null;
                         }
                         
                         public List<DateTimeZone> getTimeZones() 
                         {
                              return timeZones;
                         }
                         
                         private boolean isValid() 
                         {
                              log.debug("Validate register form");
                              if (registrar.getUsername() == null || registrar.getUsername().length() < 3 || registrar.getUsername().length() > 30) {
                                   messages.error(new BundleKey("messages", "login.error.InvalidUsername")).defaults("The username must be between 3 and 30 characters.").targets("register_usernameDec_rusername");
                              }
                              if (registrar.getPassword() == null || registrar.getPassword().length() < 5 || registrar.getPassword().length() > 30) {
                                   messages.error(new BundleKey("messages", "login.error.InvalidPassword")).defaults("The password must be between 5 and 30 characters.").targets("register_passwordDec_rpassword");
                              }
                              if (registrar.getPassword2() == null || registrar.getPassword2().length() < 5 || registrar.getPassword2().length() > 30) {
                                   messages.error(new BundleKey("messages", "login.error.InvalidPassword2")).defaults("The re-enter password must be between 5 and 30 characters.").targets("register_password2Dec_rpassword2");
                              }          
                              if (registrar.getEmail() == null || registrar.getEmail().length() < 1 || registrar.getEmail().length() > 50) {
                                   messages.error(new BundleKey("messages", "login.error.InvalidEmail")).defaults("The email must be between 1 and 50 characters.").targets("register_emailDec_remail");
                              } else {
                                   Pattern p = Pattern.compile("[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");
                                   Matcher m = p.matcher(registrar.getEmail());
                                   if (!m.matches()) {
                                        messages.error(new BundleKey("messages", "login.error.InvalidEmailFormat")).defaults("The email address has invalid format.").targets("register_emailDec_remail");
                                   }     
                              }
                              if (registrar.getEmail2() == null || registrar.getEmail2().length() < 1 || registrar.getEmail2().length() > 50) {
                                   messages.error(new BundleKey("messages", "login.error.InvalidEmail2")).defaults("The re-enter email must be between 1 and 50 characters.").targets("register_email2Dec_remail2");
                              } else {
                                   Pattern p = Pattern.compile("[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");
                                   Matcher m = p.matcher(registrar.getEmail2());
                                   if (!m.matches()) {
                                        messages.error(new BundleKey("messages", "login.error.InvalidEmailFormat2")).defaults("The re-enter email address has invalid format.").targets("register_email2Dec_remail2");
                                   }     
                              }
                              if (!registrar.getTerms()) {
                                   messages.error(new BundleKey("messages", "login.error.AcceptTerms")).defaults("Please accept our terms of sevices.").targets("register_termsDec_rterms");               
                              }
                              if (messages.isEmpty()) {
                                   if (!registrar.getPassword().equals(registrar.getPassword2())) {
                                        messages.error(new BundleKey("messages", "login.error.PasswordMatch")).defaults("Password doesnt match with re-enter.").targets("register_passwordDec_rpassword");
                                   }
                                   if (!registrar.getEmail().equals(registrar.getEmail2())) {
                                        messages.error(new BundleKey("messages", "login.error.EmailMatch")).defaults("Email doesnt match with re-enter.").targets("register_emailDec_remail");          
                                   }     
                              }
                              if (messages.isEmpty()) {
                                   return true;
                              }
                              return false;
                         }
                         
                         private String saveUser() 
                         {
                              log.debug("saveUser()");
                              
                              // Create new user
                              User regUser = new User();
                              regUser.setUsername(registrar.getUsername());
                              regUser.setEmail(registrar.getEmail());
                              regUser.setTimezone(registrar.getTimezone());
                              regUser.setNewsletter(registrar.getNewsletter());
                              
                              // Set new hashed password
                              String hashedPass = Sha256Hash.hash(registrar.getPassword());
                              log.debug(String.format("Generated password hash = {0}", hashedPass));
                              regUser.setPassword(hashedPass);
                    
                              // Persist new user
                              em.persist(regUser);
                              log.debug(String.format("Persisted new {0}", regUser.toString()));
                              createEvent.fire(new UserCreatedEvent(regUser));
                              
                              // Login with created user
                              return loginUser();
                         }
                         
                         private String loginUser() 
                         {
                              log.debug("loginUser()");
                              
                              // Set login data
                              credentials.setUsername(registrar.getUsername());
                              credentials.setCredential(new PasswordCredential(registrar.getPassword()));
                              
                              // Reset register form
                              registrar.reset();
                              
                              // Login new user
                              return identity.login();          
                         }          
                         
                    }



                    /**
                     * The registrar implementation allows for a username, password, re-enter password, 
                     * email, re-enter email, timezone and terms of service to be set.
                     * 
                     * @author Sebastian Sachtleben
                     */
                    @Named("registrar") @SessionScoped
                    public class RegistrarImpl implements Registrar, Serializable {
                    
                         private static final long serialVersionUID = -367086888739234148L;
                    
                         private String username;
                         private String password;
                         private String password2;     
                         private String email;
                         private String email2;          
                         private String timezone;
                         private Boolean newsletter;
                         private Boolean terms;
                         
                         ///////// METHODS /////////     
                         
                         @PostConstruct
                         public void initalize() {
                              reset();
                         }
                         
                         @Override
                         public void reset() {
                              username = "";
                              password = "";
                              password2 = "";
                              email = "";
                              email2 = "";
                              timezone = DateTimeZone.getDefault().getID();
                              newsletter = false;
                              terms = false;
                         }
                         
                         ///////// GETTER & SETTER /////////     
                         
                         public String getUsername() {
                              return username;
                         }
                         
                         public void setUsername(String username) {
                              this.username = username;
                         }
                         
                         public String getPassword() {
                              return password;
                         }
                         
                         public void setPassword(String password) {
                              this.password = password;
                         }
                         
                         public String getPassword2() {
                              return password2;
                         }
                         
                         public void setPassword2(String password2) {
                              this.password2 = password2;
                         }
                         
                         public String getEmail() {
                              return email;
                         }
                         
                         public void setEmail(String email) {
                              this.email = email;
                         }
                         
                         public String getEmail2() {
                              return email2;
                         }
                         
                         public void setEmail2(String email2) {
                              this.email2 = email2;
                         }
                         
                         public String getTimezone() {
                              return timezone;
                         }
                         
                         public void setTimezone(String timezone) {
                              this.timezone = timezone;
                         }
                         
                         public Boolean getNewsletter() {
                              return newsletter;
                         }
                         
                         public void setNewsletter(Boolean newsletter) {
                              this.newsletter = newsletter;
                         }
                         
                         public Boolean getTerms() {
                              return terms;
                         }
                         
                         public void setTerms(Boolean terms) {
                              this.terms = terms;
                         }
                    
                         @Override
                         public int hashCode() {
                              final int prime = 31;
                              int result = 1;
                              result = prime * result + ((email == null) ? 0 : email.hashCode());
                              result = prime * result + ((email2 == null) ? 0 : email2.hashCode());
                              result = prime * result + ((newsletter == null) ? 0 : newsletter.hashCode());
                              result = prime * result + ((password == null) ? 0 : password.hashCode());
                              result = prime * result + ((password2 == null) ? 0 : password2.hashCode());
                              result = prime * result + ((terms == null) ? 0 : terms.hashCode());
                              result = prime * result + ((timezone == null) ? 0 : timezone.hashCode());
                              result = prime * result + ((username == null) ? 0 : username.hashCode());
                              return result;
                         }
                    
                         @Override
                         public boolean equals(Object obj) {
                              if (this == obj)
                                   return true;
                              if (obj == null)
                                   return false;
                              if (getClass() != obj.getClass())
                                   return false;
                              RegistrarImpl other = (RegistrarImpl) obj;
                              if (email == null) {
                                   if (other.email != null)
                                        return false;
                              } else if (!email.equals(other.email))
                                   return false;
                              if (email2 == null) {
                                   if (other.email2 != null)
                                        return false;
                              } else if (!email2.equals(other.email2))
                                   return false;
                              if (newsletter == null) {
                                   if (other.newsletter != null)
                                        return false;
                              } else if (!newsletter.equals(other.newsletter))
                                   return false;
                              if (password == null) {
                                   if (other.password != null)
                                        return false;
                              } else if (!password.equals(other.password))
                                   return false;
                              if (password2 == null) {
                                   if (other.password2 != null)
                                        return false;
                              } else if (!password2.equals(other.password2))
                                   return false;
                              if (terms == null) {
                                   if (other.terms != null)
                                        return false;
                              } else if (!terms.equals(other.terms))
                                   return false;
                              if (timezone == null) {
                                   if (other.timezone != null)
                                        return false;
                              } else if (!timezone.equals(other.timezone))
                                   return false;
                              if (username == null) {
                                   if (other.username != null)
                                        return false;
                              } else if (!username.equals(other.username))
                                   return false;
                              return true;
                         }
                    
                         @Override
                         public String toString() {
                              return "Registrar [username=" + username + ", password=" + password + ", password2=" + password2 + ", email=" + email + ", email2="
                                        + email2 + ", timezone=" + timezone + ", newsletter=" + newsletter + ", terms=" + terms + "]";
                         }
                         
                    }



                    Dont get confused because of the login.html mapping, I have login and register on the same page :)


                    I know validation and action bean should be split but currently there is no other way to have input values which stay on error.


                    Good luck :)

                    • 8. Re: Multiple UIInputContainer lose values ?
                      Craig  Newbie

                      I have created a work around for now....


                      I have new UIInputContainer (which is a copy of the seam version) called FacetUIInputContainer.


                      The difference being in the encodeBegin method:




                      |        InputContainerElements elements = scan(getFacet(UIComponent.COMPOSITE_FACET_NAME), null, context);
                              
                              scan(getFacet("inputs"), elements, context);             
                              
                              // assignIds(elements, context);
                              wire(elements, context);
                      
                              getAttributes().put(getElementsAttributeName(), elements);
                      
                              if (elements.hasValidationError()) {
                                  getAttributes().put(getInvalidAttributeName(), true);
                              }
                              else {
                                   getAttributes().put(getInvalidAttributeName(), false);
                              } |




                      Then the component template  looks like :



                           <cc:interface componentType="org.jboss.seam.faces.FacetInputContainer" >
                                <cc:facet name="inputs"/>
                                <cc:attribute name="label"/>          
                           </cc:interface>
                      
                           <cc:implementation>
                      
                                <div id="#{cc.clientId}" class="#{cc.attrs.invalid ? 'invalid' : ''} wrapper" >
                                     <h:outputLabel id="label" value="#{cc.attrs.label}:" styleClass="#{cc.attrs.invalid ? 'invalid' : ''}" for="#{cc.attrs.for}">     
                                          <h:outputText styleClass="required" rendered="#{cc.attrs.required}" value="*" />
                                     </h:outputLabel>
                                     
                                     <span class="value"> 
                                          <h:panelGroup>
                                               <cc:renderFacet name="inputs"/>
                                          </h:panelGroup> 
                                     </span>
                                     
                                     <h:message id="wrapperMessage" errorClass="invalid message" rendered="#{cc.attrs.invalid}" showSummary="true" showDetail="false" />
                                </div>
                                
                           </cc:implementation>



                      Referenced as:



                      <components:wrapper id="messageWrapper" label="Message">
                           <f:facet name="inputs">               
                                <p:inputTextarea id="message" value="#{feedbackBean.message}" styleClass="feedback"/>
                           </f:facet>                     
                      </components:wrapper>






                      Hope this helps someone!


                      Cheers


                      Craig