]> git.basschouten.com Git - openhab-addons.git/blob
3d82937eb450a6b1d0063be14ea032fe81e12f01
[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.client;
14
15 import java.io.ByteArrayInputStream;
16 import java.io.IOException;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
20
21 import javax.xml.parsers.ParserConfigurationException;
22
23 import org.eclipse.jetty.client.HttpClient;
24 import org.eclipse.jetty.client.api.ContentResponse;
25 import org.eclipse.jetty.client.api.Request;
26 import org.eclipse.jetty.client.util.BytesContentProvider;
27 import org.eclipse.jetty.client.util.FutureResponseListener;
28 import org.eclipse.jetty.http.HttpHeader;
29 import org.openhab.binding.homematic.internal.common.HomematicConfig;
30 import org.openhab.binding.homematic.internal.communicator.message.RpcRequest;
31 import org.openhab.binding.homematic.internal.communicator.message.XmlRpcRequest;
32 import org.openhab.binding.homematic.internal.communicator.message.XmlRpcResponse;
33 import org.openhab.binding.homematic.internal.communicator.parser.RpcResponseParser;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.xml.sax.SAXException;
37
38 /**
39  * Client implementation for sending messages via XML-RPC to the Homematic server.
40  *
41  * @author Gerhard Riegler - Initial contribution
42  */
43 public class XmlRpcClient extends RpcClient<String> {
44     private final Logger logger = LoggerFactory.getLogger(XmlRpcClient.class);
45     private HttpClient httpClient;
46
47     public XmlRpcClient(HomematicConfig config, HttpClient httpClient) throws IOException {
48         super(config);
49         this.httpClient = httpClient;
50     }
51
52     @Override
53     public void dispose() {
54     }
55
56     @Override
57     public RpcRequest<String> createRpcRequest(String methodName) {
58         return new XmlRpcRequest(methodName);
59     }
60
61     /**
62      * Returns the XML-RPC url.
63      */
64     @Override
65     protected String getRpcCallbackUrl() {
66         return "http://" + config.getCallbackHost() + ":" + config.getXmlCallbackPort();
67     }
68
69     @Override
70     protected synchronized Object[] sendMessage(int port, RpcRequest<String> request) throws IOException {
71         if (logger.isTraceEnabled()) {
72             logger.trace("Client XmlRpcRequest (port {}):\n{}", port, request);
73         }
74         IOException reason = new IOException();
75         for (int rpcRetryCounter = 1; rpcRetryCounter <= MAX_RPC_RETRY; rpcRetryCounter++) {
76             try {
77                 byte[] response = send(port, request);
78                 if (response.length == 0 && "setInstallMode".equals(request.getMethodName())) {
79                     return new Object[] {};
80                 }
81                 Object[] data = new XmlRpcResponse(new ByteArrayInputStream(response), config.getEncoding())
82                         .getResponseData();
83                 return new RpcResponseParser(request).parse(data);
84             } catch (UnknownRpcFailureException | UnknownParameterSetException ex) {
85                 throw ex;
86             } catch (SAXException | ParserConfigurationException ex) {
87                 throw new IOException(ex);
88             } catch (IOException ex) {
89                 reason = ex;
90                 if ("init".equals(request.getMethodName())) { // no retries for "init" request
91                     break;
92                 }
93                 logger.debug("XmlRpcMessage failed, sending message again {}/{}", rpcRetryCounter, MAX_RPC_RETRY);
94             }
95         }
96         throw reason;
97     }
98
99     private byte[] send(int port, RpcRequest<String> request) throws IOException {
100         byte[] ret = new byte[0];
101         try {
102             BytesContentProvider content = new BytesContentProvider(
103                     request.createMessage().getBytes(config.getEncoding()));
104             String url = String.format("http://%s:%s", config.getGatewayAddress(), port);
105             if (port == config.getGroupPort()) {
106                 url += "/groups";
107             }
108             Request req = httpClient.POST(url).content(content).timeout(config.getTimeout(), TimeUnit.SECONDS)
109                     .header(HttpHeader.CONTENT_TYPE, "text/xml;charset=" + config.getEncoding());
110             FutureResponseListener listener = new FutureResponseListener(req, config.getBufferSize() * 1024);
111             req.send(listener);
112             ContentResponse response = listener.get(config.getTimeout(), TimeUnit.SECONDS);
113             ret = response.getContent();
114             if (ret == null || ret.length == 0) {
115                 throw new IOException("Received no data from the Homematic gateway");
116             }
117             if (logger.isTraceEnabled()) {
118                 String result = new String(ret, config.getEncoding());
119                 logger.trace("Client XmlRpcResponse (port {}):\n{}", port, result);
120             }
121         } catch (InterruptedException | ExecutionException | TimeoutException | IllegalArgumentException e) {
122             throw new IOException(e);
123         }
124         return ret;
125     }
126 }