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.homematic.internal.communicator.message;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.text.ParseException;
18 import java.util.ArrayList;
19 import java.util.Base64;
20 import java.util.HashMap;
21 import java.util.LinkedList;
22 import java.util.List;
25 import javax.xml.parsers.ParserConfigurationException;
26 import javax.xml.parsers.SAXParser;
27 import javax.xml.parsers.SAXParserFactory;
29 import org.xml.sax.Attributes;
30 import org.xml.sax.InputSource;
31 import org.xml.sax.SAXException;
32 import org.xml.sax.helpers.DefaultHandler;
35 * Decodes a XML-RPC message from the Homematic server.
37 * @author Gerhard Riegler - Initial contribution
39 public class XmlRpcResponse implements RpcResponse {
40 private String methodName;
41 private Object[] responseData;
44 * Decodes a XML-RPC message from the given InputStream.
46 public XmlRpcResponse(InputStream is, String encoding)
47 throws SAXException, ParserConfigurationException, IOException {
48 SAXParserFactory factory = SAXParserFactory.newInstance();
49 SAXParser saxParser = factory.newSAXParser();
50 factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
51 saxParser.getXMLReader().setFeature("http://xml.org/sax/features/external-general-entities", false);
52 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
53 InputSource inputSource = new InputSource(is);
54 inputSource.setEncoding(encoding);
55 saxParser.parse(inputSource, new XmlRpcHandler());
59 public Object[] getResponseData() {
64 public String getMethodName() {
69 public String toString() {
70 return RpcUtils.dumpRpcMessage(methodName, responseData);
74 * SAX parser implementation to decode XML-RPC.
76 * @author Gerhard Riegler
78 private class XmlRpcHandler extends DefaultHandler {
79 private List<Object> result = new ArrayList<>();
80 private LinkedList<List<Object>> currentDataObject = new LinkedList<>();
81 private StringBuilder tagValue;
82 private boolean isValueTag;
85 public void startDocument() throws SAXException {
86 currentDataObject.addLast(new ArrayList<>());
90 public void endDocument() throws SAXException {
91 result.addAll(currentDataObject.removeLast());
92 responseData = result.toArray();
96 public void startElement(String uri, String localName, String qName, Attributes attributes)
98 String tag = qName.toLowerCase();
99 if (tag.equals("array") || tag.equals("struct")) {
100 currentDataObject.addLast(new ArrayList<>());
102 isValueTag = tag.equals("value");
103 tagValue = new StringBuilder();
107 public void endElement(String uri, String localName, String qName) throws SAXException {
108 String currentTag = qName.toLowerCase();
109 String currentValue = tagValue.toString();
110 List<Object> data = currentDataObject.peekLast();
112 switch (currentTag) {
114 data.add("1".equals(currentValue) ? Boolean.TRUE : Boolean.FALSE);
118 data.add(Integer.valueOf(currentValue));
121 data.add(Double.valueOf(currentValue));
125 data.add(currentValue);
129 data.add(currentValue);
134 List<Object> arrayData = currentDataObject.removeLast();
135 currentDataObject.peekLast().add(arrayData.toArray());
138 List<Object> mapData = currentDataObject.removeLast();
139 Map<Object, Object> resultMap = new HashMap<>();
141 for (int i = 0; i < mapData.size(); i += 2) {
142 resultMap.put(mapData.get(i), mapData.get(i + 1));
144 currentDataObject.peekLast().add(resultMap);
147 data.add(Base64.getDecoder().decode(currentValue));
149 case "datetime.iso8601":
151 data.add(XmlRpcRequest.xmlRpcDateFormat.parse(currentValue));
152 } catch (ParseException ex) {
153 throw new SAXException(ex.getMessage(), ex);
157 methodName = currentValue;
162 case "methodresponse":
168 throw new SAXException("Unknown XML-RPC tag: " + currentTag);
173 public void characters(char[] ch, int start, int length) throws SAXException {
174 tagValue.append(new String(ch, start, length));