]> git.basschouten.com Git - openhab-addons.git/blob
0ed97cbf8115a15a882a4ebcb3f98e1699448d4e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.homematic.internal.communicator.message;
14
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;
23 import java.util.Map;
24
25 import javax.xml.parsers.ParserConfigurationException;
26 import javax.xml.parsers.SAXParser;
27 import javax.xml.parsers.SAXParserFactory;
28
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;
33
34 /**
35  * Decodes a XML-RPC message from the Homematic server.
36  *
37  * @author Gerhard Riegler - Initial contribution
38  */
39 public class XmlRpcResponse implements RpcResponse {
40     private String methodName;
41     private Object[] responseData;
42
43     /**
44      * Decodes a XML-RPC message from the given InputStream.
45      */
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());
53     }
54
55     @Override
56     public Object[] getResponseData() {
57         return responseData;
58     }
59
60     @Override
61     public String getMethodName() {
62         return methodName;
63     }
64
65     @Override
66     public String toString() {
67         return RpcUtils.dumpRpcMessage(methodName, responseData);
68     }
69
70     /**
71      * SAX parser implementation to decode XML-RPC.
72      *
73      * @author Gerhard Riegler
74      */
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;
80
81         @Override
82         public void startDocument() throws SAXException {
83             currentDataObject.addLast(new ArrayList<>());
84         }
85
86         @Override
87         public void endDocument() throws SAXException {
88             result.addAll(currentDataObject.removeLast());
89             responseData = result.toArray();
90         }
91
92         @Override
93         public void startElement(String uri, String localName, String qName, Attributes attributes)
94                 throws SAXException {
95             String tag = qName.toLowerCase();
96             if (tag.equals("array") || tag.equals("struct")) {
97                 currentDataObject.addLast(new ArrayList<>());
98             }
99             isValueTag = tag.equals("value");
100             tagValue = new StringBuilder();
101         }
102
103         @Override
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();
108
109             switch (currentTag) {
110                 case "boolean":
111                     data.add("1".equals(currentValue) ? Boolean.TRUE : Boolean.FALSE);
112                     break;
113                 case "int":
114                 case "i4":
115                     data.add(new Integer(currentValue));
116                     break;
117                 case "double":
118                     data.add(new Double(currentValue));
119                     break;
120                 case "string":
121                 case "name":
122                     data.add(currentValue);
123                     break;
124                 case "value":
125                     if (isValueTag) {
126                         data.add(currentValue);
127                         isValueTag = false;
128                     }
129                     break;
130                 case "array":
131                     List<Object> arrayData = currentDataObject.removeLast();
132                     currentDataObject.peekLast().add(arrayData.toArray());
133                     break;
134                 case "struct":
135                     List<Object> mapData = currentDataObject.removeLast();
136                     Map<Object, Object> resultMap = new HashMap<>();
137
138                     for (int i = 0; i < mapData.size(); i += 2) {
139                         resultMap.put(mapData.get(i), mapData.get(i + 1));
140                     }
141                     currentDataObject.peekLast().add(resultMap);
142                     break;
143                 case "base64":
144                     data.add(Base64.getDecoder().decode(currentValue));
145                     break;
146                 case "datetime.iso8601":
147                     try {
148                         data.add(XmlRpcRequest.xmlRpcDateFormat.parse(currentValue));
149                     } catch (ParseException ex) {
150                         throw new SAXException(ex.getMessage(), ex);
151                     }
152                     break;
153                 case "methodname":
154                     methodName = currentValue;
155                     break;
156                 case "params":
157                 case "param":
158                 case "methodcall":
159                 case "methodresponse":
160                 case "member":
161                 case "data":
162                 case "fault":
163                     break;
164                 default:
165                     throw new SAXException("Unknown XML-RPC tag: " + currentTag);
166             }
167         }
168
169         @Override
170         public void characters(char[] ch, int start, int length) throws SAXException {
171             tagValue.append(new String(ch, start, length));
172         }
173     }
174 }