2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.miele.internal;
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;
24 import java.util.Collections;
26 import java.util.Random;
27 import java.util.zip.GZIPInputStream;
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;
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;
42 * The {@link MieleGatewayCommunicationController} class is used for communicating with
43 * the XGW 3000 gateway through JSON-RPC.
45 * @author Jacob Laursen - Initial contribution
48 public class MieleGatewayCommunicationController {
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);
55 public MieleGatewayCommunicationController(String host) throws MalformedURLException {
56 url = new URL("http://" + host + "/remote/json-rpc");
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;
67 return invokeRPC("HDAccess/invokeDCOOperation", args);
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);
78 JsonArray params = new JsonArray();
79 for (Object o : args) {
80 params.add(gson.toJsonTree(o));
82 req.add("params", params);
84 String requestData = req.toString();
85 String responseData = null;
87 responseData = post(url, Collections.emptyMap(), requestData);
88 } catch (IOException e) {
89 throw new MieleRpcException("Exception occurred while posting data", e);
92 logger.trace("The request '{}' yields '{}'", requestData, responseData);
93 JsonObject parsedResponse = null;
95 parsedResponse = (JsonObject) JsonParser.parseReader(new StringReader(responseData));
96 } catch (JsonParseException e) {
97 throw new MieleRpcException("Error parsing JSON response", e);
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())
111 throw new MieleRpcException(
112 "Remote exception occurred: '" + code + "':'" + message + "':'" + data + "'");
114 throw new MieleRpcException("Unknown remote exception occurred: '" + error.toString() + "'");
118 result = parsedResponse.get("result");
119 if (result == null) {
120 throw new MieleRpcException("Result is missing in response");
126 private String post(URL url, Map<String, String> headers, String data) throws IOException {
127 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
129 for (Map.Entry<String, String> entry : headers.entrySet()) {
130 connection.addRequestProperty(entry.getKey(), entry.getValue());
133 connection.addRequestProperty("Accept-Encoding", "gzip");
134 connection.setRequestMethod("POST");
135 connection.setDoOutput(true);
136 connection.connect();
138 OutputStream out = null;
141 out = connection.getOutputStream();
143 out.write(data.getBytes());
146 int statusCode = connection.getResponseCode();
147 if (statusCode != HttpURLConnection.HTTP_OK) {
148 logger.debug("An unexpected status code was returned: '{}'", statusCode);
156 String responseEncoding = connection.getHeaderField("Content-Encoding");
157 responseEncoding = (responseEncoding == null ? "" : responseEncoding.trim());
159 ByteArrayOutputStream bos = new ByteArrayOutputStream();
161 InputStream in = connection.getInputStream();
163 in = connection.getInputStream();
164 if ("gzip".equalsIgnoreCase(responseEncoding)) {
165 in = new GZIPInputStream(in);
167 in = new BufferedInputStream(in);
169 byte[] buff = new byte[1024];
171 while ((n = in.read(buff)) > 0) {
172 bos.write(buff, 0, n);
182 return bos.toString();