2 * Copyright (c) 2010-2020 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 InputSource inputSource = new InputSource(is);
51 inputSource.setEncoding(encoding);
52 saxParser.parse(inputSource, new XmlRpcHandler());
56 public Object[] getResponseData() {
61 public String getMethodName() {
66 public String toString() {
67 return RpcUtils.dumpRpcMessage(methodName, responseData);
71 * SAX parser implementation to decode XML-RPC.
73 * @author Gerhard Riegler
75 private class XmlRpcHandler extends DefaultHandler {
76 private List<Object> result = new ArrayList<>();
77 private LinkedList<List<Object>> currentDataObject = new LinkedList<>();
78 private StringBuilder tagValue;
79 private boolean isValueTag;
82 public void startDocument() throws SAXException {
83 currentDataObject.addLast(new ArrayList<>());
87 public void endDocument() throws SAXException {
88 result.addAll(currentDataObject.removeLast());
89 responseData = result.toArray();
93 public void startElement(String uri, String localName, String qName, Attributes attributes)
95 String tag = qName.toLowerCase();
96 if (tag.equals("array") || tag.equals("struct")) {
97 currentDataObject.addLast(new ArrayList<>());
99 isValueTag = tag.equals("value");
100 tagValue = new StringBuilder();
104 public void endElement(String uri, String localName, String qName) throws SAXException {
105 String currentTag = qName.toLowerCase();
106 String currentValue = tagValue.toString();
107 List<Object> data = currentDataObject.peekLast();
109 switch (currentTag) {
111 data.add("1".equals(currentValue) ? Boolean.TRUE : Boolean.FALSE);
115 data.add(new Integer(currentValue));
118 data.add(new Double(currentValue));
122 data.add(currentValue);
126 data.add(currentValue);
131 List<Object> arrayData = currentDataObject.removeLast();
132 currentDataObject.peekLast().add(arrayData.toArray());
135 List<Object> mapData = currentDataObject.removeLast();
136 Map<Object, Object> resultMap = new HashMap<>();
138 for (int i = 0; i < mapData.size(); i += 2) {
139 resultMap.put(mapData.get(i), mapData.get(i + 1));
141 currentDataObject.peekLast().add(resultMap);
144 data.add(Base64.getDecoder().decode(currentValue));
146 case "datetime.iso8601":
148 data.add(XmlRpcRequest.xmlRpcDateFormat.parse(currentValue));
149 } catch (ParseException ex) {
150 throw new SAXException(ex.getMessage(), ex);
154 methodName = currentValue;
159 case "methodresponse":
165 throw new SAXException("Unknown XML-RPC tag: " + currentTag);
170 public void characters(char[] ch, int start, int length) throws SAXException {
171 tagValue.append(new String(ch, start, length));