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;
}
}