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

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testauth.validation.ComputationRuleValidator.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 java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.opentestsystem.authoring.testauth.domain.ComputationRule;
import org.opentestsystem.authoring.testauth.domain.ComputationRuleParameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;

@Component
public class ComputationRuleValidator extends AbstractDomainValidator {
    private static final String ERROR_MSG_ROOT = "computationRule.";
    private static final String PARAMETERS = "parameters";
    private static final String PARAMETERS_NAME = PARAMETERS + ".parameterName";
    private static final String PARAMETERS_POSITION = PARAMETERS + ".position";

    private static final String EMPTY_PARAMETER_NAME = "";
    private static final Function<ComputationRuleParameter, String> PARAMETER_TO_NAME_TRANSFORMER = new Function<ComputationRuleParameter, String>() {
        @Override
        public String apply(final ComputationRuleParameter computationRuleParameter) {
            return StringUtils.isEmpty(computationRuleParameter.getParameterName()) ? EMPTY_PARAMETER_NAME
                    : computationRuleParameter.getParameterName();
        }
    };

    private static final Function<ComputationRuleParameter, String> PARAMETER_TO_POSITION_TRANSFORMER = new Function<ComputationRuleParameter, String>() {
        @Override
        public String apply(final ComputationRuleParameter computationRuleParameter) {
            return computationRuleParameter != null ? String.valueOf(computationRuleParameter.getPosition()) : "-1";
        }
    };

    private static final Predicate<Entry<String, Collection<ComputationRuleParameter>>> PARAMETER_DUPLICATE_FILTER = new Predicate<Entry<String, Collection<ComputationRuleParameter>>>() {
        @Override
        public boolean apply(final Entry<String, Collection<ComputationRuleParameter>> entry) {
            return !EMPTY_PARAMETER_NAME.equals(entry.getKey()) && entry.getValue().size() > 1;
        }
    };

    @Autowired
    private ComputationRuleParameterValidator computationRuleParameterValidator;

    @Autowired
    @Qualifier("jsr303Validator")
    private Validator jsrValidator;

    @Override
    public boolean supports(final Class<?> clazz) {
        return ComputationRule.class.equals(clazz);
    }

    @Override
    public void validate(final Object obj, final Errors errors) {
        // execute JSR-303 validations (annotations)
        this.jsrValidator.validate(obj, errors);

        final ComputationRule computationRule = (ComputationRule) obj;
        if (!CollectionUtils.isEmpty(computationRule.getParameters())) {
            // custom validation for each computationRuleParameter
            for (int i = 0; i < computationRule.getParameters().size(); i++) {
                final ComputationRuleParameter nextParameter = computationRule.getParameters().get(i);
                try {
                    errors.pushNestedPath(PARAMETERS + "[" + i + "]");
                    ValidationUtils.invokeValidator(this.computationRuleParameterValidator, nextParameter, errors);

                    if (nextParameter.getPosition() > computationRule.getParameters().size()) {
                        rejectValue(errors, "position", getErrorMessageRoot() + PARAMETERS_POSITION + MSG_INVALID,
                                nextParameter.getPosition());
                    }
                } finally {
                    errors.popNestedPath();
                }
            }

            // check for duplicate parameter names
            final Map<String, Collection<ComputationRuleParameter>> duplicates = Maps.filterEntries(
                    Multimaps.index(computationRule.getParameters(), PARAMETER_TO_NAME_TRANSFORMER).asMap(),
                    PARAMETER_DUPLICATE_FILTER);
            if (!duplicates.isEmpty()) {
                rejectValue(errors, PARAMETERS, getErrorMessageRoot() + PARAMETERS_NAME + MSG_DUPLICATES,
                        duplicates.keySet().toString());
            }

            // check for duplicate parameter position
            final Map<String, Collection<ComputationRuleParameter>> duplicatePositions = Maps.filterEntries(
                    Multimaps.index(computationRule.getParameters(), PARAMETER_TO_POSITION_TRANSFORMER).asMap(),
                    PARAMETER_DUPLICATE_FILTER);
            if (!duplicatePositions.isEmpty()) {
                rejectValue(errors, PARAMETERS, getErrorMessageRoot() + PARAMETERS_POSITION + MSG_DUPLICATES,
                        duplicatePositions.keySet().toString());
            } else if (!errors.hasErrors()) {
                computationRule.setParameters(
                        Lists.newArrayList(Ordering.natural().onResultOf(PARAMETER_TO_POSITION_TRANSFORMER)
                                .sortedCopy(computationRule.getParameters())));
            }
        }
        if (StringUtils.trimToNull(computationRule.getVersion()) != null) {
            final String[] parts = computationRule.getVersion().split("\\.");
            if (parts.length != 2) { // not the right number version parts
                // should be 2 parts like "1.0"
                rejectValue(errors, "version", "version.format", new Object() {
                });
                return;
            }
            if (NumberUtils.toInt(parts[0], -1) < 1 || parts[1].length() > 1
                    || (NumberUtils.toInt(parts[1], -1) < 0 || NumberUtils.toInt(parts[1], -1) > 9)) { //major is a negative number or some other character
                rejectValue(errors, "version", "version.majorminor.format", new Object() {
                });
            }
        }
    }

    @Override
    protected String getErrorMessageRoot() {
        return ERROR_MSG_ROOT;
    }
}