2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.insteon.internal.device;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.List;
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
24 import javax.xml.parsers.ParserConfigurationException;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.openhab.binding.insteon.internal.utils.Utils;
28 import org.openhab.binding.insteon.internal.utils.Utils.ParsingException;
29 import org.openhab.core.library.types.DecimalType;
30 import org.openhab.core.library.types.IncreaseDecreaseType;
31 import org.openhab.core.library.types.OnOffType;
32 import org.openhab.core.library.types.PercentType;
33 import org.openhab.core.types.Command;
34 import org.w3c.dom.DOMException;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.NamedNodeMap;
38 import org.w3c.dom.Node;
39 import org.w3c.dom.NodeList;
40 import org.xml.sax.SAXException;
43 * Class that loads the device feature templates from an xml stream
45 * @author Daniel Pfrommer - Initial contribution
46 * @author Rob Nielsen - Port to openHAB 2 insteon binding
49 public class FeatureTemplateLoader {
50 public static List<FeatureTemplate> readTemplates(InputStream input) throws IOException, ParsingException {
51 List<FeatureTemplate> features = new ArrayList<>();
53 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
54 DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
56 Document doc = dBuilder.parse(input);
57 doc.getDocumentElement().normalize();
59 Element root = doc.getDocumentElement();
61 NodeList nodes = root.getChildNodes();
63 for (int i = 0; i < nodes.getLength(); i++) {
64 Node node = nodes.item(i);
65 if (node.getNodeType() == Node.ELEMENT_NODE) {
66 Element e = (Element) node;
67 if (e.getTagName().equals("feature")) {
68 features.add(parseFeature(e));
72 } catch (SAXException e) {
73 throw new ParsingException("Failed to parse XML!", e);
74 } catch (ParserConfigurationException e) {
75 throw new ParsingException("Got parser config exception! ", e);
80 private static FeatureTemplate parseFeature(Element e) throws ParsingException {
81 String name = e.getAttribute("name");
82 boolean statusFeature = e.getAttribute("statusFeature").equals("true");
83 FeatureTemplate feature = new FeatureTemplate(name, statusFeature, e.getAttribute("timeout"));
85 NodeList nodes = e.getChildNodes();
87 for (int i = 0; i < nodes.getLength(); i++) {
88 Node node = nodes.item(i);
89 if (node.getNodeType() == Node.ELEMENT_NODE) {
90 Element child = (Element) node;
91 if (child.getTagName().equals("message-handler")) {
92 parseMessageHandler(child, feature);
93 } else if (child.getTagName().equals("command-handler")) {
94 parseCommandHandler(child, feature);
95 } else if (child.getTagName().equals("message-dispatcher")) {
96 parseMessageDispatcher(child, feature);
97 } else if (child.getTagName().equals("poll-handler")) {
98 parsePollHandler(child, feature);
106 private static HandlerEntry makeHandlerEntry(Element e) throws ParsingException {
107 String handler = e.getTextContent();
108 if (handler == null) {
109 throw new ParsingException("Could not find Handler for: " + e.getTextContent());
112 NamedNodeMap attributes = e.getAttributes();
113 Map<String, String> params = new HashMap<>();
114 for (int i = 0; i < attributes.getLength(); i++) {
115 Node n = attributes.item(i);
116 params.put(n.getNodeName(), n.getNodeValue());
118 return new HandlerEntry(handler, params);
121 private static void parseMessageHandler(Element e, FeatureTemplate f) throws DOMException, ParsingException {
122 HandlerEntry he = makeHandlerEntry(e);
123 if (e.getAttribute("default").equals("true")) {
124 f.setDefaultMessageHandler(he);
126 String attr = e.getAttribute("cmd");
127 int command = (attr == null) ? 0 : Utils.from0xHexString(attr);
128 f.addMessageHandler(command, he);
132 private static void parseCommandHandler(Element e, FeatureTemplate f) throws ParsingException {
133 HandlerEntry he = makeHandlerEntry(e);
134 if (e.getAttribute("default").equals("true")) {
135 f.setDefaultCommandHandler(he);
137 Class<? extends Command> command = parseCommandClass(e.getAttribute("command"));
138 f.addCommandHandler(command, he);
142 private static void parseMessageDispatcher(Element e, FeatureTemplate f) throws DOMException, ParsingException {
143 HandlerEntry he = makeHandlerEntry(e);
144 f.setMessageDispatcher(he);
147 private static void parsePollHandler(Element e, FeatureTemplate f) throws ParsingException {
148 HandlerEntry he = makeHandlerEntry(e);
149 f.setPollHandler(he);
152 private static Class<? extends Command> parseCommandClass(String c) throws ParsingException {
153 if (c.equals("OnOffType")) {
154 return OnOffType.class;
155 } else if (c.equals("PercentType")) {
156 return PercentType.class;
157 } else if (c.equals("DecimalType")) {
158 return DecimalType.class;
159 } else if (c.equals("IncreaseDecreaseType")) {
160 return IncreaseDecreaseType.class;
162 throw new ParsingException("Unknown Command Type");