FileDocCategorySizeDatePackage
LaterThanValidator.javaAPI DocExample4426Tue Jun 08 11:26:42 BST 2004com.mycompany.jsf.validator

LaterThanValidator.java

package com.mycompany.jsf.validator;

import java.text.MessageFormat;
import java.io.Serializable;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

/**
 * This class is a JSF Validator that validates that the java.util.Date
 * value of the component it's attached to is later than the 
 * java.util.Date value of another component.
 *
 * @author Hans Bergsten, Gefion Software <hans@gefionsoftware.com>
 * @version 1.0
 */
public class LaterThanValidator implements Validator, Serializable {
    private String peerId;

    /**
     * Sets the ID for the peer component the main component's
     * value is compared to. It must be a format that can be
     * used with the javax.faces.component.UIComponent findComponent()
     * method.
     */
    public void setPeerId(String peerId) {
        this.peerId = peerId;
    }

    /**
     * Compares the provided value to the value of the peer component,
     * and throws a ValidatorException with an appropriate FacesMessage
     * if the provided value doesn't represent a later date or if
     * there are problems accessing the peer component value.
     */
    public void validate(FacesContext context, UIComponent component,
			 Object value) throws ValidatorException {

        Application application = context.getApplication();

	/* Note! This validator requires an application bundle
	 * that holds the messages. For validators, or other
	 * components, that should be usable in any application,
	 * bundling a default bundle and use it if the message
	 * isn't available in the application bundle is a nicer
	 * approach.
	 */
	String messageBundleName = application.getMessageBundle();
	Locale locale = context.getViewRoot().getLocale();
	ResourceBundle rb = 
	    ResourceBundle.getBundle(messageBundleName, locale);

        UIComponent peerComponent = component.findComponent(peerId);
        if (peerComponent == null) {
	    String msg = rb.getString("peer_not_found");
	    FacesMessage facesMsg = 
		new FacesMessage(FacesMessage.SEVERITY_FATAL, msg, msg);
	    throw new ValidatorException(facesMsg);
        }
        
        ValueHolder peer = null;
        try {
            peer = (ValueHolder) peerComponent;
        }
        catch (ClassCastException e) {
	    String msg = rb.getString("invalid_component");
	    FacesMessage facesMsg = 
		new FacesMessage(FacesMessage.SEVERITY_FATAL, msg, msg);
	    throw new ValidatorException(facesMsg);
        }
	if (peer instanceof EditableValueHolder &&
	    !((EditableValueHolder) peer).isValid()) {
	    // No point in validating against an invalid value
	    return;
	}
	
        Object peerValue = peer.getValue();
        if (!(peerValue instanceof Date)) {
	    String msg = rb.getString("invalid_peer");
	    FacesMessage facesMsg = 
		new FacesMessage(FacesMessage.SEVERITY_FATAL, msg, msg);
	    throw new ValidatorException(facesMsg);
        }
        
        if (!(value instanceof Date) || 
            !((Date) value).after((Date) peerValue)) {
	    String msg = rb.getString("not_later");
	    String detailMsgPattern = rb.getString("not_later_detail");
	    Object[] params = 
	        {formatDate((Date) peerValue, context, component)};
	    String detailMsg = 
		MessageFormat.format(detailMsgPattern, params);
	    FacesMessage facesMsg = 
		new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, detailMsg);
	    throw new ValidatorException(facesMsg);
        }
    }

    /**
     * Returns the provided Date formatted with the converter attached
     * to the component, if any, or with toString() otherwise.
     */
    private String formatDate(Date date, FacesContext context, 
        UIComponent component) {
        Converter converter = ((ValueHolder) component).getConverter();
        if (converter != null) {
            return converter.getAsString(context, component, date);
        }
        return date.toString();
    }
}