12 Replies Latest reply on Jan 21, 2010 6:27 PM by Arbi Sookazian

    Seam Validator not being executed

    Arbi Sookazian Master

      Seam 2.1.1.GA, RF 3.3.1.GA


      Plz advise why the validate() method is not being executed when user submits the form (this is the simplified version: it actually needs to work with a4j: event handlers which don't cause the validate() method to be called either).  It's funny, I wrote a knowledge base article on Seam business validation (which worked!) but for some reason I can't figure out how to get this scenario to work!  But that was with Seam 2.1 and now 2.2 requires @BypassInterceptors.  I don't think it's a scoping issue as I tried conversation scope and that did not work either.  I even added the validator attribute to a <h:inputText> and it still doesn't trigger the validate() method.  What's wrong?


      Seam container installation of validator component:


      09:36:55,293 INFO  [Component] Component: effectiveDateValidator, scope: EVENT, type: JAVA_BEAN, class: com.echo.cis.util.validation.EffectiveDateValidator


      validator:


      @Name("effectiveDateValidator")
      @org.jboss.seam.annotations.faces.Validator
      @BypassInterceptors
      public class EffectiveDateValidator implements javax.faces.validator.Validator, java.io.Serializable {
           
         private static final long serialVersionUID = -4259611077820028265L;
         
         private String cmpId;
         private String clientId;
            
         public void validate(FacesContext context, UIComponent cmp, Object value) throws ValidatorException {        
              if (value != null) {   
                   cmpId = cmp.getId();
                   
                   clientId = cmp.getClientId(context);
                   
                   Date effectiveDate = (Date)value;             
                   Date today = new Date();
                   if (effectiveDate.before(today)) {
                        String errorString = effectiveDate + " is a date in the past.  Please enter today's date or a future date.";             
                        throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_WARN, errorString, errorString));
                   }
              }
         }
      }



      facelet:


      <rich:calendar id="rateCategoryEffectiveDate" 
                              inputClass="dateField" 
                              required="false"
                              value="#{merchantBillingGroupEditorUI.rateCategory.priceEffectiveDate}"
                              oninputkeypress="return restrictDate(this, event);"
                              datePattern="MM/dd/yyyy"
                              enableManualInput="true"
                              isDayEnabled="isDayEnabled"
                                 dayStyleClass="getDisabledStyle"
                                 validator="effectiveDateValidator"
                              label="#{messages['/restricted/billing/add_merchant_billing_group_wizard_step1.xhtml/field.effectiveDate']}">
                              <!-- 
                              <a4j:support event="onchanged"
                                              reRender="#{rateCategoryEffectiveDate}"
                                           requestDelay="0"
                                           eventsQueue="select"
                                           ignoreDupResponses="true"/>
                               <a4j:support event="oninputchange"
                                               reRender="#{rateCategoryEffectiveDate}"
                                           requestDelay="0"
                                           eventsQueue="select"
                                           ignoreDupResponses="true"/>
                                            -->
                          </rich:calendar>


        • 1. Re: Seam Validator not being executed
          Arbi Sookazian Master

          I tried the same validator class in the Hotel booking 2.1.1.GA app and that doesn't work either.  The only app in the 2.1.1.GA distro that uses a Seam validator class is the wiki example.  And it looks like I'm doing it the same way.  Doesn't matter if I use a h:inputText or rich:calendar control, the validate() method is not called...

          • 2. Re: Seam Validator not being executed
            Arbi Sookazian Master

            effectiveDateValidator and wikiCaptchaValidator both are being executed from various components via validator attributes in book.xhtml.  This is very frustrating as it still does not work in my app for some reason.


            is there a limitation perhaps if the value attribute has #{foo.bar.baz}?  That's what I have in my case...

            • 3. Re: Seam Validator not being executed
              Arbi Sookazian Master

              So I just did the following experiment in my project.  in the testCheckinDate1 component below, both events are being fired as evidenced by the alerts.


              facelet:


              <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                                 xmlns:ui="http://java.sun.com/jsf/facelets"
                                 xmlns:c="http://java.sun.com/jstl/core"
                                 xmlns:h="http://java.sun.com/jsf/html"
                                 xmlns:f="http://java.sun.com/jsf/core"
                                 xmlns:s="http://jboss.com/products/seam/taglib"                  
                                 xmlns:a4j="http://richfaces.org/a4j"                   
                                 xmlns:rich="http://richfaces.org/rich">
                   
                   <h:form>
                             <rich:calendar id="testCheckinDate1" 
                                              value="#{merchantBillingGroupEditorUI.myCalendar}" 
                                              validator="effectiveDateValidator" 
                                              required="false" 
                                              datePattern="MM/dd/yyyy" 
                                              enableManualInput="true"
                                              onchanged="alert('testCheckinDate1: onchanged fired!');" 
                                              oninputchange="alert('testCheckinDate1: oninputchange fired!');">
                                              
                          </rich:calendar>
                          
                             <rich:calendar id="testCheckinDate2" 
                                              value="#{merchantBillingGroupEditorUI.myCalendar}" 
                                              validator="effectiveDateValidator" 
                                              required="false" 
                                              datePattern="MM/dd/yyyy" 
                                              enableManualInput="true">                                
                                         <a4j:support event="onchanged"
                                                      reRender="#{testCheckinDate2}"
                                                   requestDelay="0"
                                                   eventsQueue="select"
                                                   ignoreDupResponses="true"/>
                                       <a4j:support event="oninputchange"
                                                       reRender="#{testCheckinDate2}"
                                                   requestDelay="0"
                                                   eventsQueue="select"
                                                   ignoreDupResponses="true"/>
                          </rich:calendar>
               
                   </h:form>
                   
                   <a4j:log popup="false"/>
                       
              </ui:composition>



              backing bean:


              @Name("merchantBillingGroupEditorUI")
              @Scope(ScopeType.CONVERSATION)
              @MeasureCalls
              @Stateful
              public class MerchantBillingGroupEditorUIBean implements
                      MerchantBillingGroupEditorUI {
              
                  public void setMyCalendar(Date date) {
                       Date myCalendar = date;
                  }
                  
                  public Date getMyCalendar() {
                       return new Date();
                  }
              ...
              }



              The setter and getter methods above are being executed.  The validate() method is not. 


              a4j log output:


              debug[12:16:59,561]: Have Event [object Object] with properties: target: undefined, srcElement: [object], type: click
              debug[12:16:59,561]: Query preparation for form 'j_id0' requested
              debug[12:16:59,561]: Append hidden control j_id0 with value [j_id0] and value attribute [j_id0]
              debug[12:16:59,561]: Append text control j_id0:testCheckinDate1InputDate with value [01/19/2010] and value attribute [01/19/2010]
              debug[12:16:59,561]: Append hidden control j_id0:testCheckinDate1InputCurrentDate with value [01/2010] and value attribute [01/2010]
              debug[12:16:59,561]: Append text control j_id0:testCheckinDate2InputDate with value [01/20/2010] and value attribute [01/20/2010]
              debug[12:16:59,561]: Append hidden control j_id0:testCheckinDate2InputCurrentDate with value [01/2010] and value attribute [01/2010]
              debug[12:16:59,561]: Append hidden control javax.faces.ViewState with value [j_id7] and value attribute [j_id7]
              debug[12:16:59,561]: parameter j_id0:j_id1 with value j_id0:j_id1
              debug[12:16:59,561]: Look up queue with name 'select'
              debug[12:16:59,561]: Creating new transient queue 'select' with default settings
              debug[12:16:59,561]: Adding queue 'select' to queues registry
              debug[12:16:59,561]: Queue is empty now
              debug[12:16:59,561]: New request added to queue 'select'. Queue similarityGroupingId changed to j_id0:j_id1
              debug[12:16:59,561]: Queue will wait 0ms before submit
              debug[12:16:59,561]: Queue 'select' will submit request NOW
              debug[12:16:59,561]: NEW AJAX REQUEST !!! with form: j_id0
              debug[12:16:59,561]: Start XmlHttpRequest
              debug[12:16:59,561]: Reqest state : 1
              debug[12:16:59,561]: QueryString: AJAXREQUEST=_viewRoot&j_id0=j_id0&j_id0%3AtestCheckinDate1InputDate=01%2F19%2F2010&j_id0%3AtestCheckinDate1InputCurrentDate=01%2F2010&j_id0%3AtestCheckinDate2InputDate=01%2F20%2F2010&j_id0%3AtestCheckinDate2InputCurrentDate=01%2F2010&javax.faces.ViewState=j_id7&j_id0%3Aj_id1=j_id0%3Aj_id1&AJAX%3AEVENTS_COUNT=1&
              debug[12:17:24,373]: Reqest state : 2
              debug[12:17:24,373]: Reqest state : 3
              debug[12:17:24,373]: Reqest state : 4
              debug[12:17:24,373]: Reqest end with state 4
              debug[12:17:24,373]: Response  with content-type: text/xml;charset=UTF-8
              debug[12:17:24,373]: Full response content: <?xml version="1.0"?>
              <html xmlns="http://www.w3.org/1999/xhtml"><head><link class="component" href="/cis/a4j/s/3_3_1.GAorg/richfaces/renderkit/html/css/basic_classes.xcss/DATB/eAF7sqpgb-jyGdIAFrMEaw__" rel="stylesheet" type="text/css" /><link class="component" href="/cis/a4j/s/3_3_1.GAorg/richfaces/renderkit/html/css/extended_classes.xcss/DATB/eAF7sqpgb-jyGdIAFrMEaw__" media="rich-extended-skinning" rel="stylesheet" type="text/css" /><script src="/cis/a4j/g/3_3_1.GAorg.ajax4jsf.javascript.PrototypeScript" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg.ajax4jsf.javascript.AjaxScript" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/events.js" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/utils.js" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/json/json-dom.js" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/scriptaculous/effects.js" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/jquery/jquery.js" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/JQuerySpinBtn.js" type="text/javascript">
              </script><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/calendar.js" type="text/javascript">
              </script><link class="component" href="/cis/a4j/s/3_3_1.GAorg/richfaces/renderkit/html/css/calendar.xcss/DATB/eAF7sqpgb-jyGdIAFrMEaw__" rel="stylesheet" type="text/css" /><script src="/cis/a4j/g/3_3_1.GAorg/richfaces/renderkit/html/scripts/skinning.js" type="text/javascript">
              </script><meta name="Ajax-Update-Ids" content="" /><title></title></head><body><span id="ajax-view-state"><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id7" /></span><meta id="Ajax-Response" name="Ajax-Response" content="true" /></body></html>
              debug[12:17:24,373]: Header Ajax-Expired not found, search in <meta>
              debug[12:17:24,373]: search for elements by name 'meta'  in element #document
              debug[12:17:24,373]: Find <meta name='Ajax-Update-Ids' content=''>
              debug[12:17:24,373]: Find <meta name='Ajax-Response' content='true'>
              debug[12:17:24,373]: Header Ajax-Update-Ids not found, search in <meta>
              debug[12:17:24,373]: search for elements by name 'meta'  in element #document
              debug[12:17:24,373]: Find <meta name='Ajax-Update-Ids' content=''>
              warn[12:17:24,388]: No information in response about elements to replace
              debug[12:17:24,388]: call selectSingleNode for id= org.ajax4jsf.oncomplete
              debug[12:17:24,388]: Processing updates finished, no oncomplete function to call
              debug[12:17:24,388]: After request: queue 'select'
              debug[12:17:24,388]: There are 0 requests more in this queue
              debug[12:17:24,388]: Queue is empty now
              debug[12:17:24,388]: call selectSingleNode for id= ajax-view-state
              debug[12:17:24,388]: Hidden JSF state fields: 
              debug[12:17:24,388]: Namespace for hidden view-state input fields is undefined
              debug[12:17:24,388]: search for elements by name 'input'  in element span
              debug[12:17:24,388]: Replace value for inputs: 6 by new values: 1
              debug[12:17:24,388]: Input in response: javax.faces.ViewState
              debug[12:17:24,388]: Found same input on page with type: hidden
              debug[12:17:24,388]: search for elements by name 'INPUT'  in element span
              debug[12:17:24,388]: Replace value for inputs: 6 by new values: 0
              debug[12:17:24,388]: call selectSingleNode for id= _A4J.AJAX.focus
              debug[12:17:24,388]: No focus information in response

              • 4. Re: Seam Validator not being executed
                Arbi Sookazian Master

                this doesn't work:


                <h:form>
                               <rich:calendar id="testCheckinDate4" 
                                                value="#{merchantBillingGroupEditorUI.myCalendar}" 
                                                validator="effectiveDateValidator">
                            </rich:calendar>
                            <a4j:commandButton value="Submit"/>
                     </h:form>



                this does:


                <h:inputText id="testMyInputText"
                                         value="#{merchantBillingGroupEditorUI.myInputText}"
                                         validator="effectiveDateValidator">
                                         <a4j:support event="onblur"
                                                             ajaxSingle="true"
                                                             reRender="#{testMyInputText}"
                                                             requestDelay="0"
                                                    eventsQueue="select"
                                                    ignoreDupResponses="true"/>
                            </h:inputText>



                why?

                • 5. Re: Seam Validator not being executed
                  Arbi Sookazian Master

                  Seam validator solution abandoned.  resorting to javascript solution:


                  <rich:calendar  inputClass="dateField"
                                                                  disabled="#{pageaction == 'view'}"
                                                                  required="true"
                                                                  value="#{rateCategory.rateCategory.priceEffectiveDate}"
                                                                  oninputkeypress="return restrictDate(this, event);"
                                                                  oninputchange="return checkNoPastDate(this);"
                                                                  datePattern="MM/dd/yyyy"
                                                                  enableManualInput="true"         
                                                                  isDayEnabled="isDayEnabled"
                                                                      dayStyleClass="getDisabledStyle"                   
                                                                  label="#{messages['/restricted/billing/add_merchant_billing_group_wizard_step1.xhtml/field.effectiveDate']}" /> 
                                                  </rich:calendar>

                  • 6. Re: Seam Validator not being executed
                    Nikolay Elenkov Master

                    Try setting <rich:calendar mode="ajax"/> (default is client).

                    • 7. Re: Seam Validator not being executed
                      Arbi Sookazian Master

                      Don't think the mode matters.  I'll try it anyways at work tomorrow.


                      The following both call the validate() method from book.xhtml:


                      <s:decorate id="checkinDateDecorate" template="edit.xhtml">
                                     <ui:define name="label">Check In Date:</ui:define>
                                     <rich:calendar id="checkinDate"                                   
                                                         validator="itemValidator" 
                                                         value="#{booking.checkinDate}" 
                                                         required="true"
                                                         datePattern="MM/dd/yyyy">
                                               <a:support event="ondateselected"
                                                            ajaxSingle="true"/>                                                             
                                     </rich:calendar>
                                </s:decorate>
                                
                                <s:decorate id="checkinDateDecorate2" template="edit.xhtml">
                                     <ui:define name="label">Test Check In Date:</ui:define>
                                     <rich:calendar id="checkinDate"     
                                                         mode="ajax"                              
                                                         validator="itemValidator" 
                                                         value="#{booking.checkinDate}" 
                                                         required="true"
                                                         datePattern="MM/dd/yyyy">
                                               <a:support event="ondateselected"
                                                            ajaxSingle="true"/>                                                             
                                     </rich:calendar>
                                </s:decorate>



                      validator:


                      @Name("itemValidator")
                      @BypassInterceptors
                      @org.jboss.seam.annotations.faces.Validator
                      public class ItemValidator implements javax.faces.validator.Validator {
                           
                           Log log = Logging.getLog(ItemValidator.class);
                           
                           public void validate(FacesContext context, UIComponent cmp, Object value) throws ValidatorException {
                                log.info("in ItemValidator:validate()!");
                           }
                      }

                      • 8. Re: Seam Validator not being executed
                        Nikolay Elenkov Master

                        So did you wrap your inputs with <s:validateAll/>? That's what the <s:decorate/> above is doing.


                        • 9. Re: Seam Validator not being executed
                          Arbi Sookazian Master

                          I just tried the <s:validateAll/> (see below) and it still doesn't call the validate() method for the two rich:calendar instances below.  But I'm not sure if that tag is even necessary b/c it works for the h:inputText w/o that tag (the Seam ref doc example for validator does not show the use of <s:validateAll/>).  Also, the mode="ajax" did not help.


                          <h:form>
                                    <s:validateAll>
                                                     
                                         <rich:calendar id="testCheckinDate2" 
                                                             mode="ajax"
                                                          value="#{merchantBillingGroupEditorUI.myCalendar}" 
                                                          validator="effectiveDateValidator" 
                                                          required="true" 
                                                          datePattern="MM/dd/yyyy" 
                                                          enableManualInput="true">                                
                                                     <a4j:support ajaxSingle="true"
                                                                     event="onchanged"
                                                                  reRender="#{testCheckinDate2}"
                                                               requestDelay="0"
                                                               eventsQueue="select"
                                                               ignoreDupResponses="true"/>
                                                   <a4j:support ajaxSingle="true"
                                                                   event="oninputchange"
                                                                   reRender="#{testCheckinDate2}"
                                                               requestDelay="0"
                                                               eventsQueue="select"
                                                               ignoreDupResponses="true"/>
                                      </rich:calendar>
                                                              
                                      <rich:calendar id="testCheckinDate3" 
                                                          mode="ajax"
                                                          value="#{merchantBillingGroupEditorUI.myCalendar}" 
                                                          validator="effectiveDateValidator"
                                                          required="true">                               
                                                   <a4j:support ajaxSingle="true"
                                                                   event="onchanged"
                                                              reRender="#{testCheckinDate3}"
                                                           requestDelay="0"
                                                           eventsQueue="select"
                                                           ignoreDupResponses="true"/>
                                                 <a4j:support ajaxSingle="true" 
                                                                event="oninputchange"
                                                                 reRender="#{testCheckinDate3}"
                                                           requestDelay="0"
                                                           eventsQueue="select"
                                                           ignoreDupResponses="true"/>
                                      </rich:calendar>
                                                
                                                  
                                      <h:inputText id="testMyInputText"
                                                   value="#{merchantBillingGroupEditorUI.myInputText}"
                                                   validator="effectiveDateValidator">
                                                   <a4j:support event="onblur"
                                                                       ajaxSingle="true"
                                                                       reRender="#{testMyInputText}"
                                                                       requestDelay="0"
                                                              eventsQueue="select"
                                                              ignoreDupResponses="true"/>
                                      </h:inputText>
                                     
                                      
                                   </s:validateAll>
                           
                               </h:form>

                          • 10. Re: Seam Validator not being executed
                            Nikolay Elenkov Master

                            Arbi Sookazian wrote on Jan 20, 2010 17:44:


                            I just tried the <s:validateAll/> (see below) and it still doesn't call the validate() method for the two rich:calendar instances below.  But I'm not sure if that tag is even necessary b/c it works for the h:inputText w/o that tag (the Seam ref doc example for validator does not show the use of <s:validateAll/>).  Also, the mode="ajax" did not help.


                            You are right, the <s:validateAll> is for model validations. I forgot you are writing a JSF validator. So this may be a problem with the calendar control. You might want to ask on the RF forums. But while we are at it, why did you opt for a JSF validtor? A model validator (Hibernate validator) might make more sense here.

                            • 11. Re: Seam Validator not being executed
                              Arbi Sookazian Master

                              Nikolay Elenkov wrote on Jan 21, 2010 03:12:



                              Arbi Sookazian wrote on Jan 20, 2010 17:44:


                              I just tried the <s:validateAll/> (see below) and it still doesn't call the validate() method for the two rich:calendar instances below.  But I'm not sure if that tag is even necessary b/c it works for the h:inputText w/o that tag (the Seam ref doc example for validator does not show the use of <s:validateAll/>).  Also, the mode="ajax" did not help.


                              You are right, the <s:validateAll> is for model validations. I forgot you are writing a JSF validator. So this may be a problem with the calendar control. You might want to ask on the RF forums. But while we are at it, why did you opt for a JSF validtor? A model validator (Hibernate validator) might make more sense here.


                              I looked at the @Future Hibernate Validator annotation but the problem is that Hibernate Validator restricts you to those validations for those fields always when there is a <s:validate/> or <s:validateAll/> surrounding a entity field in EL expression, for example.


                              So I thought the JSF Seam validator would be a good re-usable alternative.  Another guy had the same problem: http://community.jboss.org/message/521178#521178

                              • 12. Re: Seam Validator not being executed
                                Arbi Sookazian Master

                                Also, @Past or @Future is not possible for this scenario b/c the users tab thru the controls/fields in the form and we need to allow previously saved back-dated (in the past) dates for the oninputblur event, for example.  So I must implement custom logic that compares any newly entered value with the cached value for that field/control.  If live a4j:support validation fails, the focus must be set back to that failed control.  I don't know how to do that in a rich:dataTable when there are multiple rich:calendar components in multiples rows.