/**
* 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;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.eclipse.smarthome.config.core.ConfigDescription;
import org.eclipse.smarthome.config.core.ConfigDescriptionParameter;
import org.eclipse.smarthome.config.core.ConfigDescriptionRegistry;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.config.core.internal.Activator;
import org.eclipse.smarthome.config.core.validation.internal.ConfigDescriptionParameterValidator;
import org.eclipse.smarthome.config.core.validation.internal.ConfigDescriptionParameterValidatorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
/**
* The {@link ConfigDescriptionValidator} validates a given set of {@link Configuration} parameters against a
* given {@link ConfigDescription} URI. So it can be used as a static pre-validation to avoid that the configuration of
* an entity is updated with parameters which do not match with the declarations in the configuration description.
* If the validator detects one or more mismatches then a {@link ConfigValidationException} is thrown.
*
* @author Thomas Höfer - Initial contribution
* @author Chris Jackson - Handle checks on multiple selection parameters
*/
public final class ConfigDescriptionValidator {
private static final Logger logger = LoggerFactory.getLogger(ConfigDescriptionValidator.class);
private static final List<ConfigDescriptionParameterValidator> validators = new ImmutableList.Builder<ConfigDescriptionParameterValidator>()
.add(ConfigDescriptionParameterValidatorFactory.createRequiredValidator())
.add(ConfigDescriptionParameterValidatorFactory.createTypeValidator())
.add(ConfigDescriptionParameterValidatorFactory.createMinMaxValidator())
.add(ConfigDescriptionParameterValidatorFactory.createPatternValidator()).build();
private ConfigDescriptionValidator() {
super();
}
/**
* Validates the given configuration parameters against the given configuration description having the given URI.
*
* @param configurationParameters the configuration parameters to be validated
* @param configDescriptionURI the URI of the configuration description against which the configuration parameters
* are to be validated
*
* @throws ConfigValidationException if one or more configuration parameters do not match with the configuration
* description having the given URI
* @throws NullPointerException if given config description URI or configuration parameters are null
*/
@SuppressWarnings("unchecked")
public static void validate(Map<String, Object> configurationParameters, URI configDescriptionURI) {
Preconditions.checkNotNull(configurationParameters, "Configuration parameters must not be null");
Preconditions.checkNotNull(configDescriptionURI, "Config description URI must not be null");
ConfigDescription configDescription = getConfigDescription(configDescriptionURI);
if (configDescription == null) {
logger.warn("Skipping config description validation because no config description found for URI '{}'",
configDescriptionURI);
return;
}
Map<String, ConfigDescriptionParameter> map = configDescription.toParametersMap();
Collection<ConfigValidationMessage> configDescriptionValidationMessages = new ArrayList<>();
for (String key : configurationParameters.keySet()) {
ConfigDescriptionParameter configDescriptionParameter = map.get(key);
if (configDescriptionParameter != null) {
// If the parameter supports multiple selection, then it may be provided as an array
if (configDescriptionParameter.isMultiple() && configurationParameters.get(key) instanceof List) {
// Perform validation on each value in the list separately
for (Object value : (List<Object>) configurationParameters.get(key)) {
ConfigValidationMessage message = validateParameter(configDescriptionParameter, value);
if (message != null) {
configDescriptionValidationMessages.add(message);
}
}
} else {
ConfigValidationMessage message = validateParameter(configDescriptionParameter,
configurationParameters.get(key));
if (message != null) {
configDescriptionValidationMessages.add(message);
}
}
}
}
if (!configDescriptionValidationMessages.isEmpty()) {
throw new ConfigValidationException(Activator.getBundleContext().getBundle(),
configDescriptionValidationMessages);
}
}
/**
* Validates the given value against the given config description parameter.
*
* @param configDescriptionParameter the corresponding config description parameter
* @param value the actual value
*
* @return the {@link ConfigValidationMessage} if the given value is not valid for the config description parameter,
* otherwise null
*/
private static ConfigValidationMessage validateParameter(ConfigDescriptionParameter configDescriptionParameter,
Object value) {
for (ConfigDescriptionParameterValidator validator : validators) {
ConfigValidationMessage message = validator.validate(configDescriptionParameter, value);
if (message != null) {
return message;
}
}
return null;
}
/**
* Retrieves the {@link ConfigDescription} for the given URI.
*
* @param configDescriptionURI the URI of the configuration description to be retrieved
*
* @return the requested config description or null if config description could not be found (either because of
* config description registry is not available or because of config description could not be found for
* given URI)
*/
private static ConfigDescription getConfigDescription(URI configDescriptionURI) {
ConfigDescriptionRegistry configDescriptionRegistry = Activator.getConfigDescriptionRegistry();
if (configDescriptionRegistry == null) {
logger.warn("No config description registry available.");
return null;
}
ConfigDescription configDescription = configDescriptionRegistry.getConfigDescription(configDescriptionURI);
if (configDescription == null) {
logger.warn("No config description found for URI '{}'", configDescriptionURI);
}
return configDescription;
}
}