/** * 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.xml; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.eclipse.smarthome.config.core.ConfigDescriptionParameter; import org.eclipse.smarthome.config.core.ConfigDescriptionParameter.Type; import org.eclipse.smarthome.config.core.ConfigDescriptionParameterBuilder; import org.eclipse.smarthome.config.core.FilterCriteria; import org.eclipse.smarthome.config.core.ParameterOption; import org.eclipse.smarthome.config.xml.util.ConverterAttributeMapValidator; import org.eclipse.smarthome.config.xml.util.ConverterValueMap; import org.eclipse.smarthome.config.xml.util.GenericUnmarshaller; import org.eclipse.smarthome.config.xml.util.NodeValue; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; /** * The {@link ConfigDescriptionParameterConverter} is a concrete implementation * of the {@code XStream} {@link Converter} interface used to convert config * description parameters information within an XML document into a {@link ConfigDescriptionParameter} object. * <p> * This converter converts {@code parameter} XML tags. * * @author Michael Grammling - Initial Contribution * @author Alex Tugarev - Extended for options and filter criteria * @author Chris Jackson - Modified to use config parameter builder. Added * parameters. * @author Thomas Höfer - Added unit */ public class ConfigDescriptionParameterConverter extends GenericUnmarshaller<ConfigDescriptionParameter> { private ConverterAttributeMapValidator attributeMapValidator; public ConfigDescriptionParameterConverter() { super(ConfigDescriptionParameter.class); this.attributeMapValidator = new ConverterAttributeMapValidator( new String[][] { { "name", "true" }, { "type", "true" }, { "min", "false" }, { "max", "false" }, { "step", "false" }, { "pattern", "false" }, { "required", "false" }, { "readOnly", "false" }, { "multiple", "false" }, { "groupName", "false" }, { "unit", "false" } }); } private Type toType(String xmlType) { if (xmlType != null) { return Type.valueOf(xmlType.toUpperCase()); } return null; } private BigDecimal toNumber(String value) { try { if (value != null) { return new BigDecimal(value); } } catch (NumberFormatException e) { throw new ConversionException("The value '" + value + "' could not be converted to a decimal number.", e); } return null; } private Boolean toBoolean(String val) { if (val == null) { return null; } return new Boolean(val); } private Boolean falseIfNull(Boolean b) { return (b != null) ? b : false; } @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { ConfigDescriptionParameter configDescriptionParam = null; // read attributes Map<String, String> attributes = this.attributeMapValidator.readValidatedAttributes(reader); String name = attributes.get("name"); Type type = toType(attributes.get("type")); BigDecimal min = toNumber(attributes.get("min")); BigDecimal max = toNumber(attributes.get("max")); BigDecimal step = toNumber(attributes.get("step")); String patternString = attributes.get("pattern"); Boolean required = toBoolean(attributes.get("required")); Boolean readOnly = falseIfNull(toBoolean(attributes.get("readOnly"))); Boolean multiple = falseIfNull(toBoolean(attributes.get("multiple"))); String groupName = attributes.get("groupName"); String unit = attributes.get("unit"); // read values ConverterValueMap valueMap = new ConverterValueMap(reader, context); String parameterContext = valueMap.getString("context"); if (required == null) { // fallback to deprecated "required" element required = valueMap.getBoolean("required", false); } String defaultValue = valueMap.getString("default"); String label = valueMap.getString("label"); String description = valueMap.getString("description"); Boolean advanced = valueMap.getBoolean("advanced", false); Boolean verify = valueMap.getBoolean("verify", false); Boolean limitToOptions = valueMap.getBoolean("limitToOptions", true); Integer multipleLimit = valueMap.getInteger("multipleLimit"); String unitLabel = null; if (unit == null) { unitLabel = valueMap.getString("unitLabel"); } // read options and filter criteria List<ParameterOption> options = readParameterOptions(valueMap.getObject("options")); @SuppressWarnings("unchecked") List<FilterCriteria> filterCriteria = (List<FilterCriteria>) valueMap.getObject("filter"); // create object configDescriptionParam = ConfigDescriptionParameterBuilder.create(name, type).withMinimum(min).withMaximum(max) .withStepSize(step).withPattern(patternString).withRequired(required).withReadOnly(readOnly) .withMultiple(multiple).withContext(parameterContext).withDefault(defaultValue).withLabel(label) .withDescription(description).withOptions(options).withFilterCriteria(filterCriteria) .withGroupName(groupName).withAdvanced(advanced).withVerify(verify).withLimitToOptions(limitToOptions) .withMultipleLimit(multipleLimit).withUnit(unit).withUnitLabel(unitLabel).build(); return configDescriptionParam; } private List<ParameterOption> readParameterOptions(Object rawNodeValueList) { if (rawNodeValueList instanceof List<?>) { List<?> list = (List<?>) rawNodeValueList; List<ParameterOption> result = new ArrayList<>(); for (Object object : list) { if (object instanceof NodeValue) { NodeValue nodeValue = (NodeValue) object; String value = nodeValue.getAttributes().get("value"); String label = nodeValue.getValue().toString(); result.add(new ParameterOption(value, label)); } } return result; } return null; } }