com.ylw.enterprise.validation.bean.AbstractValidationBean Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Validation Show documentation
Show all versions of Validation Show documentation
A Java web validation framework
/**
* This file is part of
*
* Copyright (C) 2014-2015 The YLW-Java-Validation-Framework Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ylw.enterprise.validation.bean;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import org.apache.log4j.Logger;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.ylw.enterprise.validation.binder.AbstractBeanBinder;
import com.ylw.enterprise.validation.binder.FieldBinder;
import com.ylw.enterprise.validation.error.BeanError;
import com.ylw.enterprise.validation.error.ErrorMessage;
import com.ylw.enterprise.validation.error.FieldError;
import com.ylw.enterprise.validation.error.FieldErrorCode;
import com.ylw.enterprise.validation.validator.AbstractProjectValidator;
import com.ylw.enterprise.validation.validator.FieldValidator;
import com.ylw.enterprise.validation.validator.ValidationRule;
public abstract class AbstractValidationBean {
private static final Logger LOGGER = Logger.getLogger(AbstractValidationBean.class);
// --------------Field text format----------------
protected String dateFormat = "MM/dd/yyyy";
public String getDateFormat() {
return dateFormat;
}
public void setDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
}
// --------------------Binding----------------------
private final Map formKeyMap = Maps.newTreeMap();
private String beanName;
public Map getFormKeyMap() {
return formKeyMap;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/**
* The default form key map beanName.fieldName
* beanName can be set or use class name if not
*/
private void buildDefaultFormKeyMap() {
// beanName - use class name if not set
if (beanName == null) {
beanName = this.getClass().getSimpleName();
}
// Get all fields of this bean
Field[] fields = this.getClass().getDeclaredFields();
// Build default form key map for each field in this bean
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String fieldName = field.getName();
// Add the field form key to form key map
formKeyMap.put(fieldName, beanName + "." + fieldName);
}
LOGGER.info(this.getClass().getSimpleName() + " default form key map: " + formKeyMap);
}
/**
* Build Form Key Map
*/
public void buildFormKeyMap() {
// Build default form key map
buildDefaultFormKeyMap();
// Customize base on form keys defined in FormKey class
Class> formKeyClass = getFormKeyClass();
if (formKeyClass != null) {
// If form key class defined
Field[] fields = formKeyClass.getDeclaredFields();
// Get value for form key of each field and put them in to form key map
String key = null;
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
try {
key = (String) field.get(this);
}
catch (IllegalArgumentException | IllegalAccessException | ClassCastException e) {
// Error happened when retrieve key from FormKey
LOGGER.info("Error happened when retrieve key from FormKey");
e.printStackTrace();
}
// Put the form key into the map
if (key != null) {
formKeyMap.put(field.getName(), key);
}
}
}
LOGGER.info(this.getClass().getSimpleName() + " Form Key Map: " + formKeyMap);
}
/**
* Check if the FormKey nested class declared in the sub class. FormKey class is where the customized form key for
* each field defined. Form keys in this class will be used in the form and data binding logic.
*
* @return true - if the class is declared; false - if not
*/
private boolean isFormKeyClassDefined() {
Class> cl = getClass();
// Loop through all declared class and see if the FormKey class defined
for (Class> innerClass : cl.getDeclaredClasses()) {
if (innerClass.getSimpleName().equals("FormKey")) {
return true;
}
LOGGER.info(innerClass.getCanonicalName());
}
return false;
}
/**
* Get FormKey class if it is defined in the sub class
*/
public Class> getFormKeyClass() {
// Get class of this bean
Class> thisClass = this.getClass();
// Loop through all declared class and get the FormKey class defined
for (Class> innerClass : thisClass.getDeclaredClasses()) {
if (innerClass.getSimpleName().equals("FormKey")) {
// Return FormKey class if defined
return innerClass;
}
LOGGER.info(innerClass.getCanonicalName());
}
// Return null if FormKey class not defined
return null;
}
/**
* Bind this bean from HTTP request form parameters
*
* @param parameterMap
* - parameter map from web request
* @return this instance
*/
public AbstractValidationBean bind(@Nonnull Map parameterMap) {
FieldError error;
// get all fields of this bean
Field[] fields = this.getClass().getDeclaredFields();
// bind parameter to each matching field
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String[] stringValues = parameterMap.get(field.getName());
if (stringValues != null) {
// found a match - bind to the field
error = FieldBinder.bindToField(this, field, stringValues);
// add error
if (error != null) {
errors.add(error);
}
}
}
// return this bean
return this;
}
public AbstractValidationBean bind(@Nonnull AbstractBeanBinder binder) {
// return the binded bean
return binder.bind();
}
// -------------------Validation---------------------
// A set of error messages
protected final Set errors = Sets.newHashSet();
private final Map> fieldErrorMap = Maps.newTreeMap();
/* Deal with errors */
public Set getErrors() {
return errors;
}
public void addError(BeanError error) {
errors.add(error);
}
/**
* Construct and add error from general error message
*
* @param message
*/
public void addError(String message) {
addError(new BeanError(message));
}
/** See if there are errors in this object */
public boolean hasError() {
return !errors.isEmpty() || !fieldErrorMap.isEmpty();
}
/**
* Clear both object and field errors - normally do this before bind and validate
*
* @return this instance
*/
public AbstractValidationBean clearErrors() {
// Clear object errors
errors.clear();
// Clear field errors
fieldErrorMap.clear();
// return this bean
return this;
}
/* Deal with field errors */
public Map> getFieldErrorMap() {
return fieldErrorMap;
}
/**
* @return Validation Rule Builder
*/
protected ValidationRule.Builder onRule() {
return ValidationRule.Builder.defaultValues();
}
/**
* Override this method to specify validation rule for each field in the object and validate.
*/
public abstract AbstractValidationBean validate();
/**
* Validate the field base on the validation rule with customized error message
*
* @param fieldName
* @param fieldValue
* @param validationRule
* @param errorMessage
* - customized error message
*/
protected void validate(String fieldName, Object fieldValue, ValidationRule validationRule, String errorMessage) {
validate(validationRule, fieldName, fieldValue, errorMessage);
}
/**
* Validate the field base on the validation rule with customized error message code
*
* @param fieldName
* @param fieldValue
* @param validationRule
* @param message
* - customized error code
*/
protected void validate(String fieldName, Object fieldValue, ValidationRule validationRule, ErrorMessage message) {
validate(validationRule, fieldName, fieldValue, message);
}
/**
* Validate the field base on the validation rule
*
* @param fieldName
* @param fieldValue
* @param validationRule
*/
protected void validate(String fieldName, Object fieldValue, ValidationRule validationRule) {
validate(validationRule, fieldName, fieldValue, null);
}
/*
* Validate field value base on validation rule Create error base on error code or customized error
*/
private void validate(ValidationRule validationRule, String fieldName, Object fieldValue, Object customError) {
// Validate
FieldValidator validator = new FieldValidator(validationRule);
FieldErrorCode fieldErrorCode = validator.validate(fieldValue);
// Deal with violated rules and add field error to errors if any
if (fieldErrorCode != null) {
// There is error - build error object
FieldError error = new FieldError(fieldName, fieldErrorCode);
if (customError == null) {
// build error object base on error code
error = new FieldError(fieldName, fieldErrorCode);
}
else {
if (customError instanceof ErrorMessage) {
error = new FieldError(fieldName, ((ErrorMessage) customError).getMessage());
}
else
if (customError instanceof String) {
error = new FieldError(fieldName, (String) customError);
}
else {
LOGGER.warn("Unricegnized customized message -> " + customError);
}
}
// Add field error
addFieldError(fieldName, error);
}
}
/*
* Add field error to error set and field error map
*/
private void addFieldError(String fieldName, FieldError error) {
// Add error to the object error set
errors.add(error);
// add to the field error map
Set fieldErrors = fieldErrorMap.get(fieldName);
if (fieldErrors == null) {
fieldErrors = Sets.newHashSet();
}
fieldErrors.add(error);
fieldErrorMap.put(fieldName, fieldErrors);
}
/* Project Specific Validation */
private AbstractProjectValidator projectValidator;
/**
*
* Create project specific Validator extends {@link AbstractProjectValidator} Set the validator here so the
* validation framework can call the customized validation logic
*
* @param projectValidator - project specific validator
*/
public void setProjectValidator(AbstractProjectValidator projectValidator) {
this.projectValidator = projectValidator;
}
/**
* Call project validator to verify customized validation logic
* @param customized validation method
* @return true/false based on verification result
*/
protected boolean verify(String methodName) {
// Check the instance of project specific validator
LOGGER.info("The instance of project validator -> " + projectValidator);
Preconditions.checkNotNull(projectValidator, "Please instantiate the project specific validator and set it here");
// call the customized validation method
try {
// Get the method
Method method = projectValidator.getClass().getMethod(methodName);
// call the method
return (boolean) method.invoke(projectValidator);
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NoSuchMethodException | SecurityException e) {
// Can not get the method
LOGGER.info("Can not get method -" + methodName + "- in class -" + projectValidator.getClass().getName());
e.printStackTrace();
}
// return false by default
return false;
}
}