/** * 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.core.thing.xml.internal; import java.net.URI; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.smarthome.config.core.ConfigDescription; import org.eclipse.smarthome.config.xml.util.ConverterAttributeMapValidator; import org.eclipse.smarthome.config.xml.util.NodeIterator; import org.eclipse.smarthome.config.xml.util.NodeValue; import org.eclipse.smarthome.core.thing.type.ChannelKind; import org.eclipse.smarthome.core.thing.type.ChannelType; import org.eclipse.smarthome.core.thing.type.ChannelTypeUID; import org.eclipse.smarthome.core.types.EventDescription; import org.eclipse.smarthome.core.types.StateDescription; 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 ChannelTypeConverter} is a concrete implementation of the {@code XStream} {@link Converter} interface used * to convert channel type information within an XML document * into a {@link ChannelTypeXmlResult} object. * <p> * This converter converts {@code channel-type} XML tags. It uses the {@link AbstractDescriptionTypeConverter} which * offers base functionality for each type definition. * * @author Michael Grammling - Initial Contribution * @author Ivan Iliev - Added support for system wide channel types */ public class ChannelTypeConverter extends AbstractDescriptionTypeConverter<ChannelTypeXmlResult> { public ChannelTypeConverter() { super(ChannelTypeXmlResult.class, "channel-type"); super.attributeMapValidator = new ConverterAttributeMapValidator( new String[][] { { "id", "true" }, { "advanced", "false" }, { "system", "false" } }); } private boolean readBoolean(Map<String, String> attributes, String attributeName, boolean defaultValue) { String advancedFlag = attributes.get(attributeName); if (advancedFlag != null) { return Boolean.parseBoolean(advancedFlag); } return defaultValue; } private String readItemType(NodeIterator nodeIterator) throws ConversionException { return (String) nodeIterator.nextValue("item-type", false); } private String readKind(NodeIterator nodeIterator) throws ConversionException { return (String) nodeIterator.nextValue("kind", false); } private String readCategory(NodeIterator nodeIterator) throws ConversionException { return (String) nodeIterator.nextValue("category", false); } private Set<String> readTags(NodeIterator nodeIterator) throws ConversionException { Set<String> tags = null; List<?> tagsNode = nodeIterator.nextList("tags", false); if (tagsNode != null) { tags = new HashSet<>(tagsNode.size()); for (Object tagNodeObject : tagsNode) { NodeValue tagNode = (NodeValue) tagNodeObject; if ("tag".equals(tagNode.getNodeName())) { String tag = (String) tagNode.getValue(); if (tag != null) { tags.add(tag); } } else { throw new ConversionException("The 'tags' node must only contain 'tag' nodes!"); } } } return tags; } private StateDescription readStateDescription(NodeIterator nodeIterator) { Object nextNode = nodeIterator.next(); if (nextNode != null) { if (nextNode instanceof StateDescription) { return (StateDescription) nextNode; } nodeIterator.revert(); } return null; } private EventDescription readEventDescription(NodeIterator nodeIterator) { Object nextNode = nodeIterator.next(); if (nextNode != null) { if (nextNode instanceof EventDescription) { return (EventDescription) nextNode; } nodeIterator.revert(); } return null; } @Override protected ChannelTypeXmlResult unmarshalType(HierarchicalStreamReader reader, UnmarshallingContext context, Map<String, String> attributes, NodeIterator nodeIterator) throws ConversionException { boolean advanced = readBoolean(attributes, "advanced", false); boolean system = readBoolean(attributes, "system", false); String uid = system ? XmlHelper.getSystemUID(super.getID(attributes)) : super.getUID(attributes, context); ChannelTypeUID channelTypeUID = new ChannelTypeUID(uid); String itemType = readItemType(nodeIterator); String kind = readKind(nodeIterator); String label = super.readLabel(nodeIterator); String description = super.readDescription(nodeIterator); String category = readCategory(nodeIterator); Set<String> tags = readTags(nodeIterator); StateDescription stateDescription = readStateDescription(nodeIterator); EventDescription eventDescription = readEventDescription(nodeIterator); Object[] configDescriptionObjects = super.getConfigDescriptionObjects(nodeIterator); if (kind == null) { // Default for kind is 'state' kind = "state"; } ChannelType channelType = new ChannelType(channelTypeUID, advanced, itemType, ChannelKind.parse(kind), label, description, category, tags, stateDescription, eventDescription, (URI) configDescriptionObjects[0]); ChannelTypeXmlResult channelTypeXmlResult = new ChannelTypeXmlResult(channelType, (ConfigDescription) configDescriptionObjects[1], system); return channelTypeXmlResult; } }