9 Replies Latest reply on Mar 24, 2009 1:45 AM by Ingo Jobling

    ValidateAll and decorate problems...

    Todd Gould Newbie

      Hello,


      I am new to s:validateAll and s:decorate, so I'm hoping someone can help me find the problems in my code.....  I'm using Seam 2.1.1.GA with RichFaces 3.3.0.GA, hibernate-annotations-3.3.0.GA, hibernate-validator-3.1.0.GA and hibernate-distribution-3.3.1.GA.


      I have the following template for decoration:


      <ui:composition 
          xmlns="http://www.w3.org/1999/xhtml"
          xmlns:ui="http://java.sun.com/jsf/facelets"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
          xmlns:rich="http://richfaces.org/rich"
          xmlns:t="http://myfaces.apache.org/tomahawk"
          xmlns:ts="http://myfaces.apache.org/sandbox"
          xmlns:s="http://jboss.com/products/seam/taglib"
          xmlns:e="http://www.ensuren.com/facelets/ensuren">
      
                      <s:label styleClass="#{invalid?'error':''}">
                          <ui:insert name="label" style="float:left; text-align: right;"/>
                      </s:label>
                  
                      <s:span class="#{invalid?'error':''}" style="float: right;">
                          <s:validateAll>
                              <ui:insert/>
                          </s:validateAll>
                          <s:span styleClass="required" rendered="#{required}">*</s:span>                    
                          <s:graphicImage src="/images/error.jpg" rendered="#{invalid}"/>
                          <s:graphicImage src="/images/checkmark.gif" rendered="#{! invalid}"/>
                      </s:span>           
              
                      <s:message styleClass="error"/>
      
      </ui:composition>



      I reference that template in the following form...


             <a4j:form id="discoveryListEditForm">
                 <a4j:outputPanel ajaxRendered="true">
                      <rich:messages style="color:red;"></rich:messages>
                 </a4j:outputPanel>
                 
                 <h:panelGrid columns="1">
                     <a4j:outputPanel>
                         <s:decorate id="subnetDecoration" template="/templates/editField.xhtml">
                             <ui:define name="label"><h:outputText value="#{msgs.subnetHeader}"/></ui:define>
                             <h:inputText id="subnet" value="#{discoveryListController.selectedItem.subnet}" required="true">
                                     <a4j:support event="onblur" reRender="subnetDecoration"/>
                             </h:inputText>
                         </s:decorate>
                         <s:decorate id="netmaskDecoration" template="/templates/editField.xhtml">
                             <ui:define name="label"><h:outputText value="#{msgs.netmaskHeader}" /></ui:define>
                             <h:inputText id="netmask" value="#{discoveryListController.selectedItem.netmask}" required="true">
                                     <a4j:support event="onblur" reRender="netmaskDecoration"/>
                             </h:inputText>
                         </s:decorate>
                     </a4j:outputPanel>
                     <a4j:commandButton value="#{msgs.addButtonActionLabel}"
                      rendered="#{discoveryListController.operationName == 'ADD'}"
                         action="#{discoveryListController.doIt}"
                          reRender="contentView:discoveryListForm:discoveryListTable,contentView:discoveryListForm:discoveryListTableScroller,contentView:discoveryListForm:discoveryListPageCount"
                         oncomplete="if (#{facesContext.maximumSeverity==null}) #{rich:component('discoveryListEditPanel')}.hide();"
                         status="mainStatus"/>
                     <a4j:commandButton value="#{msgs.editButtonActionLabel}"
                      rendered="#{discoveryListController.operationName == 'EDIT'}"
                         action="#{discoveryListController.doIt}"
                          reRender="subnet, netmask"
                         oncomplete="if (#{facesContext.maximumSeverity==null}) #{rich:component('discoveryListEditPanel')}.hide();"
                         status="mainStatus"/>
                 </h:panelGrid>  
             </a4j:form>



      The form references a component as follows:



      @Name( "discoveryList" )
      public class DiscoveryList
          implements Serializable
      {
          private static final long serialVersionUID = 1734458878690387538L;
      
          /**
           * Specifies the subnet indicated in this DiscoveryList (the unique id)
           */
          @NotNull(message="The subnet is a required field")
          @Length(max=15, message="The subnet cannot be longer than 15 characters")
          @Pattern(regex="^\\d\\{1,3\\}\\.\\d\\{1,3\\}\\.\\d\\{1,3\\}\\.\\d\\{1,3\\}$", message="The subnet must be in the format \\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}")
          protected String subnet_ = null;
          
          /**
           * Specifies the netmask to go along with the netmask attribute
           */
          @NotNull(message="The netmask is a required field")
          @Length(max=15, message="The metmask cannot be longer than 15 characters")
          @Pattern(regex="^\\d\\{1,3\\}\\.\\d\\{1,3\\}\\.\\d\\{1,3\\}\\.\\d\\{1,3\\}$", message="The netmask must be in the format \\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}")
          protected String netmask_ = null;
          /**
           * @return the subnet
           */
          public String getSubnet()
          {
      System.out.println( "getSubnet returns " + subnet_ );     
              return subnet_;
          }
      
          /**
           * @param subnet the subnet to set
           */
          public void setSubnet( String subnet )
          {
      System.out.println( "setSubnet called with [" + subnet + "]" );     
              this.subnet_ = subnet;
          }
          
          /**
           * @return the netmask
           */
          public String getNetmask()
          {
              return netmask_;
          }
      
          /**
           * @param netmask the netmask to set
           */
          public void setNetmask( String netmask )
          {
              this.netmask_ = netmask;
          }
      }
      



      I have several problems with the above.....


      1) While I get some indication from the server log that the hibernate is getting invoked when the setters are called onblur


      16:04:24,947 ERROR [STDERR] Mar 14, 2009 4:04:24 PM org.hibernate.validator.Version <clinit>
      INFO: Hibernate Validator 3.1.0.GA
      16:04:25,036 ERROR [STDERR] Mar 14, 2009 4:04:25 PM org.hibernate.annotations.common.Version <clinit>
      INFO: Hibernate Commons Annotations 3.1.0.GA



      There are no facesMessages, error icons, error formatting or form submission prevention that would indicate that the Validators are actually being executed or enforced when invalid input is put in the form.....


      2) The icons for invalid and ! invalid never appear at in the form.


      I would greatly appreciate any and all help with this as I am unable to make any progress after multiple hours of attempt and googling.


      TIA!




        • 1. Re: ValidateAll and decorate problems...
          Todd Gould Newbie

          I have resolved my second question, but not my first.  Changing the graphicImage tags to use value instead of a src attribute allows the images to be displayed.


          This does confirm, however, that the inputFields are shown as valid (! invalid), even when I know I have put in invalid data per the annotations.


          I am lost on the validation question and will welcome any and all assistance - as there are no errors or other indications of problems - yet the validation does not appear to be being applied.


          Thanks!

          • 2. Re: ValidateAll and decorate problems...
            Todd Gould Newbie

            My first problem appears to be related to hibernate validators and/or configuration.  If I add the following inside my inputText elements and leave all of the s:decorate and s:validateAll code as is, I get the desired behaviour and all works well (except, of course, for violating DRY):



            <t:validateRegExpr pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"/>



            This tells me that the s:decorate and s:validateAll are working just fine and that I have a problem with using the hibernate validator.  Is there some configuration or other setup that I must do in my app to use these beyond including the hibernate-validator, hibernate-annotations, hibernate-commons-annotations and slf4j-api jar files?  Are there problems with using hibernate validators with non @Entity (i.e. POJO beans) components?


            Any and all help will be appreciated as I am a bit stuck.


            TIA!

            • 3. Re: ValidateAll and decorate problems...
              Arbi Sookazian Master

              Are there problems with using hibernate validators with non @Entity (i.e. POJO beans) components?

              Don't use Hibernate Validator with non-JPA entity (or Hibernate entity) classes.


              If you need to add validation to a SFSB, SLSB or JavaBean, for example, then you should use Seam Validator.  Here's an example from my project:


              validator POJO:


              @Name("seamValidatorDates") 
              @Scope(ScopeType.CONVERSATION)
              @org.jboss.seam.annotations.faces.Validator
              public class SeamValidatorDates implements javax.faces.validator.Validator, Serializable
              {
                      @Logger
                      Log log;
              
                      public void validate(FacesContext context, UIComponent cmp, Object value) throws ValidatorException 
                      {      
                           log.info("validate() started");
                           if (value != null)
                           {                  
                                if (!(value instanceof Date))
                                     throw new ValidatorException(new FacesMessage("please enter a valid date in this format: mm/dd/yyyy"));             
                                
                           }
                      }
                  
              }



              xhtml:


              <s:decorate id="receiptDateDecorator"
                   template="layout/edit.xhtml">
                   <rich:calendar id="receiptDateCalendar"
                        value="#{equipmentDetail.equipmentServiceDate}"
                        datePattern="MM/dd/yyyy" cellWidth="24px" cellHeight="22px"
                        style="width:200px" enableManualInput="true"
                        required="true" reRender="receiptDateDecorator">
                        <f:validator validatorId="seamValidatorDates" />
                        <a4j:support event="oninputblur" ajaxSingle="true"
                             eventsQueue="myQueue" requestDelay="200"
                             ignoreDupResponses="true" />
                        <a4j:support event="ondateselected" ajaxSingle="true"
                             eventsQueue="myQueue" requestDelay="200"
                             ignoreDupResponses="true" bypassUpdates="true" />
                   </rich:calendar>
              </s:decorate>



              then use this API for regex:  http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/util/regex/Pattern.html


              I'm not sure if Seam has its own regex facility or not...

              • 4. Re: ValidateAll and decorate problems...
                Arbi Sookazian Master

                The Seam Validator comes in very handy when you need to do live validation (AJAX onblur event validation on form fields) and you need to read a list dynamically from a db table to see if the value the user just entered exists in that table or not, etc.



                @Validator:  Allows a Seam component to act as a JSF validator. The annotated class must be a Seam
                component, and must implement javax.faces.validator.Validator.
                • 6. Re: ValidateAll and decorate problems...
                  Todd Gould Newbie

                  Ron Ramirez wrote on Mar 16, 2009 23:32:


                  The Seam Validator comes in very handy when you need to do live validation (AJAX onblur event validation on form fields)


                  Does this mean that the @Validator will not work with onblur events used with s:decorate?  If so, than this will not meet my needs as I do need live form field validation in this case.  I will be looking into your article, but would appreciate any clarification you can provide on this specific question as it is critical to our requirements.

                  • 7. Re: ValidateAll and decorate problems...
                    Arbi Sookazian Master

                    Todd Gould wrote on Mar 17, 2009 13:44:



                    Ron Ramirez wrote on Mar 16, 2009 23:32:


                    The Seam Validator comes in very handy when you need to do live validation (AJAX onblur event validation on form fields)


                    Does this mean that the @Validator will not work with onblur events used with s:decorate?  If so, than this will not meet my needs as I do need live form field validation in this case.  I will be looking into your article, but would appreciate any clarification you can provide on this specific question as it is critical to our requirements.


                    It will work with s:decorate.  look at my examples again.

                    • 8. Re: ValidateAll and decorate problems...
                      Todd Gould Newbie

                      Ron,


                      Sorry for the delay in getting back to you - my wife was in the hospital...


                      Your suggestion to use the Seam Validator is working as desired.  One important note though, I had to add



                      @BypassInterceptors




                      to the Validator class.  It appears that this is a new requirement since 2.1.1 and will mean that we cannot inject via @IN.  I can see how this would be useful in some situations.  Are there any plans to remove this restriction or provide alternatives?


                      Thanks again for your help with this!

                      • 9. Re: ValidateAll and decorate problems...
                        Ingo Jobling Master

                        Hi Todd, Hope your wife is OK. 


                        The requirement for @BypassInterceptors was added because injection cannot be reliably performed in JSF validators.


                        Instead of using @In, call Component.getInstance(), see Javadoc