/**
* 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;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.smarthome.config.core.normalization.Normalizer;
import org.eclipse.smarthome.config.core.normalization.NormalizerFactory;
import org.eclipse.smarthome.config.core.validation.ConfigDescriptionValidator;
/**
* This class provides some useful static methods for handling configurations
*
* @author Kai Kreuzer - Initial API and implementation
* @author Thomas Höfer - Minor changes for type normalization based on config description
*/
public class ConfigUtil {
/**
* Normalizes the types to the ones allowed for configurations.
*
* @param configuration the configuration that needs to be normalzed
* @return normalized configuration
*/
public static Map<String, Object> normalizeTypes(Map<String, Object> configuration) {
Map<String, Object> convertedConfiguration = new HashMap<String, Object>(configuration.size());
for (Entry<String, Object> parameter : configuration.entrySet()) {
String name = parameter.getKey();
Object value = parameter.getValue();
convertedConfiguration.put(name, normalizeType(value));
}
return convertedConfiguration;
}
/**
* Normalizes the type of the parameter to the one allowed for configurations.
*
* @param value the value to return as normalized type
* @return corresponding value as a valid type
*/
public static Object normalizeType(Object value) {
return normalizeType(value, null);
}
/**
* Normalizes the type of the parameter to the one allowed for configurations.
*
* @param value the value to return as normalized type
* @param configDescriptionParameter the parameter that needs to be normalized
* @return corresponding value as a valid type
* @throws IllegalArgumentException if a invalid type has been given
*/
public static Object normalizeType(Object value, ConfigDescriptionParameter configDescriptionParameter) {
if (configDescriptionParameter != null) {
Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter);
return normalizer.normalize(value);
} else if (value == null || value instanceof Boolean || value instanceof String
|| value instanceof BigDecimal) {
return value;
} else if (value instanceof Number) {
return new BigDecimal(value.toString());
} else if (value instanceof Collection) {
return normalizeCollection((Collection<?>) value);
}
throw new IllegalArgumentException(
"Invalid type '{" + value.getClass().getCanonicalName() + "}' of configuration value!");
}
/**
* Normalizes a collection.
*
* @param collection the collection that entries should be normalized
* @return a collection that contains the normalized entries
* @throws IllegalArgumentException if the type of the normalized values differ or an invalid type has been given
*/
private static Collection<Object> normalizeCollection(Collection<?> collection) throws IllegalArgumentException {
if (collection.size() == 0) {
return Collections.emptyList();
} else {
final List<Object> lst = new ArrayList<>(collection.size());
for (final Object it : collection) {
final Object normalized = normalizeType(it);
lst.add(normalized);
if (normalized.getClass() != lst.get(0).getClass()) {
throw new IllegalArgumentException(
"Invalid configuration property. Heterogeneous collection value!");
}
}
return lst;
}
}
/**
* Normalizes the given configuration according to the given config descriptions.
*
* By doing so, it tries to convert types on a best-effort basis. The result will contain
* BigDecimals, Strings and Booleans wherever a conversion of similar types was possible.
*
* However, it does not check for general correctness of types. This can be done using the
* {@link ConfigDescriptionValidator}.
*
* If multiple config descriptions are given and a parameter is described several times, then the first one (lower
* index in the list) wins.
*
* @param configuration the configuration to be normalized (can be null)
* @param configDescriptions the configuration descriptions that should be applied (must not be null or empty).
* @return the normalized configuration or null if given configuration was null
* @throws IllegalArgumentExcetpion if given config description is null
*/
public static Map<String, Object> normalizeTypes(Map<String, Object> configuration,
List<ConfigDescription> configDescriptions) {
if (configDescriptions == null || configDescriptions.isEmpty()) {
throw new IllegalArgumentException("Config description must not be null.");
}
if (configuration == null) {
return null;
}
Map<String, Object> convertedConfiguration = new HashMap<String, Object>(configuration.size());
Map<String, ConfigDescriptionParameter> configParams = new HashMap<>();
for (int i = configDescriptions.size() - 1; i >= 0; i--) {
configParams.putAll(configDescriptions.get(i).toParametersMap());
}
for (Entry<String, ?> parameter : configuration.entrySet()) {
String name = parameter.getKey();
Object value = parameter.getValue();
ConfigDescriptionParameter configDescriptionParameter = configParams.get(name);
convertedConfiguration.put(name, normalizeType(value, configDescriptionParameter));
}
return convertedConfiguration;
}
}