title: rich:calendar native validation hides/overwrites/?? my bean validation errors
body: <p>My application uses rich:calendars and h:inputText.  If I put input bad data in the UI for the intputText (i.e. non-numeric data) and press "Search" I get the proper error message from the bean.  However, if I put in invalid data in both the inputText (non-numeric) and the rich:calendar(non-date related input such as "foo"), I only get the rich:calendar error messages back.  It is as if the native rich calendar validation messages knocks out the bean validation messages.</p>
  
  <p>How do I get all messages to display?</p>
  
  <p>The xhtml code is as follows:</p>
  
  <pre><code>    &lt;html xmlns:f="http://java.sun.com/jsf/core"
        xmlns:ui="http://java.sun.com/jsf/facelets" xmlns="http://www.w3.org/1999/xhtml"
        xmlns:a4j="http://richfaces.org/a4j"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:tr="http://myfaces.apache.org/trinidad"
        xmlns:rich="http://richfaces.org/rich"&gt;
  &lt;f:view&gt;
      &lt;br/&gt;
      &lt;div class="container"&gt;
      &lt;tr:form id="searchCriteria" defaultCommand="appealSearchManager.search"&gt;
          &lt;a4j:outputPanel id="errorMessagesPanel"&gt;
              &lt;h:messages id="errorMessages"/&gt;
          &lt;/a4j:outputPanel&gt;
          &lt;div class="div30"&gt;
              &lt;p&gt;&lt;h:outputText value="#{messages.ProgramInvoiceId}"/&gt;&lt;/p&gt;
              &lt;h:inputText id="programInvoiceId" value="#{appealSearchManager.programInvoiceId}"/&gt;
          &lt;/div&gt;
          &lt;div class="div30"&gt;
          &lt;p&gt;&lt;h:outputText value="#{messages.ResponseReleaseDate}"/&gt;&lt;/p&gt;
          &lt;rich:calendar id="responseReleaseDateBegin"
              enableManualInput="true"  datePattern="MM/dd/yyyy"
              buttonIcon="/images/calendar_icon.jpg" buttonClass="calendar"
              converterMessage="Invalid Response Release begin date.  Format must be blah, blah, blah."
              value="#{appealSearchManager.responseReleaseDateBegin}"&gt;
          &lt;/rich:calendar&gt;
          &lt;rich:calendar id="responseReleaseDateEnd"
              enableManualInput="true"  datePattern="MM/dd/yyyy"
              buttonIcon="/images/calendar_icon.jpg" buttonClass="calendar"
             converterMessage="Invalid Response Release End date.  Format must be blah, blah, blah."
              value="#{appealSearchManager.responseReleaseDateEnd}"&gt;
          &lt;/rich:calendar&gt;
          &lt;/div&gt;
  
          &lt;div class="searchaction"&gt;
              &lt;div&gt;
                  &lt;ul&gt;
  
                      &lt;li&gt;
                          &lt;a4j:commandLink id="searchButton"
                                           value="#{messages.Search}"
                                           actionListener="#{appealSearchManager.search}"
                                           reRender="errorMessagesPanel, richErrorMessages, errorMessages"
                                           styleClass="searchbtn"/&gt;
                      &lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/tr:form&gt;
      &lt;/div&gt;
  &lt;/f:view&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>and the bean code:</p>
  
  <pre><code>    public void search(ActionEvent e) {
      setHasErrors(validateCriteria());
  }
  
  private boolean validateCriteria() {
      boolean isValid = true;
      //always check for Program Invoice ID may contain a comma-separated list of ids
      if (getProgramInvoiceId() != null &amp;&amp; !getProgramInvoiceId().equals("") &amp;&amp; !areValidProgamInvoiceIds(getProgramInvoiceId())) {
          String errorMessage = "Invalid Program Invoice ID.  Must be comma delimited list of numbers.";
          FacesContext.getCurrentInstance().addMessage(null,
                                                       new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, errorMessage));
          isValid = false;
      }
      //check Dates Response Release Date
      if (!isValidDateRange("Response Release Date", getResponseReleaseDateBegin(), getResponseReleaseDateEnd())) {
          isValid = false;
      }
      return isValid;
  }
  
  private boolean areValidProgamInvoiceIds(String ids) {
      boolean validIds = true;
      String regexp = "^([0-9]+(-[0-9]+)*,*)+$";
      Pattern pattern = Pattern.compile(regexp);
      if (!pattern.matcher(ids).matches()) {
          validIds = false;
      }
      return validIds;
  }
  
  private boolean isValidDateRange(String dateRange, Date startDate, Date endDate) {
      boolean isValidDateAndRange = true;
      Calendar futureDate = Calendar.getInstance();
      futureDate.roll(Calendar.DAY_OF_MONTH, 2);
      if ((startDate != null &amp;&amp; (endDate == null || endDate.equals(""))) ||
           ((startDate == null || startDate.equals("")) &amp;&amp; endDate != null)) {
          //one date is null and the other has a value.  We need both values to do a search.
          String errorMessage = "Invalid " + dateRange + " range.  Missing Date. A date range must contain both start and end dates.";
          FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, errorMessage));
      } else if (startDate != null &amp;&amp; endDate != null) {
          if (isValidDateAndRange) {
              //future start dates are not allowed
              if (startDate.after(futureDate.getTime())) {
                  String errorMessage = "Invalid date range.  Start date must be less than today's date.";
                  FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, errorMessage));
                  isValidDateAndRange = false;
              }
              //start date greater than the end date is not allowed
              if (endDate.before(startDate)) {
                  String errorMessage = "Invalid date range.  End date must be greater than or equal to start date.";
                  FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, errorMessage));
                  isValidDateAndRange = false;
              }
          }
      }
      return isValidDateAndRange;
  }
  </code></pre>
  
  <p>Any suggestions would be greatly appreciated.
  Thanks!</p>