/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.config.core.validation.internal;
import java.math.BigDecimal;
import java.util.Map;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter.Type;
import com.google.common.collect.ImmutableMap;
/**
* The {@link TypeIntrospections} provides a corresponding {@link TypeIntrospection} for each config description
* parameter type.
*
* @author Thomas Höfer - Initial contribution
*/
final class TypeIntrospections {
private static final Map<Type, TypeIntrospection> introspections = new ImmutableMap.Builder<Type, TypeIntrospection>()
.put(Type.BOOLEAN, new BooleanIntrospection()).put(Type.TEXT, new StringIntrospection())
.put(Type.INTEGER, new IntegerIntrospection()).put(Type.DECIMAL, new FloatIntrospection()).build();
private TypeIntrospections() {
super();
}
/**
* Returns the corresponding {@link TypeIntrospection} for the given type.
*
* @param type the type for which the {@link TypeIntrospection} is to be returned
*
* @return the {@link TypeIntrospection} for the given type
*
* @throws IllegalArgumentException if no {@link TypeIntrospection} was found for the given type
*/
static TypeIntrospection get(Type type) {
TypeIntrospection typeIntrospection = introspections.get(type);
if (typeIntrospection == null) {
throw new IllegalArgumentException("There is no type introspection for type " + type);
}
return typeIntrospection;
}
/**
* The {@link TypeIntrospection} provides operations to introspect the actual value for a configuration description
* parameter.
*/
static abstract class TypeIntrospection {
private final Class<?> clazz;
private final MessageKey minViolationMessageKey;
private final MessageKey maxViolationMessageKey;
private TypeIntrospection(Class<?> clazz) {
this(clazz, null, null);
}
private TypeIntrospection(Class<?> clazz, MessageKey minViolationMessageKey,
MessageKey maxViolationMessageKey) {
this.clazz = clazz;
this.minViolationMessageKey = minViolationMessageKey;
this.maxViolationMessageKey = maxViolationMessageKey;
}
/**
* Returns true, if the given value is less than the given min attribute, otherwise false.
*
* @param value the corresponding value
* @param min the value of the min attribute
*
* @return true, if the given value is less than the given min attribute, otherwise false
*/
boolean isMinViolated(Object value, BigDecimal min) {
if (min == null) {
return false;
}
final BigDecimal bd;
if (isBigDecimalInstance(value)) {
bd = (BigDecimal) value;
} else {
bd = new BigDecimal(value.toString());
}
return bd.compareTo(min) < 0;
}
/**
* Returns true, if the given value is greater than the given max attribute, otherwise false.
*
* @param value the corresponding value
* @param max the value of the max attribute
*
* @return true, if the given value is greater than the given max attribute, otherwise false
*/
boolean isMaxViolated(Object value, BigDecimal max) {
if (max == null) {
return false;
}
final BigDecimal bd;
if (isBigDecimalInstance(value)) {
bd = (BigDecimal) value;
} else {
bd = new BigDecimal(value.toString());
}
return bd.compareTo(max) > 0;
}
/**
* Returns true, if the given value can be assigned to the type of this introspection, otherwise false.
*
* @param value the corresponding value
*
* @return true, if the given value can be assigned to the type of this introspection, otherwise false
*/
boolean isAssignable(Object value) {
return clazz.isAssignableFrom(value.getClass());
}
/**
* Returns true, if the given value is a big decimal, otherwise false.
*
* @param value the value to be analyzed
*
* @return true, if the given value is a big decimal, otherwise false
*/
final boolean isBigDecimalInstance(Object value) {
return value instanceof BigDecimal;
}
/**
* Returns the corresponding {@link MessageKey} for the min attribute violation.
*
* @return the corresponding {@link MessageKey} for the min attribute violation
*/
final MessageKey getMinViolationMessageKey() {
return minViolationMessageKey;
}
/**
* Returns the corresponding {@link MessageKey} for the max attribute violation.
*
* @return the corresponding {@link MessageKey} for the max attribute violation
*/
final MessageKey getMaxViolationMessageKey() {
return maxViolationMessageKey;
}
}
private static final class BooleanIntrospection extends TypeIntrospection {
private BooleanIntrospection() {
super(Boolean.class);
}
@Override
boolean isMinViolated(Object value, BigDecimal min) {
throw new UnsupportedOperationException("Min attribute not supported for boolean parameter.");
}
@Override
boolean isMaxViolated(Object value, BigDecimal max) {
throw new UnsupportedOperationException("Max attribute not supported for boolean parameter.");
}
}
private static final class FloatIntrospection extends TypeIntrospection {
private FloatIntrospection() {
super(Float.class, MessageKey.MIN_VALUE_NUMERIC_VIOLATED, MessageKey.MAX_VALUE_NUMERIC_VIOLATED);
}
@Override
boolean isAssignable(Object value) {
if (!super.isAssignable(value)) {
return isBigDecimalInstance(value);
}
return true;
}
}
private static final class IntegerIntrospection extends TypeIntrospection {
private IntegerIntrospection() {
super(Integer.class, MessageKey.MIN_VALUE_NUMERIC_VIOLATED, MessageKey.MAX_VALUE_NUMERIC_VIOLATED);
}
@Override
boolean isAssignable(Object value) {
if (!super.isAssignable(value)) {
return isBigDecimalInstance(value);
}
return true;
}
}
private static final class StringIntrospection extends TypeIntrospection {
private StringIntrospection() {
super(String.class, MessageKey.MIN_VALUE_TXT_VIOLATED, MessageKey.MAX_VALUE_TXT_VIOLATED);
}
@Override
boolean isMinViolated(Object value, BigDecimal min) {
if (min == null) {
return false;
}
return ((String) value).length() < min.intValueExact();
}
@Override
boolean isMaxViolated(Object value, BigDecimal max) {
if (max == null) {
return false;
}
return ((String) value).length() > max.intValueExact();
}
}
}