Java tutorial
/******************************************************************************* * 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.math.BigDecimal; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; 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.stereotype.Component; import org.springframework.validation.Errors; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimaps; @Component public class ItemSelectionAlgorithmParameterValidator extends AbstractDomainValidator { private static final String ITEM_SELECTION_ROOT = "itemSelectionAlgorithm.parameters."; private static final String DEFAULT_FIELD = "defaultValue"; private static final String MINIMUM_FIELD = "minimumValue"; private static final String MAXIMUM_FIELD = "maximumValue"; private static final String ITEM_TYPE_FIELD = "itemSelectionType"; private static final String ITEM_LIST_FIELD = "itemSelectionList"; private static final String ITEM_LIST_NAME_FIELD = ITEM_LIST_FIELD + ".name"; private static final String ITEM_LIST_POSITION_FIELD = ITEM_LIST_FIELD + ".position"; private static final Integer MAXIMUM_DEFAULT_STRING_LENGTH = 60; private static final String EMPTY_PARAMETER_ELEMENT_NAME = ""; private static final Function<ItemSelectionParameterElement, String> ITEM_SELECTION_PARAMETER_ELEMENT_TO_NAME_TRANSFORMER = new Function<ItemSelectionParameterElement, String>() { @Override public String apply(final ItemSelectionParameterElement itemSelectionParameterElement) { return StringUtils.isBlank(itemSelectionParameterElement.getName()) ? EMPTY_PARAMETER_ELEMENT_NAME : itemSelectionParameterElement.getName(); } }; private static final Function<ItemSelectionParameterElement, String> ITEM_SELECTION_PARAMETER_ELEMENT_TO_POSITION_TRANSFORMER = new Function<ItemSelectionParameterElement, String>() { @Override public String apply(final ItemSelectionParameterElement itemSelectionParameterElement) { return String.valueOf(itemSelectionParameterElement.getPosition()); } }; private static final Predicate<Entry<String, Collection<ItemSelectionParameterElement>>> ITEM_SELECTION_PARAMETER_ELEMENT_DUPLICATE_FILTER = new Predicate<Entry<String, Collection<ItemSelectionParameterElement>>>() { @Override public boolean apply(final Entry<String, Collection<ItemSelectionParameterElement>> entry) { return !EMPTY_PARAMETER_ELEMENT_NAME.equals(entry.getKey()) && entry.getValue().size() > 1; } }; private static final Predicate<ItemSelectionParameterElement> ITEM_SELECTION_PARAMETER_ELEMENT_BLANK = new Predicate<ItemSelectionParameterElement>() { @Override public boolean apply(final ItemSelectionParameterElement ispe) { return ispe != null && StringUtils.isBlank(ispe.getName()); } }; private static final class PARAMETER_POSITION_OUT_OF_RANGE_FILTER implements Predicate<ItemSelectionParameterElement> { private final int parameterListSize; private PARAMETER_POSITION_OUT_OF_RANGE_FILTER(final int parameterListSize) { this.parameterListSize = parameterListSize; } public static PARAMETER_POSITION_OUT_OF_RANGE_FILTER getInstance(final int parameterListSize) { return new PARAMETER_POSITION_OUT_OF_RANGE_FILTER(parameterListSize); } @Override public boolean apply(final ItemSelectionParameterElement input) { return input == null || input.getPosition() < 1 || input.getPosition() > this.parameterListSize; } }; @Override public boolean supports(final Class<?> clazz) { return ItemSelectionAlgorithmParameter.class.equals(clazz); } @Override public void validate(final Object obj, final Errors e) { final ItemSelectionAlgorithmParameter parameter = (ItemSelectionAlgorithmParameter) obj; if (parameter.getItemSelectionType() != null) { final Object[] errorArgs = new String[] { parameter.getItemSelectionType().name(), parameter.getParameterName() }; switch (parameter.getItemSelectionType()) { case FLOAT: case INTEGER: // defaultValue validated via jsr-303 rejectIfTooLong(e, DEFAULT_FIELD, MAX_PARSEABLE_LENGTH, errorArgs); final boolean isFloat = parameter.getItemSelectionType() == ItemSelectionType.FLOAT; rejectIfNotFloatOrIntegerParseable(e, DEFAULT_FIELD, isFloat, errorArgs); rejectIfNotFloatOrIntegerParseable(e, MINIMUM_FIELD, isFloat, errorArgs); rejectIfNotFloatOrIntegerParseable(e, MAXIMUM_FIELD, isFloat, errorArgs); if (!e.hasErrors()) { boolean compareDefaultToMinMax = true; if (StringUtils.isNotBlank(parameter.getMinimumValue()) && StringUtils.isNotBlank(parameter.getMaximumValue())) { final BigDecimal minimumBigDecimal = new BigDecimal(parameter.getMinimumValue()); final BigDecimal maximumBigDecimal = new BigDecimal(parameter.getMaximumValue()); if (minimumBigDecimal.compareTo(maximumBigDecimal) > -1) { rejectValue(e, MINIMUM_FIELD, getErrorMessageRoot() + MINIMUM_FIELD + MSG_LESS_THAN_MAX, errorArgs); compareDefaultToMinMax = false; } } if (StringUtils.isNotBlank(parameter.getDefaultValue())) { final BigDecimal defaultBigDecimal = new BigDecimal(parameter.getDefaultValue()); if (StringUtils.isNotBlank(parameter.getMinimumValue())) { final BigDecimal minimumBigDecimal = new BigDecimal(parameter.getMinimumValue()); if (compareDefaultToMinMax && defaultBigDecimal.compareTo(minimumBigDecimal) < 0) { rejectValue(e, DEFAULT_FIELD, getErrorMessageRoot() + DEFAULT_FIELD + MSG_WITHIN_MIN_MAX, errorArgs); } } if (StringUtils.isNotBlank(parameter.getMaximumValue())) { final BigDecimal maximumBigDecimal = new BigDecimal(parameter.getMaximumValue()); if (compareDefaultToMinMax && defaultBigDecimal.compareTo(maximumBigDecimal) > 0) { rejectValue(e, DEFAULT_FIELD, getErrorMessageRoot() + DEFAULT_FIELD + MSG_WITHIN_MIN_MAX, errorArgs); } } } } rejectIfCollectionNotEmpty(e, ITEM_LIST_FIELD, errorArgs); break; case BOOLEAN: rejectIfNotEmpty(e, MINIMUM_FIELD, errorArgs); rejectIfNotEmpty(e, MAXIMUM_FIELD, errorArgs); rejectIfNotBooleanParseable(e, DEFAULT_FIELD, errorArgs); rejectIfCollectionNotEmpty(e, ITEM_LIST_FIELD, errorArgs); break; case LIST: rejectIfNotEmpty(e, MINIMUM_FIELD, errorArgs); rejectIfNotEmpty(e, MAXIMUM_FIELD, errorArgs); rejectIfCollectionEmpty(e, ITEM_LIST_FIELD, errorArgs); if (parameter.getItemSelectionList() != null) { if (Iterables.any(parameter.getItemSelectionList(), ITEM_SELECTION_PARAMETER_ELEMENT_BLANK)) { rejectValue(e, ITEM_LIST_FIELD, getErrorMessageRoot() + ITEM_LIST_NAME_FIELD + MSG_REQUIRED, errorArgs); } // check if defaultValue is one of values in selection list rejectIfNotInCollection(e, DEFAULT_FIELD, Lists.transform(parameter.getItemSelectionList(), ITEM_SELECTION_PARAMETER_ELEMENT_TO_NAME_TRANSFORMER), errorArgs); // check if list has duplicate names and duplicate or out-of-range positions final Map<String, Collection<ItemSelectionParameterElement>> duplicates = Maps.filterEntries( Multimaps.index(parameter.getItemSelectionList(), ITEM_SELECTION_PARAMETER_ELEMENT_TO_NAME_TRANSFORMER).asMap(), ITEM_SELECTION_PARAMETER_ELEMENT_DUPLICATE_FILTER); if (!duplicates.isEmpty()) { rejectValue(e, ITEM_LIST_FIELD, getErrorMessageRoot() + ITEM_LIST_NAME_FIELD + MSG_DUPLICATES, duplicates.keySet().toString()); } final Map<String, Collection<ItemSelectionParameterElement>> duplicatePositions = Maps .filterEntries( Multimaps .index(parameter.getItemSelectionList(), ITEM_SELECTION_PARAMETER_ELEMENT_TO_POSITION_TRANSFORMER) .asMap(), ITEM_SELECTION_PARAMETER_ELEMENT_DUPLICATE_FILTER); if (!duplicatePositions.isEmpty()) { rejectValue(e, ITEM_LIST_FIELD, getErrorMessageRoot() + ITEM_LIST_POSITION_FIELD + MSG_DUPLICATES, duplicatePositions.keySet().toString()); } final List<String> outOfRange = Lists.newArrayList(Iterables.transform( Iterables.filter(parameter.getItemSelectionList(), PARAMETER_POSITION_OUT_OF_RANGE_FILTER .getInstance(parameter.getItemSelectionList().size())), ITEM_SELECTION_PARAMETER_ELEMENT_TO_POSITION_TRANSFORMER)); if (outOfRange.size() > 0) { rejectValue(e, ITEM_LIST_FIELD, getErrorMessageRoot() + ITEM_LIST_POSITION_FIELD + MSG_INVALID, outOfRange.toString()); } } break; case STRING: rejectIfNotEmpty(e, MINIMUM_FIELD, errorArgs); rejectIfNotEmpty(e, MAXIMUM_FIELD, errorArgs); rejectIfCollectionNotEmpty(e, ITEM_LIST_FIELD, errorArgs); rejectIfTooLong(e, DEFAULT_FIELD, MAXIMUM_DEFAULT_STRING_LENGTH, errorArgs); break; default: rejectValue(e, ITEM_TYPE_FIELD, getErrorMessageRoot() + ITEM_TYPE_FIELD + MSG_INVALID, errorArgs); break; } } } @Override protected String getErrorMessageRoot() { return ITEM_SELECTION_ROOT; } }