org.opentestsystem.authoring.testauth.validation.AbstractDomainValidator.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testauth.validation.AbstractDomainValidator.java

Source

/*******************************************************************************
 * Educational Online Test Delivery System
 * Copyright (c) 2013 American Institutes for Research
 * 
 * Distributed under the AIR Open Source License, Version 1.0
 * See accompanying file AIR-License-1_0.txt or at
 * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf
 ******************************************************************************/
package org.opentestsystem.authoring.testauth.validation;

import java.util.Collection;

import org.apache.commons.lang.StringUtils;
import org.opentestsystem.authoring.testauth.domain.ItemSelectionAlgorithmParameter;
import org.opentestsystem.authoring.testauth.domain.ItemSelectionParameterElement;
import org.opentestsystem.authoring.testauth.domain.ItemSelectionType;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;

public abstract class AbstractDomainValidator implements Validator {
    public static final int MAX_STRING_LENGTH = 60;
    public static final int MAX_PARSEABLE_LENGTH = 18;

    protected static final String MSG_REQUIRED = ".required";
    protected static final String MSG_REQUIRED_EMPTY = ".required.empty";
    protected static final String MSG_REQUIRED_CONTAINS = ".required.contains";
    protected static final String MSG_PARSEABLE_NUMBER = ".parseable.number";
    protected static final String MSG_PARSEABLE_BOOLEAN = ".parseable.boolean";
    protected static final String MSG_LENGTH_MAX = ".length.max";
    protected static final String MSG_LENGTH_MIN = "length.min";

    protected static final String MSG_COUNT = ".count";
    protected static final String MSG_DUPLICATES = ".duplicates";
    protected static final String MSG_INVALID = ".invalid";
    protected static final String MSG_MIN = ".min";
    protected static final String MSG_LESS_THAN_MAX = ".lessthan.max";
    protected static final String MSG_WITHIN_MIN_MAX = ".within.minmax";

    protected static final String MSG_TYPE_NOT_RECOGNIZED = ".type.not.recognized";
    protected static final String MSG_INVALID_SELECTION = ".invalid.selection";
    protected static final String MSG_OUT_OF_RANGE = ".out.of.range";

    private static final class ITEM_SELECTION_VALUE_FILTER implements Predicate<ItemSelectionParameterElement> {
        private final String value;

        public static ITEM_SELECTION_VALUE_FILTER getInstance(final String value) {
            return new ITEM_SELECTION_VALUE_FILTER(value);
        }

        private ITEM_SELECTION_VALUE_FILTER(final String value) {
            this.value = value;
        }

        @Override
        public boolean apply(final ItemSelectionParameterElement element) {
            return element.getName() != null && element.getName().equals(this.value);
        }
    };

    protected abstract String getErrorMessageRoot();

    protected void rejectIfTooLong(final Errors errors, final String fieldName, final int maxLength,
            final Object... errorArgs) {
        final Object value = errors.getFieldValue(fieldName);
        if (!org.springframework.util.StringUtils.isEmpty(value)) {
            final int size = value.toString().length();
            if (size > maxLength) {
                rejectValue(errors, fieldName, getErrorMessageRoot() + fieldName + MSG_LENGTH_MAX,
                        flattenArgs(errorArgs, maxLength));
            }
        }
    }

    protected void rejectIfTooShort(final Errors errors, final String fieldName, final int minLength,
            final Object... errorArgs) {
        final Object value = errors.getFieldValue(fieldName);
        if (!org.springframework.util.StringUtils.isEmpty(value)) {
            final int size = value.toString().length();
            if (size < minLength) {
                rejectValue(errors, fieldName, getErrorMessageRoot() + fieldName + MSG_LENGTH_MIN,
                        flattenArgs(errorArgs, minLength));
            }
        }
    }

    protected void rejectIfNotBooleanParseable(final Errors errors, final String fieldName,
            final Object... errorArgs) {
        final Object value = errors.getFieldValue(fieldName);
        if (!org.springframework.util.StringUtils.isEmpty(value)) {
            if (!Boolean.FALSE.toString().equals(value.toString())
                    && !Boolean.TRUE.toString().equals(value.toString())) {
                rejectValue(errors, fieldName, getErrorMessageRoot() + fieldName + MSG_PARSEABLE_BOOLEAN,
                        errorArgs);
            }
        }
    }

    protected void rejectIfNotFloatOrIntegerParseable(final Errors errors, final String fieldName,
            final boolean parseFloat, final Object... errorArgs) {
        final Object value = errors.getFieldValue(fieldName);
        if (!org.springframework.util.StringUtils.isEmpty(value)
                && value.toString().length() <= MAX_PARSEABLE_LENGTH) {
            if (!isFloatOrIntegerParseable(value.toString(), parseFloat)) {
                rejectValue(errors, fieldName, getErrorMessageRoot() + fieldName + MSG_PARSEABLE_NUMBER, errorArgs);
            }
        }
    }

    protected boolean isFloatOrIntegerParseable(final String fieldValue, final boolean isFloat) {
        if (StringUtils.isNotEmpty(fieldValue) && fieldValue.toString().length() <= MAX_PARSEABLE_LENGTH) {
            try {
                if (isFloat) {
                    Float.parseFloat(fieldValue);
                } else {
                    Long.parseLong(fieldValue);
                }
                return true;
            } catch (final NumberFormatException e) {
                return false;
            }
        }
        return false;
    }

    protected void rejectIfEmpty(final Errors e, final String fieldName, final Object... errorArgs) {
        final String errorCode = getErrorMessageRoot() + fieldName + MSG_REQUIRED;
        ValidationUtils.rejectIfEmpty(e, fieldName, errorCode, errorArgs, errorCode);
    }

    protected void rejectIfNotEmpty(final Errors e, final String fieldName, final Object... errorArgs) {
        final Object value = e.getFieldValue(fieldName);
        if (value != null && StringUtils.isNotEmpty(value.toString())) {
            rejectValue(e, fieldName, getErrorMessageRoot() + fieldName + MSG_REQUIRED_EMPTY, errorArgs);
        }
    }

    protected void rejectIfCollectionEmpty(final Errors e, final String fieldName, final Object... errorArgs) {
        final Collection<?> value = (Collection<?>) e.getFieldValue(fieldName);
        if (value == null || value.isEmpty()) {
            rejectValue(e, fieldName, getErrorMessageRoot() + fieldName + MSG_REQUIRED, errorArgs);
        }
    }

    protected void rejectIfCollectionNotEmpty(final Errors e, final String fieldName, final Object... errorArgs) {
        final Collection<?> value = (Collection<?>) e.getFieldValue(fieldName);
        if (value != null && !value.isEmpty()) {
            rejectValue(e, fieldName, getErrorMessageRoot() + fieldName + MSG_REQUIRED_EMPTY, errorArgs);
        }
    }

    protected void rejectIfNotInCollection(final Errors e, final String fieldName,
            final Collection<String> collection, final Object... errorArgs) {
        final Object value = e.getFieldValue(fieldName);
        if (!org.springframework.util.StringUtils.isEmpty(value) && collection != null && !collection.isEmpty()) {
            if (!collection.contains(value.toString())) {
                rejectValue(e, fieldName, getErrorMessageRoot() + fieldName + MSG_REQUIRED_CONTAINS,
                        flattenArgs(errorArgs, collection.toString()));
            }
        }

    }

    protected void rejectValue(final Errors e, final String fieldName, final String errorCode,
            final Object... errorArgs) {
        e.rejectValue(fieldName, errorCode, errorArgs, errorCode);
    }

    protected void validateParameterValue(final String parameterValue, final String parametersFieldName,
            final ItemSelectionAlgorithmParameter algorithmParameter, final Errors errors) {
        final Object[] errorArgs = new Object[] { algorithmParameter.getItemSelectionType().name(), parameterValue,
                algorithmParameter.getMinimumValue(), algorithmParameter.getMaximumValue() };

        if (StringUtils.isEmpty(parameterValue)) {
            rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_REQUIRED);
        } else {
            switch (algorithmParameter.getItemSelectionType()) {
            case FLOAT:
            case INTEGER:
                if (parameterValue.length() > MAX_PARSEABLE_LENGTH) {
                    rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_LENGTH_MAX,
                            MAX_PARSEABLE_LENGTH);
                } else {
                    rejectIfNotWithinNumericConstraints(parameterValue, parametersFieldName, errors,
                            algorithmParameter, errorArgs);
                }
                break;
            case BOOLEAN:
                if (!Boolean.TRUE.toString().equals(parameterValue)
                        && !Boolean.FALSE.toString().equals(parameterValue)) {
                    rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_INVALID, errorArgs);
                }
                break;
            case LIST:
                if (!Iterables.tryFind(algorithmParameter.getItemSelectionList(),
                        ITEM_SELECTION_VALUE_FILTER.getInstance(parameterValue)).isPresent()) {
                    rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_INVALID_SELECTION);
                }
                break;
            case STRING:
                if (parameterValue.length() > MAX_STRING_LENGTH) {
                    rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_LENGTH_MAX,
                            MAX_STRING_LENGTH);
                }
                break;
            default:
                rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_TYPE_NOT_RECOGNIZED);
                break;
            }
        }
    }

    /**
     * when an ItemSelectionAlgorithmParameter is defined as a numeric type (FLOAT or INTEGER), every instance
     * must be of that numeric type and fall within the range boundary of the ItemSelectionAlgorithmParameter MIN & MAX values
     */
    private void rejectIfNotWithinNumericConstraints(final String fieldValue, final String parametersFieldName,
            final Errors errors, final ItemSelectionAlgorithmParameter parameter, final Object... errorArgs) {
        try {
            if (parameter.getItemSelectionType() == ItemSelectionType.FLOAT) {
                final Float floatValue = Float.parseFloat(fieldValue);
                final Range<Float> floatRange = buildFloatRange(parameter.getMinimumValue(),
                        parameter.getMaximumValue());
                if (floatRange != null && !floatRange.contains(floatValue)) {
                    rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_OUT_OF_RANGE,
                            flattenArgs(errorArgs, buildRangeConstraintString(parameter.getMinimumValue(),
                                    parameter.getMaximumValue())));
                }
            } else {
                final Long longValue = Long.parseLong(fieldValue);
                final Range<Long> longRange = buildLongRange(parameter.getMinimumValue(),
                        parameter.getMaximumValue());
                if (longRange != null && !longRange.contains(longValue)) {
                    rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_OUT_OF_RANGE,
                            flattenArgs(errorArgs, buildRangeConstraintString(parameter.getMinimumValue(),
                                    parameter.getMaximumValue())));
                }
            }
        } catch (final NumberFormatException e) {
            rejectValue(errors, "", getErrorMessageRoot() + parametersFieldName + MSG_PARSEABLE_NUMBER, errorArgs);
        }
    }

    protected Range<Float> buildFloatRange(final String min, final String max) {
        Range<Float> floatRange = null;
        if (StringUtils.isNotEmpty(min) && StringUtils.isNotEmpty(max)) { // has both ends of a range
            floatRange = Range.closed(Float.valueOf(min), Float.valueOf(max));
        } else if (StringUtils.isNotEmpty(min) && StringUtils.isEmpty(max)) { // only has a minimum
            floatRange = Range.atLeast(Float.valueOf(min));
        } else if (StringUtils.isEmpty(min) && StringUtils.isNotEmpty(max)) { // only has a maximum
            floatRange = Range.atMost(Float.valueOf(max));
        }
        return floatRange;
    }

    protected Range<Long> buildLongRange(final String min, final String max) {
        Range<Long> longRange = null;
        if (StringUtils.isNotEmpty(min) && StringUtils.isNotEmpty(max)) { // has both ends of a range
            longRange = Range.closed(Long.valueOf(min), Long.valueOf(max));
        } else if (StringUtils.isNotEmpty(min) && StringUtils.isEmpty(max)) { // only has a minimum
            longRange = Range.atLeast(Long.valueOf(min));
        } else if (StringUtils.isEmpty(min) && StringUtils.isNotEmpty(max)) { // only has a maximum
            longRange = Range.atMost(Long.valueOf(max));
        }
        return longRange;
    }

    protected String buildRangeConstraintString(final String min, final String max) {
        if (StringUtils.isNotEmpty(min) && StringUtils.isNotEmpty(max)) { // has both ends of a range
            return "(" + min + " - " + max + ")";
        } else if (StringUtils.isNotEmpty(min) && StringUtils.isEmpty(max)) { // only has a minimum
            return "(Minimum: " + min + ")";
        } else if (StringUtils.isEmpty(min) && StringUtils.isNotEmpty(max)) { // only has a maximum
            return "(Maximum: " + max + ")";
        }
        return "";
    }

    protected Object[] flattenArgs(final Object[] firstArray, final Object... additionalArgs) {
        return Iterables.toArray(
                Iterables.concat(Lists.newArrayList(firstArray), Lists.newArrayList(additionalArgs)), Object.class);
    }

}