All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.droitateddb.DatabaseValidator Maven / Gradle / Ivy

Go to download

droitatedDB is a lightweight framework, which frees you from the burden of dealing with Androids SQLite database directly if you don't want to and let's you access it directly if you have to.

The newest version!
package org.droitateddb;

import org.droitateddb.schema.AbstractAttribute;
import org.droitateddb.schema.ColumnValidator;
import org.droitateddb.schema.EntityInfo;
import org.droitateddb.validation.AccumulatedValidationResult;
import org.droitateddb.validation.CustomValidator;
import org.droitateddb.validation.ValidationResult;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Locale;

import static org.droitateddb.Utilities.getFieldValue;
import static org.droitateddb.Utilities.getStaticFieldValue;

/**
 * Validates entities by their schema definition
 *
 * @author Falk Appel
 * @author Alexander Frank
 */
public class DatabaseValidator {

    public AccumulatedValidationResult validate(Collection toBeValidated) {
        return validate(toBeValidated, Integer.MAX_VALUE);
    }

    public AccumulatedValidationResult validate(Collection toBeValidated, int maxDepth) {
        AccumulatedValidationResult validationResult = new AccumulatedValidationResult();
        Set alreadyValidated = new HashSet();
        for (T data : toBeValidated) {
            validate(data, validationResult, alreadyValidated, 0, maxDepth);
        }
        return validationResult;
    }

    public AccumulatedValidationResult validate(T toBeValidated) {
        return validate(toBeValidated, Integer.MAX_VALUE);
    }

    public AccumulatedValidationResult validate(T toBeValidated, int maxDepth) {
        AccumulatedValidationResult validationResult = new AccumulatedValidationResult();
        Set alreadyValidated = new HashSet();
        validate(toBeValidated, validationResult, alreadyValidated, 0, maxDepth);
        return validationResult;
    }

    private void validate(Object validatingObject, AccumulatedValidationResult validationResult, Set alreadyValidated, int currentDepth, int maxDepth) {
        try {
            EntityInfo entityInfo = SchemaUtil.getEntityInfo(validatingObject.getClass());
            Class definition = entityInfo.definition();
            EntityData entityData = EntityData.getEntityData(validatingObject);

            List allAssociations = entityData.allAssociations;
            if (allAssociations.size() > 0) {
                validateRelationshipsOfEntity(validatingObject, allAssociations, validationResult, alreadyValidated, currentDepth, maxDepth);
            }

            if (entityInfo.hasValidation()) {
                validateColumnsInEntity(validatingObject, definition, entityData.columns, validationResult);
            }
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }


    private void validateColumnsInEntity(Object validatingObject, Class definition, List columns, AccumulatedValidationResult validationResult) throws NoSuchFieldException, IllegalAccessException, InstantiationException, java.lang.reflect.InvocationTargetException, NoSuchMethodException {
        for (Field column : columns) {
            ValidationResult result = checkForValidatorsAndValidate(validatingObject, column, definition);
            if (!result.isValid()) {
                validationResult.addError(result);
            }
        }
    }

    private void validateRelationshipsOfEntity(Object validatingObject, List relationships, AccumulatedValidationResult validationResult, Set alreadyValidated, int currentDepth, int maxDepth) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException, NoSuchFieldException {
        if (currentDepth < maxDepth) {
            for (Field relationship : relationships) {
                getRelatedEntityAndValidate(validatingObject, relationship, validationResult, currentDepth, maxDepth, alreadyValidated);
            }
        }
    }

    private void getRelatedEntityAndValidate(Object validatingObject, Field relationship, AccumulatedValidationResult validationResult, int currentDepth, int maxDepth, Set alreadyValidated) throws IllegalAccessException {
        Object relatedEntity = getFieldValue(validatingObject,relationship);
        if (relatedEntity != null) {
            handleRelatedEntity(relatedEntity, validationResult, currentDepth, maxDepth, alreadyValidated);

        }
    }

    @SuppressWarnings("unchecked")
    private void handleRelatedEntity(Object relatedEntity, AccumulatedValidationResult validationResult, int currentDepth, int maxDepth, Set alreadyValidated) {
        if (Collection.class.isAssignableFrom(relatedEntity.getClass())) {
            handleCollectionRelationship((Collection) relatedEntity, validationResult, currentDepth, maxDepth, alreadyValidated);
        } else {
            checkAlreadyValidatedAndValidate(relatedEntity, validationResult, currentDepth, maxDepth, alreadyValidated);
        }
    }

    private void handleCollectionRelationship(Collection relatedEntity, AccumulatedValidationResult validationResult, int currentDepth, int maxDepth, Set alreadyValidated) {
        for (Object entity : relatedEntity) {
            checkAlreadyValidatedAndValidate(entity, validationResult, currentDepth, maxDepth, alreadyValidated);
        }
    }

    private void checkAlreadyValidatedAndValidate(Object entity, AccumulatedValidationResult validationResult, int currentDepth, int maxDepth, Set alreadyValidated) {
        if (!alreadyValidated.contains(entity)) {
            alreadyValidated.add(entity);
            validate(entity, validationResult, alreadyValidated, currentDepth + 1, maxDepth);
        }
    }

    private ValidationResult checkForValidatorsAndValidate(Object toBeValidated, Field column, Class definition) throws NoSuchFieldException, IllegalAccessException, InstantiationException, java.lang.reflect.InvocationTargetException, NoSuchMethodException {
        AbstractAttribute attribute = getStaticFieldValue(definition,column.getName().toUpperCase(Locale.US));
        ColumnValidator[] columnValidators = attribute.getColumnValidators();
        if (columnValidators.length > 0) {
            return validateColumn(toBeValidated, attribute, columnValidators);
        }
        return ValidationResult.valid();
    }

    @SuppressWarnings("unchecked")
    private ValidationResult validateColumn(Object toBeValidated, AbstractAttribute attribute, ColumnValidator[] columnValidators) throws NoSuchFieldException, IllegalAccessException, InstantiationException, java.lang.reflect.InvocationTargetException, NoSuchMethodException {
        Object entityValue = getFieldValue(toBeValidated.getClass(),attribute.fieldName(),toBeValidated);
        for (ColumnValidator columnValidator : columnValidators) {
            Class validatorAnnotation = columnValidator.getValidatorAnnotation();
            Class proxyClass=null;
            try {
                proxyClass = Proxy.getProxyClass(DatabaseValidator.class.getClassLoader(), validatorAnnotation);
            } catch (IllegalArgumentException iae) {
                proxyClass = Proxy.getProxyClass(Thread.currentThread().getContextClassLoader(), validatorAnnotation);
            }
            Annotation annotationInstance = (Annotation) proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(new Object[]{new DatabaseValidatorAnnotationHandler(columnValidator.getParams())});

            Class> validatorClass = columnValidator.getValidatorClass();
            CustomValidator customValidator = (CustomValidator) validatorClass.getConstructor().newInstance();


            ValidationResult result = customValidator.onValidate(validatorAnnotation.cast(annotationInstance), entityValue);
            if (!result.isValid()) {
                return result;
            }
        }
        return ValidationResult.valid();
    }

}