]> git.basschouten.com Git - openhab-addons.git/blob
58f5363b3d1058b4e9a3ea1c4178e5db0c2afb72
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.miele.internal;
14
15 import java.io.BufferedInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.io.StringReader;
21 import java.net.HttpURLConnection;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.util.Collections;
25 import java.util.Map;
26 import java.util.Random;
27 import java.util.zip.GZIPInputStream;
28
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.openhab.binding.miele.internal.exceptions.MieleRpcException;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import com.google.gson.Gson;
35 import com.google.gson.JsonArray;
36 import com.google.gson.JsonElement;
37 import com.google.gson.JsonObject;
38 import com.google.gson.JsonParseException;
39 import com.google.gson.JsonParser;
40
41 /**
42  * The {@link MieleGatewayCommunicationController} class is used for communicating with
43  * the XGW 3000 gateway through JSON-RPC.
44  *
45  * @author Jacob Laursen - Initial contribution
46  */
47 @NonNullByDefault
48 public class MieleGatewayCommunicationController {
49
50     private final URL url;
51     private final Random rand = new Random();
52     private final Gson gson = new Gson();
53     private final Logger logger = LoggerFactory.getLogger(MieleGatewayCommunicationController.class);
54
55     public MieleGatewayCommunicationController(String host) throws MalformedURLException {
56         url = new URL("http://" + host + "/remote/json-rpc");
57     }
58
59     public JsonElement invokeOperation(FullyQualifiedApplianceIdentifier applianceIdentifier, String modelID,
60             String methodName) throws MieleRpcException {
61         Object[] args = new Object[4];
62         args[0] = applianceIdentifier.getUid();
63         args[1] = MieleBindingConstants.MIELE_CLASS + modelID;
64         args[2] = methodName;
65         args[3] = null;
66
67         return invokeRPC("HDAccess/invokeDCOOperation", args);
68     }
69
70     public JsonElement invokeRPC(String methodName, Object[] args) throws MieleRpcException {
71         JsonElement result = null;
72         JsonObject req = new JsonObject();
73         int id = rand.nextInt(Integer.MAX_VALUE);
74         req.addProperty("jsonrpc", "2.0");
75         req.addProperty("id", id);
76         req.addProperty("method", methodName);
77
78         JsonArray params = new JsonArray();
79         for (Object o : args) {
80             params.add(gson.toJsonTree(o));
81         }
82         req.add("params", params);
83
84         String requestData = req.toString();
85         String responseData = null;
86         try {
87             responseData = post(url, Collections.emptyMap(), requestData);
88         } catch (IOException e) {
89             throw new MieleRpcException("Exception occurred while posting data", e);
90         }
91
92         logger.trace("The request '{}' yields '{}'", requestData, responseData);
93         JsonObject parsedResponse = null;
94         try {
95             parsedResponse = (JsonObject) JsonParser.parseReader(new StringReader(responseData));
96         } catch (JsonParseException e) {
97             throw new MieleRpcException("Error parsing JSON response", e);
98         }
99
100         JsonElement error = parsedResponse.get("error");
101         if (error != null && !error.isJsonNull()) {
102             if (error.isJsonPrimitive()) {
103                 throw new MieleRpcException("Remote exception occurred: '" + error.getAsString() + "'");
104             } else if (error.isJsonObject()) {
105                 JsonObject o = error.getAsJsonObject();
106                 Integer code = (o.has("code") ? o.get("code").getAsInt() : null);
107                 String message = (o.has("message") ? o.get("message").getAsString() : null);
108                 String data = (o.has("data")
109                         ? (o.get("data") instanceof JsonObject ? o.get("data").toString() : o.get("data").getAsString())
110                         : null);
111                 throw new MieleRpcException(
112                         "Remote exception occurred: '" + code + "':'" + message + "':'" + data + "'");
113             } else {
114                 throw new MieleRpcException("Unknown remote exception occurred: '" + error.toString() + "'");
115             }
116         }
117
118         result = parsedResponse.get("result");
119         if (result == null) {
120             throw new MieleRpcException("Result is missing in response");
121         }
122
123         return result;
124     }
125
126     private String post(URL url, Map<String, String> headers, String data) throws IOException {
127         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
128
129         for (Map.Entry<String, String> entry : headers.entrySet()) {
130             connection.addRequestProperty(entry.getKey(), entry.getValue());
131         }
132
133         connection.addRequestProperty("Accept-Encoding", "gzip");
134         connection.setRequestMethod("POST");
135         connection.setDoOutput(true);
136         connection.connect();
137
138         OutputStream out = null;
139
140         try {
141             out = connection.getOutputStream();
142
143             out.write(data.getBytes());
144             out.flush();
145
146             int statusCode = connection.getResponseCode();
147             if (statusCode != HttpURLConnection.HTTP_OK) {
148                 logger.debug("An unexpected status code was returned: '{}'", statusCode);
149             }
150         } finally {
151             if (out != null) {
152                 out.close();
153             }
154         }
155
156         String responseEncoding = connection.getHeaderField("Content-Encoding");
157         responseEncoding = (responseEncoding == null ? "" : responseEncoding.trim());
158
159         ByteArrayOutputStream bos = new ByteArrayOutputStream();
160
161         InputStream in = connection.getInputStream();
162         try {
163             in = connection.getInputStream();
164             if ("gzip".equalsIgnoreCase(responseEncoding)) {
165                 in = new GZIPInputStream(in);
166             }
167             in = new BufferedInputStream(in);
168
169             byte[] buff = new byte[1024];
170             int n;
171             while ((n = in.read(buff)) > 0) {
172                 bos.write(buff, 0, n);
173             }
174             bos.flush();
175             bos.close();
176         } finally {
177             if (in != null) {
178                 in.close();
179             }
180         }
181
182         return bos.toString();
183     }
184 }