]> git.basschouten.com Git - openhab-addons.git/blob
ea1a16f33f94b6e15e7f3220f4c2966988b4784a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.math.BigDecimal;
16 import java.math.RoundingMode;
17 import java.text.SimpleDateFormat;
18 import java.util.ArrayList;
19 import java.util.Base64;
20 import java.util.Calendar;
21 import java.util.Date;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Map.Entry;
25
26 import org.openhab.core.util.StringUtils;
27
28 /**
29  * A XML-RPC request for sending data to the Homematic server.
30  *
31  * @author Gerhard Riegler - Initial contribution
32  */
33 public class XmlRpcRequest implements RpcRequest<String> {
34
35     public enum TYPE {
36         REQUEST,
37         RESPONSE
38     }
39
40     private String methodName;
41     private List<Object> parms;
42     private StringBuilder sb;
43     private TYPE type;
44     public static final SimpleDateFormat XML_RPC_DATEFORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
45
46     public XmlRpcRequest(String methodName) {
47         this(methodName, TYPE.REQUEST);
48     }
49
50     public XmlRpcRequest(String methodName, TYPE type) {
51         this.methodName = methodName;
52         this.type = type;
53         parms = new ArrayList<>();
54     }
55
56     @Override
57     public void addArg(Object parameter) {
58         parms.add(parameter);
59     }
60
61     @Override
62     public String createMessage() {
63         return toString();
64     }
65
66     @Override
67     public String getMethodName() {
68         return methodName;
69     }
70
71     @Override
72     public String toString() {
73         sb = new StringBuilder();
74
75         sb.append("<?xml");
76         attr("version", "1.0");
77         attr("encoding", "ISO-8859-1");
78         sb.append("?>\n");
79
80         if (type == TYPE.REQUEST) {
81             sb.append("<methodCall>");
82             tag("methodName", methodName);
83         } else {
84             sb.append("<methodResponse>");
85         }
86
87         sb.append("\n");
88         sb.append("<params>");
89         for (Object parameter : parms) {
90             sb.append("<param><value>");
91             generateValue(parameter);
92             sb.append("</value></param>");
93         }
94         sb.append("</params>");
95
96         if (type == TYPE.REQUEST) {
97             sb.append("</methodCall>");
98         } else {
99             sb.append("</methodResponse>");
100         }
101         return sb.toString();
102     }
103
104     /**
105      * Generates a XML attribute.
106      */
107     private void attr(String name, String value) {
108         sb.append(" ").append(name).append("=\"").append(value).append("\"");
109     }
110
111     /**
112      * Generates a XML tag.
113      */
114     private void tag(String name, String value) {
115         sb.append("<").append(name).append(">").append(value).append("</").append(name).append(">");
116     }
117
118     /**
119      * Generates a value tag based on the type of the value.
120      */
121     private void generateValue(Object value) {
122         if (value == null) {
123             tag("string", "void");
124         } else {
125             Class<?> clazz = value.getClass();
126             if (clazz == String.class || clazz == Character.class) {
127                 sb.append(StringUtils.escapeXml(value.toString()));
128             } else if (clazz == Long.class || clazz == Integer.class || clazz == Short.class || clazz == Byte.class) {
129                 tag("int", value.toString());
130             } else if (clazz == Double.class) {
131                 tag("double", String.valueOf(((Double) value).doubleValue()));
132             } else if (clazz == Float.class) {
133                 BigDecimal bd = new BigDecimal((Float) value);
134                 generateValue(bd.setScale(6, RoundingMode.HALF_DOWN).doubleValue());
135             } else if (clazz == BigDecimal.class) {
136                 generateValue(((BigDecimal) value).setScale(6, RoundingMode.HALF_DOWN).doubleValue());
137             } else if (clazz == Boolean.class) {
138                 tag("boolean", ((Boolean) value).booleanValue() ? "1" : "0");
139             } else if (clazz == Date.class) {
140                 synchronized (XML_RPC_DATEFORMAT) {
141                     tag("dateTime.iso8601", XML_RPC_DATEFORMAT.format(((Date) value)));
142                 }
143             } else if (value instanceof Calendar calendar) {
144                 generateValue(calendar.getTime());
145             } else if (value instanceof byte[] bytes) {
146                 tag("base64", Base64.getEncoder().encodeToString(bytes));
147             } else if (clazz.isArray() || value instanceof List) {
148                 sb.append("<array><data>");
149
150                 Object[] array = null;
151                 if (value instanceof List list) {
152                     array = list.toArray();
153                 } else {
154                     array = (Object[]) value;
155                 }
156                 for (Object arrayObject : array) {
157                     sb.append("<value>");
158                     generateValue(arrayObject);
159                     sb.append("</value>");
160                 }
161
162                 sb.append("</data></array>");
163             } else if (value instanceof Map) {
164                 sb.append("<struct>");
165
166                 for (Entry<?, ?> entry : ((Map<?, ?>) value).entrySet()) {
167                     sb.append("<member>");
168                     sb.append("<name>").append(entry.getKey()).append("</name>");
169                     sb.append("<value>");
170                     generateValue(entry.getValue());
171                     sb.append("</value>");
172                     sb.append("</member>");
173                 }
174
175                 sb.append("</struct>");
176             } else {
177                 throw new RuntimeException("Unsupported XML-RPC Type: " + value.getClass());
178             }
179         }
180     }
181 }