package nl.quintor.commons.validator; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; import nl.quintor.commons.util.JSFUtils; import nl.quintor.commons.util.ValidatorMessages; import org.apache.log4j.Logger; /** * The base class for all JSF validators in any JSF application. Deals with the validation error codes but leaves the * actual validation to subclasses. */ abstract class AbstractValidator implements Validator { private final Logger logger = Logger.getLogger(getClass()); /** * The name of the value being validated, used for logging purposes. A default can be set by validator subclasses * and overridden by setting the corresponding attribute in the validator tags in the JSF page. */ private String fieldName; /** * Constructor; sets a default value name for logging purposes. */ public AbstractValidator(final String fieldName) { setFieldName(fieldName); } /** * Logs the validation action and delegates the actual validation to the subclass through an abstract method. When * the subclass returns an error code, so when the return value is not null, then a * {@link FacesMessage} will be made with the corresponding error message, either through a message resource bundle * or, if not available, a default message. * * @param context Being used to fetch a message from the resource bundle form the application (if available). * @param component Being passed along by JSF, which we'll just ignore. * @param fieldValue The value that needs to be validated by the subclass. * @see #validate(Object) * @see #getFieldname() * @see #getErrorMessage(String, Object, String) * @see javax.faces.validator.Validator#validate(FacesContext, UIComponent, Object) */ public final void validate(final FacesContext context, final UIComponent component, final Object fieldValue) { logger.debug(String.format("validatie [%s: %s]", fieldName, fieldValue)); final String code = validate(fieldValue); if (code != null) { final String backupMsg = ValidatorMessages.getDefaultMessage(code); final Object[] messageparams = getMessageParams(fieldValue, code); final String msg = JSFUtils.getMessageFromFacesBundle(code, messageparams, backupMsg); final FacesMessage message = getErrorMessage(fieldName, fieldValue, msg); logger.debug(String.format("validatie failed: '%s'", message.getDetail())); throw new ValidatorException(message); } } /** * Returns a default list of parameters to be used in an error message. Can be overridden by subclasses to provide a * custom list of parameters. * * @param fieldValue The value which didn't validate. * @param errorCode The errorCode needed to differentiate between parameters as needed. * @return Returns a default list of parameters to be used in an error message. */ protected Object[] getMessageParams(final Object fieldValue, final String errorCode) { return new Object[] { fieldValue }; } /** * Validates a value and returns an error code if invalid (null otherwise). * * @param fieldValue The actual value being validated. * @return An error code String in case of invalidation or null otherwise. */ protected abstract String validate(final Object fieldValue); /** * Creates a new JSF {@link FacesMessage} with the invalidated value, summary including value's name en a detailed * reason (as provided by the validation algorithm) why validation failed. * * @param fieldName The name of the input field being invalidated. * @param fieldValue The invalidated value itself. * @param detailedMessage The specific reason why validation failed. * @return A {@link FacesMessage} with the validation info which will be used by the JSF validation framework. */ private FacesMessage getErrorMessage(final String fieldName, final Object fieldValue, final String detailedMessage) { final FacesMessage message = new FacesMessage(); message.setDetail(detailedMessage); message.setSummary(String.format("%s '%s' is invalid", fieldName, fieldValue)); message.setSeverity(FacesMessage.SEVERITY_ERROR); return message; } /** * A bean setter for the value's name; the name representing the value being validated. This is a property that can * be specified on the validator tags in the JSP page. * * @param fieldName The name representing the value being validated. */ public final void setFieldName(final String fieldName) { this.fieldName = fieldName; } }