]> git.basschouten.com Git - openhab-addons.git/blob
cc21456d20189ba363c16817143f57edc57f8bd0
[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.ihc.internal.ws.services;
14
15 import java.io.IOException;
16 import java.net.SocketTimeoutException;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Set;
20
21 import javax.xml.xpath.XPathExpressionException;
22
23 import org.openhab.binding.ihc.internal.ws.datatypes.XPathUtils;
24 import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
25 import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
26 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
27 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSDateValue;
28 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
29 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSFloatingPointValue;
30 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
31 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
32 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimeValue;
33 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimerValue;
34 import org.openhab.binding.ihc.internal.ws.resourcevalues.WSWeekdayValue;
35 import org.w3c.dom.Node;
36 import org.w3c.dom.NodeList;
37
38 /**
39  * Class to handle IHC / ELKO LS Controller's resource interaction service.
40  *
41  * Service is used to fetch or update resource values from/to controller.
42  *
43  * @author Pauli Anttila - Initial contribution
44  */
45 public class IhcResourceInteractionService extends IhcBaseService {
46
47     public IhcResourceInteractionService(String host, int timeout, IhcConnectionPool ihcConnectionPool) {
48         super(ihcConnectionPool, timeout, host, "ResourceInteractionService");
49     }
50
51     /**
52      * Query resource value from controller.
53      *
54      * @param resoureId Resource Identifier.
55      * @return Resource value.
56      */
57     public WSResourceValue resourceQuery(int resoureId) throws IhcExecption {
58         // @formatter:off
59         final String soapQuery =
60                   """
61                 <?xml version="1.0" encoding="UTF-8"?>
62                 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
63                  <soapenv:Body>
64                   <ns1:getRuntimeValue1 xmlns:ns1="utcs">%s</ns1:getRuntimeValue1>
65                  </soapenv:Body>
66                 </soapenv:Envelope>\
67                 """;
68         // @formatter:on
69
70         String query = String.format(soapQuery, String.valueOf(resoureId));
71         String response = sendSoapQuery(null, query);
72         NodeList nodeList;
73         try {
74             nodeList = XPathUtils.parseList(response, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getRuntimeValue2");
75
76             if (nodeList != null && nodeList.getLength() == 1) {
77                 WSResourceValue val = parseResourceValue(nodeList.item(0));
78
79                 if (val != null && val.resourceID == resoureId) {
80                     return val;
81                 } else {
82                     throw new IhcExecption("No resource id found");
83                 }
84             } else {
85                 throw new IhcExecption("No resource value found");
86             }
87         } catch (XPathExpressionException | NumberFormatException | IOException e) {
88             throw new IhcExecption("Error occured during XML data parsing", e);
89         }
90     }
91
92     private WSResourceValue parseResourceValue(Node n) throws XPathExpressionException, NumberFormatException {
93         // parse resource id
94         String resourceId = XPathUtils.getSpeficValueFromNode(n, "ns1:resourceID");
95
96         if (resourceId != null && !resourceId.isBlank()) {
97             int id = Integer.parseInt(resourceId);
98
99             // Parse floating point value
100             String floatingPointValue = getValue(n, "floatingPointValue");
101             if (floatingPointValue != null && !floatingPointValue.isBlank()) {
102                 String min = getValue(n, "minimumValue");
103                 String max = getValue(n, "maximumValue");
104                 return new WSFloatingPointValue(id, Double.valueOf(floatingPointValue), Double.valueOf(min),
105                         Double.valueOf(max));
106             }
107
108             // Parse boolean value
109             String value = getValue(n, "value");
110             if (value != null && !value.isBlank()) {
111                 return new WSBooleanValue(id, Boolean.valueOf(value));
112             }
113
114             // Parse integer value
115             String integer = getValue(n, "integer");
116             if (integer != null && !integer.isBlank()) {
117                 String min = getValue(n, "minimumValue");
118                 String max = getValue(n, "maximumValue");
119                 return new WSIntegerValue(id, Integer.valueOf(integer), Integer.valueOf(min), Integer.valueOf(max));
120             }
121
122             // Parse timer value
123             String milliseconds = getValue(n, "milliseconds");
124             if (milliseconds != null && !milliseconds.isBlank()) {
125                 return new WSTimerValue(id, Integer.valueOf(milliseconds));
126             }
127
128             // Parse time value
129             String hours = getValue(n, "hours");
130             if (hours != null && !hours.isBlank()) {
131                 String minutes = getValue(n, "minutes");
132                 String seconds = getValue(n, "seconds");
133                 return new WSTimeValue(id, Integer.valueOf(hours), Integer.valueOf(minutes), Integer.valueOf(seconds));
134             }
135
136             // Parse date value
137             String year = getValue(n, "year");
138             if (year != null && !year.isBlank()) {
139                 String month = getValue(n, "month");
140                 String day = getValue(n, "day");
141                 return new WSDateValue(id, Short.valueOf(year), Byte.valueOf(month), Byte.valueOf(day));
142             }
143
144             // Parse enum value
145             String definitionTypeID = getValue(n, "definitionTypeID");
146             if (definitionTypeID != null && !definitionTypeID.isBlank()) {
147                 String enumValueID = getValue(n, "enumValueID");
148                 String enumName = getValue(n, "enumName");
149                 return new WSEnumValue(id, Integer.valueOf(definitionTypeID), Integer.valueOf(enumValueID), enumName);
150             }
151
152             // Parse week day value
153             value = getValue(n, "weekdayNumber");
154             if (value != null && !value.isBlank()) {
155                 return new WSWeekdayValue(id, Integer.valueOf(value));
156             }
157
158             // Unknown value type
159             throw new IllegalArgumentException("Unsupported value type");
160         }
161         return null;
162     }
163
164     private String getValue(Node n, String value) throws XPathExpressionException {
165         return XPathUtils.getSpeficValueFromNode(n, "ns1:value/" + XPathUtils.createIgnoreNameSpaceSyntaxExpr(value));
166     }
167
168     /**
169      * Update resource value to controller.
170      *
171      *
172      * @param value Resource value.
173      * @return True if value is successfully updated.
174      */
175     public boolean resourceUpdate(WSResourceValue value) throws IhcExecption {
176         boolean retval = false;
177
178         if (value instanceof WSFloatingPointValue pointValue) {
179             retval = resourceUpdate(pointValue);
180         } else if (value instanceof WSBooleanValue booleanValue) {
181             retval = resourceUpdate(booleanValue);
182         } else if (value instanceof WSIntegerValue integerValue) {
183             retval = resourceUpdate(integerValue);
184         } else if (value instanceof WSTimerValue timerValue) {
185             retval = resourceUpdate(timerValue);
186         } else if (value instanceof WSWeekdayValue weekdayValue) {
187             retval = resourceUpdate(weekdayValue);
188         } else if (value instanceof WSEnumValue enumValue) {
189             retval = resourceUpdate(enumValue);
190         } else if (value instanceof WSTimeValue timeValue) {
191             retval = resourceUpdate(timeValue);
192         } else if (value instanceof WSDateValue dateValue) {
193             retval = resourceUpdate(dateValue);
194         } else {
195             throw new IhcExecption("Unsupported value type " + value.getClass().toString());
196         }
197
198         return retval;
199     }
200
201     public boolean resourceUpdate(WSBooleanValue value) throws IhcExecption {
202         // @formatter:off
203         final String soapQuery =
204                   """
205                 <?xml version="1.0" encoding="UTF-8"?>
206                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
207                  <soap:Body>
208                   <setResourceValue1 xmlns="utcs">
209                    <value xmlns:q1="utcs.values" xsi:type="q1:WSBooleanValue">
210                     <q1:value>%s</q1:value>
211                    </value>
212                    <resourceID>%s</resourceID>
213                    <isValueRuntime>true</isValueRuntime>
214                   </setResourceValue1>
215                  </soap:Body>
216                 </soap:Envelope>\
217                 """;
218         // @formatter:on
219
220         String query = String.format(soapQuery, value.value ? "true" : "false", value.resourceID);
221         return doResourceUpdate(query);
222     }
223
224     public boolean resourceUpdate(WSFloatingPointValue value) throws IhcExecption {
225         // @formatter:off
226         final String soapQuery =
227                   """
228                 <?xml version="1.0" encoding="UTF-8"?>
229                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
230                  <soap:Body>
231                   <setResourceValue1 xmlns="utcs">
232                    <value xmlns:q1="utcs.values" xsi:type="q1:WSFloatingPointValue">
233                     <q1:maximumValue>%s</q1:maximumValue>
234                     <q1:minimumValue>%s</q1:minimumValue>
235                     <q1:floatingPointValue>%s</q1:floatingPointValue>
236                    </value>
237                    <resourceID>%s</resourceID>
238                    <isValueRuntime>true</isValueRuntime>
239                   </setResourceValue1>
240                  </soap:Body>
241                 </soap:Envelope>\
242                 """;
243         // @formatter:on
244
245         String query = String.format(soapQuery, value.maximumValue, value.minimumValue, value.value, value.resourceID);
246         return doResourceUpdate(query);
247     }
248
249     public boolean resourceUpdate(WSIntegerValue value) throws IhcExecption {
250         // @formatter:off
251         final String soapQuery =
252                   """
253                 <?xml version="1.0" encoding="UTF-8"?>
254                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
255                  <soap:Body>
256                   <setResourceValue1 xmlns="utcs">
257                    <value xmlns:q1="utcs.values" xsi:type="q1:WSIntegerValue">
258                     <q1:maximumValue>%s</q1:maximumValue>
259                     <q1:minimumValue>%s</q1:minimumValue>
260                     <q1:integer>%s</q1:integer>
261                    </value>
262                    <resourceID>%s</resourceID>
263                    <isValueRuntime>true</isValueRuntime>
264                   </setResourceValue1>
265                  </soap:Body>
266                 </soap:Envelope>\
267                 """;
268         // @formatter:on
269
270         String query = String.format(soapQuery, value.maximumValue, value.minimumValue, value.value, value.resourceID);
271         return doResourceUpdate(query);
272     }
273
274     public boolean resourceUpdate(WSTimerValue value) throws IhcExecption {
275         // @formatter:off
276         final String soapQuery =
277                   """
278                 <?xml version="1.0" encoding="UTF-8"?>
279                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
280                  <soap:Body>
281                   <setResourceValue1 xmlns="utcs">
282                    <value xmlns:q1="utcs.values" xsi:type="q1:WSTimerValue">
283                     <q1:milliseconds>%s</q1:milliseconds>
284                    </value>
285                    <resourceID>%s</resourceID>
286                    <isValueRuntime>true</isValueRuntime>
287                   </setResourceValue1>
288                  </soap:Body>
289                 </soap:Envelope>\
290                 """;
291         // @formatter:on
292
293         String query = String.format(soapQuery, value.milliseconds, value.resourceID);
294         return doResourceUpdate(query);
295     }
296
297     public boolean resourceUpdate(WSWeekdayValue value) throws IhcExecption {
298         // @formatter:off
299         final String soapQuery =
300                   """
301                 <?xml version="1.0" encoding="UTF-8"?>
302                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
303                  <soap:Body>
304                   <setResourceValue1 xmlns="utcs">
305                    <value xmlns:q1="utcs.values" xsi:type="q1:WSWeekdayValue">
306                     <q1:weekdayNumber>%s</q1:weekdayNumber>
307                    </value>
308                    <resourceID>%s</resourceID>
309                    <isValueRuntime>true</isValueRuntime>
310                   </setResourceValue1>
311                  </soap:Body>
312                 </soap:Envelope>\
313                 """;
314         // @formatter:on
315
316         String query = String.format(soapQuery, value.weekdayNumber, value.resourceID);
317         return doResourceUpdate(query);
318     }
319
320     public boolean resourceUpdate(WSEnumValue value) throws IhcExecption {
321         // @formatter:off
322         final String soapQuery =
323                   """
324                 <?xml version="1.0" encoding="UTF-8"?>
325                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
326                  <soap:Body>
327                   <setResourceValue1 xmlns="utcs">
328                    <value xmlns:q1="utcs.values" xsi:type="q1:WSEnumValue">
329                     <q1:definitionTypeID>%s</q1:definitionTypeID>
330                     <q1:enumValueID>%s</q1:enumValueID>
331                     <q1:enumName>%s</q1:enumName>
332                    </value>
333                    <resourceID>%s</resourceID>
334                    <isValueRuntime>true</isValueRuntime>
335                   </setResourceValue1>
336                  </soap:Body>
337                 </soap:Envelope>\
338                 """;
339         // @formatter:on
340
341         String query = String.format(soapQuery, value.definitionTypeID, value.enumValueID, value.enumName,
342                 value.resourceID);
343         return doResourceUpdate(query);
344     }
345
346     public boolean resourceUpdate(WSTimeValue value) throws IhcExecption {
347         // @formatter:off
348         final String soapQuery =
349                   """
350                 <?xml version="1.0" encoding="UTF-8"?>
351                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
352                  <soap:Body>
353                   <setResourceValue1 xmlns="utcs">
354                    <value xmlns:q1="utcs.values" xsi:type="q1:WSTimeValue">
355                     <q1:hours>%s</q1:hours>
356                     <q1:minutes>%s</q1:minutes>
357                     <q1:seconds>%s</q1:seconds>
358                    </value>
359                    <resourceID>%s</resourceID>
360                    <isValueRuntime>true</isValueRuntime>
361                   </setResourceValue1>
362                  </soap:Body>
363                 </soap:Envelope>\
364                 """;
365         // @formatter:on
366
367         String query = String.format(soapQuery, value.hours, value.minutes, value.seconds, value.resourceID);
368         return doResourceUpdate(query);
369     }
370
371     public boolean resourceUpdate(WSDateValue value) throws IhcExecption {
372         // @formatter:off
373         final String soapQuery =
374                   """
375                 <?xml version="1.0" encoding="UTF-8"?>
376                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
377                  <soap:Body>
378                   <setResourceValue1 xmlns="utcs">
379                    <value xmlns:q1="utcs.values" xsi:type="q1:WSDateValue">
380                     <q1:month>%s</q1:month>
381                     <q1:year>%s</q1:year>
382                     <q1:day>%s</q1:day>
383                    </value>
384                    <resourceID>%s</resourceID>
385                    <isValueRuntime>true</isValueRuntime>
386                   </setResourceValue1>
387                  </soap:Body>
388                 </soap:Envelope>\
389                 """;
390         // @formatter:on
391
392         String query = String.format(soapQuery, value.month, value.year, value.day, value.resourceID);
393         return doResourceUpdate(query);
394     }
395
396     private boolean doResourceUpdate(String query) throws IhcExecption {
397         String response = sendSoapQuery(null, query);
398         try {
399             return Boolean.parseBoolean(
400                     XPathUtils.parseXMLValue(response, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:setResourceValue2"));
401         } catch (IOException | XPathExpressionException e) {
402             throw new IhcExecption(e);
403         }
404     }
405
406     /**
407      * Enable resources runtime value notifications.
408      *
409      * @param resourceIdList List of resource Identifiers.
410      * @return True is connection successfully opened.
411      */
412     public void enableRuntimeValueNotifications(Set<Integer> resourceIdList) throws IhcExecption {
413         // @formatter:off
414         final String soapQueryPrefix =
415                   """
416                 <?xml version="1.0" encoding="UTF-8"?>
417                 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
418                  <soap:Body>
419                   <enableRuntimeValueNotifications1 xmlns="utcs">
420                 """;
421
422         final String soapQuerySuffix =
423                   """
424                   </enableRuntimeValueNotifications1>
425                  </soap:Body>
426                 </soap:Envelope>\
427                 """;
428         // @formatter:on
429
430         String query = soapQueryPrefix;
431         for (int i : resourceIdList) {
432             query += "   <xsd:arrayItem>" + i + "</xsd:arrayItem>\n";
433         }
434         query += soapQuerySuffix;
435         sendSoapQuery(null, query);
436     }
437
438     /**
439      * Wait runtime value notifications.
440      *
441      * Runtime value notification should firstly be activated by
442      * enableRuntimeValueNotifications function.
443      *
444      * @param timeoutInSeconds How many seconds to wait notifications.
445      * @return List of received runtime value notifications.
446      * @throws SocketTimeoutException
447      * @throws IhcTimeoutExecption
448      */
449     public List<WSResourceValue> waitResourceValueNotifications(int timeoutInSeconds) throws IhcExecption {
450         // @formatter:off
451         final String soapQuery =
452                   """
453                 <?xml version="1.0" encoding="UTF-8"?>
454                 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:utcs="utcs">
455                  <soapenv:Body>
456                   <utcs:waitForResourceValueChanges1>%s</utcs:waitForResourceValueChanges1>
457                  </soapenv:Body>
458                 </soapenv:Envelope>\
459                 """;
460         // @formatter:on
461
462         String query = String.format(soapQuery, timeoutInSeconds);
463         String response = sendSoapQuery(null, query, getTimeout() + timeoutInSeconds * 1000);
464         List<WSResourceValue> resourceValueList = new ArrayList<>();
465
466         try {
467             NodeList nodeList = XPathUtils.parseList(response,
468                     "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:waitForResourceValueChanges2/ns1:arrayItem");
469
470             if (nodeList != null) {
471                 if (nodeList.getLength() == 1) {
472                     String resourceId = XPathUtils.getSpeficValueFromNode(nodeList.item(0), "ns1:resourceID");
473                     if (resourceId == null || resourceId.isEmpty()) {
474                         // IHC controller indicates timeout, return empty list
475                         return resourceValueList;
476                     }
477                 }
478
479                 for (int i = 0; i < nodeList.getLength(); i++) {
480                     WSResourceValue newVal = parseResourceValue(nodeList.item(i));
481                     if (newVal != null) {
482                         resourceValueList.add(newVal);
483                     }
484                 }
485             } else {
486                 throw new IhcExecption("Illegal resource value notification response received");
487             }
488             return resourceValueList;
489         } catch (XPathExpressionException | NumberFormatException | IOException e) {
490             throw new IhcExecption("Error occured during XML data parsing", e);
491         }
492     }
493 }