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

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testauth.validation.ItemSelectionAlgorithmValidator.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.ItemSelectionAlgorithm;
import org.opentestsystem.authoring.testauth.domain.ItemSelectionAlgorithmParameter;
import org.opentestsystem.authoring.testauth.domain.ItemSelectionPurpose;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
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.Maps;
import com.google.common.collect.Multimaps;

@Component
public class ItemSelectionAlgorithmValidator extends AbstractDomainValidator {
    private static final String ERROR_MSG_ROOT = "itemSelectionAlgorithm.";
    private static final String PARAMETERS_FIELD = "parameters";
    private static final String PARAMETERS_NAME_FIELD = PARAMETERS_FIELD + ".parameterName";
    private static final String PARAMETERS_POSITION_FIELD = PARAMETERS_FIELD + ".position";

    private static final String EMPTY_ALGORITHM_PARAMETER_NAME = "";
    private static final Function<ItemSelectionAlgorithmParameter, String> ITEM_SELECTION_ALGORITHM_PARAMETER_TO_NAME_TRANSFORMER = new Function<ItemSelectionAlgorithmParameter, String>() {
        @Override
        public String apply(final ItemSelectionAlgorithmParameter itemSelectionAlgorithmParameter) {
            return StringUtils.isEmpty(itemSelectionAlgorithmParameter.getParameterName())
                    ? EMPTY_ALGORITHM_PARAMETER_NAME
                    : itemSelectionAlgorithmParameter.getParameterName();
        }
    };

    private static final Function<ItemSelectionAlgorithmParameter, String> ITEM_SELECTION_ALGORITHM_PARAMETER_TO_POSITION_TRANSFORMER = new Function<ItemSelectionAlgorithmParameter, String>() {
        @Override
        public String apply(final ItemSelectionAlgorithmParameter itemSelectionAlgorithmParameter) {
            return String.valueOf(itemSelectionAlgorithmParameter.getPosition());
        }
    };
    private static final Predicate<Entry<String, Collection<ItemSelectionAlgorithmParameter>>> ITEM_SELECTION_ALGORITHM_PARAMETER_DUPLICATE_FILTER = new Predicate<Entry<String, Collection<ItemSelectionAlgorithmParameter>>>() {
        @Override
        public boolean apply(final Entry<String, Collection<ItemSelectionAlgorithmParameter>> entry) {
            if (!EMPTY_ALGORITHM_PARAMETER_NAME.equals(entry.getKey()) && entry.getValue().size() > 2) {
                return true;
            } else if (!EMPTY_ALGORITHM_PARAMETER_NAME.equals(entry.getKey()) && entry.getValue().size() == 2) {
                ItemSelectionAlgorithmParameter[] iSAPs = new ItemSelectionAlgorithmParameter[2];
                entry.getValue().toArray(iSAPs);
                ItemSelectionPurpose first = iSAPs[0].getItemSelectionPurpose();
                ItemSelectionPurpose second = iSAPs[1].getItemSelectionPurpose();
                if (first != null && second != null && first.compareTo(second) == 0)
                    return true;
                else
                    return false;
            }
            return !EMPTY_ALGORITHM_PARAMETER_NAME.equals(entry.getKey()) && entry.getValue().size() > 1;
        }
    };

    @Autowired
    private ItemSelectionAlgorithmParameterValidator itemSelectionAlgorithmParameterValidator;

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

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

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

        final ItemSelectionAlgorithm algorithm = (ItemSelectionAlgorithm) obj;
        if (algorithm.getParameters() != null) {
            // custom validation for each itemSelectionAlgorithmParameter
            for (int i = 0; i < algorithm.getParameters().size(); i++) {
                final ItemSelectionAlgorithmParameter nextParameter = algorithm.getParameters().get(i);
                try {
                    errors.pushNestedPath(PARAMETERS_FIELD + "[" + i + "]");
                    ValidationUtils.invokeValidator(this.itemSelectionAlgorithmParameterValidator, nextParameter,
                            errors);

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

            // check if parameters have duplicate names
            final Map<String, Collection<ItemSelectionAlgorithmParameter>> duplicates = Maps.filterEntries(
                    Multimaps.index(algorithm.getParameters(),
                            ITEM_SELECTION_ALGORITHM_PARAMETER_TO_NAME_TRANSFORMER).asMap(),
                    ITEM_SELECTION_ALGORITHM_PARAMETER_DUPLICATE_FILTER);
            if (!duplicates.isEmpty()) {
                rejectValue(errors, PARAMETERS_FIELD,
                        getErrorMessageRoot() + PARAMETERS_NAME_FIELD + MSG_DUPLICATES,
                        duplicates.keySet().toString());
            }

            // check if parameters have duplicate position
            final Map<String, Collection<ItemSelectionAlgorithmParameter>> duplicatePositions = Maps.filterEntries(
                    Multimaps.index(algorithm.getParameters(),
                            ITEM_SELECTION_ALGORITHM_PARAMETER_TO_POSITION_TRANSFORMER).asMap(),
                    ITEM_SELECTION_ALGORITHM_PARAMETER_DUPLICATE_FILTER);
            if (!duplicatePositions.isEmpty()) {
                rejectValue(errors, PARAMETERS_FIELD,
                        getErrorMessageRoot() + PARAMETERS_POSITION_FIELD + MSG_DUPLICATES,
                        duplicatePositions.keySet().toString());
            }
        }
        if (StringUtils.trimToNull(algorithm.getVersion()) != null) {
            String[] parts = algorithm.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() {
                });
            }
        }

        if (!errors.hasErrors()) {
            algorithm.trimParameterValues();
        }
    }

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