2 * Copyright (c) 2010-2023 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.StringReader;
17 import java.net.URISyntaxException;
18 import java.util.Random;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.TimeoutException;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
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.StringContentProvider;
27 import org.eclipse.jetty.http.HttpMethod;
28 import org.openhab.binding.miele.internal.exceptions.MieleRpcException;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 import com.google.gson.Gson;
33 import com.google.gson.JsonArray;
34 import com.google.gson.JsonElement;
35 import com.google.gson.JsonObject;
36 import com.google.gson.JsonParseException;
37 import com.google.gson.JsonParser;
40 * The {@link MieleGatewayCommunicationController} class is used for communicating with
41 * the XGW 3000 gateway through JSON-RPC.
43 * @author Jacob Laursen - Initial contribution
46 public class MieleGatewayCommunicationController {
48 private final URI uri;
49 private final Random rand = new Random();
50 private final Gson gson = new Gson();
51 private final Logger logger = LoggerFactory.getLogger(MieleGatewayCommunicationController.class);
52 private final HttpClient httpClient;
54 public MieleGatewayCommunicationController(HttpClient httpClient, String host) throws URISyntaxException {
55 uri = new URI("http://" + host + "/remote/json-rpc");
56 this.httpClient = httpClient;
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 requestBodyAsJson = new JsonObject();
73 int id = rand.nextInt(Integer.MAX_VALUE);
74 requestBodyAsJson.addProperty("jsonrpc", "2.0");
75 requestBodyAsJson.addProperty("id", id);
76 requestBodyAsJson.addProperty("method", methodName);
78 JsonArray params = new JsonArray();
79 for (Object o : args) {
80 params.add(gson.toJsonTree(o));
82 requestBodyAsJson.add("params", params);
84 String requestBody = requestBodyAsJson.toString();
85 Request request = httpClient.newRequest(uri).method(HttpMethod.POST)
86 .content(new StringContentProvider(requestBody), "application/json");
88 String responseData = null;
90 final ContentResponse contentResponse = request.send();
91 final int httpStatus = contentResponse.getStatus();
92 if (httpStatus != 200) {
93 if (httpStatus == 503) {
94 throw new MieleRpcException("Gateway is temporarily unavailable");
96 throw new MieleRpcException("Unexpected HTTP status code " + httpStatus);
98 responseData = contentResponse.getContentAsString();
99 } catch (TimeoutException e) {
100 throw new MieleRpcException("Timeout when calling gateway", e);
101 } catch (ExecutionException e) {
102 throw new MieleRpcException("Failure when calling gateway", e);
103 } catch (InterruptedException e) {
104 Thread.currentThread().interrupt();
105 throw new MieleRpcException("Interrupted while calling gateway", e);
108 logger.trace("The request '{}' yields '{}'", requestBody, responseData);
109 JsonObject parsedResponse = null;
111 parsedResponse = (JsonObject) JsonParser.parseReader(new StringReader(responseData));
112 } catch (JsonParseException e) {
113 throw new MieleRpcException("Error parsing JSON response", e);
116 JsonElement error = parsedResponse.get("error");
117 if (error != null && !error.isJsonNull()) {
118 if (error.isJsonPrimitive()) {
119 throw new MieleRpcException("Remote exception occurred: '" + error.getAsString() + "'");
120 } else if (error.isJsonObject()) {
121 JsonObject o = error.getAsJsonObject();
122 Integer code = (o.has("code") ? o.get("code").getAsInt() : null);
123 String message = (o.has("message") ? o.get("message").getAsString() : null);
124 String data = (o.has("data")
125 ? (o.get("data") instanceof JsonObject ? o.get("data").toString() : o.get("data").getAsString())
127 throw new MieleRpcException(
128 "Remote exception occurred: '" + code + "':'" + message + "':'" + data + "'");
130 throw new MieleRpcException("Unknown remote exception occurred: '" + error.toString() + "'");
134 result = parsedResponse.get("result");
135 if (result == null) {
136 throw new MieleRpcException("Result is missing in response");