2011-04-24

RichFaces 4: AJAX validation feedback

In my previous post I showed you how to create a simple Maven based RichFaces 4 project. In this post I will show you how to provide a nice dynamic status for JSR-303 validation that may take a long time (check if user name is unique for instance).

AJAX feedback

Download sample code


Please note that I’ve been working a bit on the sample app so it has changed a little from its previous version. Therefore if you want to look at the source, please download the new version of my sample Maven 3, RichFaces 4, JSF 2 app.

The form


    <h:form rendered="#{!sessionTracker.loggedIn}">
       <rich:panel>
           <h:panelGrid columns="3">
               <h:outputText value="#{msg['registration.email']}" />
               <h:inputText id="email" value="#{registrationBean.email}">
                   <rich:validator />
               </h:inputText>
               <rich:message for="email" />

               <h:outputText value="#{msg['registration.name']}" />
               <h:inputText id="name" value="#{registrationBean.name}"
                   status="nameStatus">
                   <rich:validator status="nameStatus" />
               </h:inputText>
               <h:panelGroup>
                   <a4j:status name="nameStatus"
                       startText="#{msg['registration.checkingName']}"
                       startStyle="background-color: FFA500" />
                   <rich:message for="name" />
               </h:panelGroup>

               <h:commandButton value="#{msg['registration.register']}"
                   action="#{registrationBean.register}" />
           </h:panelGrid>
       </rich:panel>
   </h:form>

Backing bean


    @NotNull(message = "{rf.name.notNull}")
   @Size(min = 2, message = "{rf.name.size}")
   @ValidUserName
   public String getName() {
       return name;
   }

Validation


import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class ValidUserNameValidator implements
       ConstraintValidator<ValidUserName, String> {

   private Logger log = LoggerFactory.getLogger(ValidUserNameValidator.class);

   private String[] forbiddenNames = { "Michal", "Mikey", "Mickey", "M1key",
           "M1ckey" };

   @Override
   public void initialize(ValidUserName firstUpper) {
       // See JSR 303 Section 2.4.1 for sample implementation.
   }

   @Override
   public boolean isValid(String value, ConstraintValidatorContext context) {
       log.debug("Validating.");

       if (value == null || value.length() == 0) {
           return true;
       }

       // Let's simulate a costly operation.
       try {
           Thread.sleep(1000);
       } catch (InterruptedException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }

       return isNotForbidden(value);
   }


To see it working, download the source code. It expects you to run it on JBoss 6.0.0.Final.

2011-04-05

RichFaces 4: JSR 303 Validation

RichFaces 4 is out! In this article I will demonstrate one of the new features - JSR 303 validation with RichFaces 4.

RichFaces supports JSF 2, so I decided to write a small sample app that takes advantage of other JSF 2 goodies as well. Download the source code of this sample Maven 3 application that runs on JBoss 6 and see these in action (in simple action):
  • standard JSR 303 validation
  • custom JSR 303 validation
  • CDI
  • SLF4J
  • JSF 2


Standard JSR-303 Validation


First, look at this sample registration form.

    <h:form>
       <rich:panel>
           <h:panelGrid columns="3">
               <h:outputText value="Email:" />
               <h:inputText id="email" value="#{registration.email}">
                   <rich:validator />
               </h:inputText>
               <rich:message for="email" />

               <h:outputText value="Name:" />
               <h:inputText id="name" value="#{registration.name}">
                   <rich:validator />
               </h:inputText>
               <rich:message for="name" />

               <a4j:commandButton value="Register"
                   action="#{registration.register}" render="length" />
           </h:panelGrid>
       </rich:panel>
   </h:form>

Registration

What’s worth noting is the rich:validator element. That activates JSR 303 validation for that field. Let’s look at the corresponding managed bean.

package me.m1key.rf;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@ManagedBean
@RequestScoped
public class Registration {
   
   @Inject
   private SessionTracker sessionTracker;

   private String email;
   private String name;

   @NotNull(message = "{rf.email.notNull}")
   @Pattern(message = "{rf.email.pattern}", regexp = "...")
   public String getEmail() {
       return email;
   }

   @NotNull(message = "{rf.name.notNull}")
   @Size(min = 2, message = "{rf.name.size}")
   public String getName() {
       return name;
   }
I spared you the regular expression for email validation. What’s cool about it? This gives you both automatic client-side and server side (in case someone turned off their JavaScript, for instance) validation.


Custom JSR-303 Validation


You might also annotate fields with your own validators. They will be picked up as well.

    @ValidUserName
   public String getName() {
       return name;
   }

@Documented
@Constraint(validatedBy = ValidUserNameValidator.class)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidUserName {
   String message() default "{rf.validUserName}";

   Class<?>[] groups() default {};

   Class<? extends Payload>[] payload() default {};
}

public class ValidUserNameValidator implements
       ConstraintValidator<ValidUserName, String> {
   
   private Logger log = LoggerFactory.getLogger(ValidUserNameValidator.class);

   private String[] forbiddenNames = { "Michal", "Mikey", "Mickey", "M1key",
           "M1ckey" };

   @Override
   public void initialize(ValidUserName firstUpper) {
       // See JSR 303 Section 2.4.1 for sample implementation.
   }

   @Override
   public boolean isValid(String value, ConstraintValidatorContext context) {
       log.info("Validating");
       
       if (value == null || value.length() == 0) {
           return true;
       }


       return isNotForbidden(value);
   }

   private boolean isNotForbidden(String name) {
       return !isForbidden(name);
   }

   private boolean isForbidden(String name) {
       for (String forbiddenName : forbiddenNames) {
           if (name.equals(forbiddenName)) {
               return true;
           }
       }
       return false;
   }
}

CDI and other goodies


I will describe it in another blog post, but you can check it out already by downloading the source code. What I will also describe is how to add dynamic Ajax statuses for fields which validation takes long time.