2 * Copyright (c) 2010-2023 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.homematic.internal.communicator.message;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.nio.charset.Charset;
18 import java.text.ParseException;
19 import java.util.ArrayList;
20 import java.util.Base64;
21 import java.util.HashMap;
22 import java.util.LinkedList;
23 import java.util.List;
26 import javax.xml.parsers.ParserConfigurationException;
27 import javax.xml.parsers.SAXParser;
28 import javax.xml.parsers.SAXParserFactory;
30 import org.xml.sax.Attributes;
31 import org.xml.sax.InputSource;
32 import org.xml.sax.SAXException;
33 import org.xml.sax.helpers.DefaultHandler;
36 * Decodes a XML-RPC message from the Homematic server.
38 * @author Gerhard Riegler - Initial contribution
40 public class XmlRpcResponse implements RpcResponse {
41 private String methodName;
42 private Object[] responseData;
45 * Decodes a XML-RPC message from the given InputStream.
47 public XmlRpcResponse(InputStream is, Charset encoding)
48 throws SAXException, ParserConfigurationException, IOException {
49 SAXParserFactory factory = SAXParserFactory.newInstance();
50 SAXParser saxParser = factory.newSAXParser();
51 factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
52 saxParser.getXMLReader().setFeature("http://xml.org/sax/features/external-general-entities", false);
53 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
54 InputSource inputSource = new InputSource(is);
55 inputSource.setEncoding(encoding.name());
56 saxParser.parse(inputSource, new XmlRpcHandler());
60 public Object[] getResponseData() {
65 public String getMethodName() {
70 public String toString() {
71 return RpcUtils.dumpRpcMessage(methodName, responseData);
75 * SAX parser implementation to decode XML-RPC.
77 * @author Gerhard Riegler
79 private class XmlRpcHandler extends DefaultHandler {
80 private List<Object> result = new ArrayList<>();
81 private LinkedList<List<Object>> currentDataObject = new LinkedList<>();
82 private StringBuilder tagValue;
83 private boolean isValueTag;
86 public void startDocument() throws SAXException {
87 currentDataObject.addLast(new ArrayList<>());
91 public void endDocument() throws SAXException {
92 result.addAll(currentDataObject.removeLast());
93 responseData = result.toArray();
97 public void startElement(String uri, String localName, String qName, Attributes attributes)
99 String tag = qName.toLowerCase();
100 if ("array".equals(tag) || "struct".equals(tag)) {
101 currentDataObject.addLast(new ArrayList<>());
103 isValueTag = "value".equals(tag);
104 tagValue = new StringBuilder();
108 public void endElement(String uri, String localName, String qName) throws SAXException {
109 String currentTag = qName.toLowerCase();
110 String currentValue = tagValue.toString();
111 List<Object> data = currentDataObject.peekLast();
113 switch (currentTag) {
115 data.add("1".equals(currentValue) ? Boolean.TRUE : Boolean.FALSE);
119 data.add(Integer.valueOf(currentValue));
122 data.add(Double.valueOf(currentValue));
126 data.add(currentValue);
130 data.add(currentValue);
135 List<Object> arrayData = currentDataObject.removeLast();
136 currentDataObject.peekLast().add(arrayData.toArray());
139 List<Object> mapData = currentDataObject.removeLast();
140 Map<Object, Object> resultMap = new HashMap<>();
142 for (int i = 0; i < mapData.size(); i += 2) {
143 resultMap.put(mapData.get(i), mapData.get(i + 1));
145 currentDataObject.peekLast().add(resultMap);
148 data.add(Base64.getDecoder().decode(currentValue));
150 case "datetime.iso8601":
152 data.add(XmlRpcRequest.XML_RPC_DATEFORMAT.parse(currentValue));
153 } catch (ParseException ex) {
154 throw new SAXException(ex.getMessage(), ex);
158 methodName = currentValue;
163 case "methodresponse":
169 throw new SAXException("Unknown XML-RPC tag: " + currentTag);
174 public void characters(char[] ch, int start, int length) throws SAXException {
175 tagValue.append(new String(ch, start, length));