/**
* Copyright (c) 2009--2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.common.validator;
import com.redhat.rhn.common.localization.LocalizationService;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* <p>
* The <code>Validator</code> class allows an application component or client
* to provide data, and determine if the data is valid for the requested type.
* </p>
*
* This code was copied from:
*
* http://www.javaworld.com/javaworld/jw-09-2000/jw-0908-validation.html
*
* There were no appearent license restrictions on this code, the Author
* indicated it was free and available to be used by readers of the article.
*
* @version $Rev$
*/
public class Validator {
private static Logger log = Logger.getLogger(Validator.class);
/** The instances of this class for use (singleton design pattern) */
private static Map instances = null;
/** The URL of the XML Schema for this <code>Validator</code> */
private URL schemaURL;
/** The constraints for this XML Schema */
private Map constraints;
/**
* <p>
* This constructor is private so that the class cannot be instantiated
* directly, but instead only through <code>{@link #getInstance()}</code>.
* </p>
*
* @param schemaURLIn <code>URL</code> to parse the schema at.
* @throws IOException - when errors in parsing occur.
*/
private Validator(URL schemaURLIn) throws IOException {
this.schemaURL = schemaURLIn;
// parse the XML Schema and create the constraints
SchemaParser parser = new SchemaParser(schemaURL);
constraints = parser.getConstraints();
}
/**
* <p>
* This will return the instance for the specific XML Schema URL. If a
* schema exists, it is returned (as parsing will already be done);
* otherwise, a new instance is created, and then returned.
* </p>
*
* @param schemaURL <code>URL</code> of schema to validate against.
* @return <code>Validator</code>- the instance, ready to use.
* @throws IOException when errors in parsing occur.
*/
public static synchronized Validator getInstance(URL schemaURL)
throws IOException {
if (instances != null) {
if (instances.containsKey(schemaURL.toString())) {
return (Validator) instances.get(schemaURL.toString());
}
Validator validator = new Validator(schemaURL);
instances.put(schemaURL.toString(), validator);
return validator;
}
instances = new HashMap();
Validator validator = new Validator(schemaURL);
instances.put(schemaURL.toString(), validator);
return validator;
}
/**
* <p>
* This will validate a data value (in <code>String</code> format) against
* a specific constraint, and return <code>true</code> if that value is
* valid for the constraint.
* </p>
*
* @param constraintName the identifier in the constraints to validate this
* data against.
* @param objToValidate <code>String</code> data to validate.
* @return ValidatorError whether the data is valid or not.
* TODO: rename this method to something other than isValid()
*/
public ValidatorError isValid(String constraintName, Object objToValidate) {
// Validate against the correct constraint
Object o = constraints.get(constraintName);
log.debug("Validating: " + constraintName);
// If no constraint, then everything is valid
if (o == null) {
log.debug("No constraint found for " + constraintName);
return null;
}
ParsedConstraint constraint = (ParsedConstraint) o;
// Get the field we want to check
Object value = null;
try {
value = PropertyUtils.getProperty(objToValidate,
constraint.getIdentifier());
}
catch (Exception e) {
String errorMessage = "Exception trying to get bean property: " +
e.toString();
log.error(errorMessage, e);
throw new ValidatorException(errorMessage, e);
}
// TODO: Get rid of the toString and determine the type
String data = (value == null) ? null : value.toString();
ValidatorError validationMessage = null;
log.debug("Data: " + data);
log.debug("Constraint: " + constraint);
boolean required = !constraint.getOptional() ||
(value != null && !value.equals(""));
if (required) {
boolean checkConstraint = true;
if (constraint instanceof RequiredIfConstraint) {
checkConstraint = ((RequiredIfConstraint) constraint).
isRequired(data, objToValidate);
log.debug("RequiredIf indicates:" + required);
}
if (checkConstraint) {
// Validate data type
validationMessage = correctDataType(data, constraint);
if (validationMessage != null) {
log.debug("Not the right datatype.. " + validationMessage);
return validationMessage;
}
validationMessage = constraint.checkConstraint(data);
if (validationMessage != null) {
log.debug("Failed: " + validationMessage);
return validationMessage;
}
}
}
log.debug("All is OK, returning true ...");
return null;
}
/**
* Get the list of Contraints associated with this Validator
*
* @return List of Constraint objects
*/
public List getConstraints() {
return new LinkedList(constraints.values());
}
/**
* <p>
* This will test the supplied data to see if it can be converted to the
* Java data type given in <code>Constraint.dataType</code>.
* </p>
*
* @param data <code>String</code> to test data type of.
* @param constraint <code>Constraint</code> Constraint to be checked.
* @return <code>ValidatorError</code>- or null, if there are no errors.
*/
private ValidatorError correctDataType(String data, Constraint constraint) {
ValidatorError validationMessage = null;
String dataType = constraint.getDataType();
String identifier =
LocalizationService.getInstance().getMessage(constraint.getIdentifier());
/* code does not change anything, leaving just for demonstration
if ((dataType.equals("String")) || (dataType.equals("java.lang.String"))) {
validationMessage = null;
}
else
*/
if ((dataType.equals("int")) || (dataType.equals("java.lang.Integer"))) {
try {
Integer.parseInt(data);
}
catch (NumberFormatException e) {
validationMessage = new ValidatorError("errors.integer", identifier);
}
}
else if ((dataType.equals("long")) || (dataType.equals("java.lang.Long"))) {
try {
Long.parseLong(data);
}
catch (NumberFormatException e) {
validationMessage = new ValidatorError("errors.long", identifier);
}
}
else if ((dataType.equals("float")) || (dataType.equals("java.lang.Float"))) {
try {
Float.parseFloat(data);
}
catch (NumberFormatException e) {
validationMessage = new ValidatorError("errors.float", identifier);
}
}
else if ((dataType.equals("double")) || (dataType.equals("java.lang.Double"))) {
try {
Double.parseDouble(data);
}
catch (NumberFormatException e) {
validationMessage = new ValidatorError("errors.double", identifier);
}
}
else if (dataType.equals("java.lang.Boolean")) {
if ((data.equalsIgnoreCase("true")) ||
(data.equalsIgnoreCase("false")) ||
(data.equalsIgnoreCase("yes")) ||
(data.equalsIgnoreCase("no"))) {
// empty
// validationMessage = null;
}
else {
validationMessage = new ValidatorError("errors.invalid", identifier);
}
}
return validationMessage;
}
}