diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleGatewayCommunicationController.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleGatewayCommunicationController.java index 58f5363b3..566f4627f 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleGatewayCommunicationController.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleGatewayCommunicationController.java @@ -12,21 +12,19 @@ */ package org.openhab.binding.miele.internal; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.StringReader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.Map; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Random; -import java.util.zip.GZIPInputStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; import org.openhab.binding.miele.internal.exceptions.MieleRpcException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,13 +45,15 @@ import com.google.gson.JsonParser; @NonNullByDefault public class MieleGatewayCommunicationController { - private final URL url; + private final URI uri; private final Random rand = new Random(); private final Gson gson = new Gson(); private final Logger logger = LoggerFactory.getLogger(MieleGatewayCommunicationController.class); + private final HttpClient httpClient; - public MieleGatewayCommunicationController(String host) throws MalformedURLException { - url = new URL("http://" + host + "/remote/json-rpc"); + public MieleGatewayCommunicationController(HttpClient httpClient, String host) throws URISyntaxException { + uri = new URI("http://" + host + "/remote/json-rpc"); + this.httpClient = httpClient; } public JsonElement invokeOperation(FullyQualifiedApplianceIdentifier applianceIdentifier, String modelID, @@ -69,27 +69,43 @@ public class MieleGatewayCommunicationController { public JsonElement invokeRPC(String methodName, Object[] args) throws MieleRpcException { JsonElement result = null; - JsonObject req = new JsonObject(); + JsonObject requestBodyAsJson = new JsonObject(); int id = rand.nextInt(Integer.MAX_VALUE); - req.addProperty("jsonrpc", "2.0"); - req.addProperty("id", id); - req.addProperty("method", methodName); + requestBodyAsJson.addProperty("jsonrpc", "2.0"); + requestBodyAsJson.addProperty("id", id); + requestBodyAsJson.addProperty("method", methodName); JsonArray params = new JsonArray(); for (Object o : args) { params.add(gson.toJsonTree(o)); } - req.add("params", params); + requestBodyAsJson.add("params", params); + + String requestBody = requestBodyAsJson.toString(); + Request request = httpClient.newRequest(uri).method(HttpMethod.POST) + .content(new StringContentProvider(requestBody), "application/json"); - String requestData = req.toString(); String responseData = null; try { - responseData = post(url, Collections.emptyMap(), requestData); - } catch (IOException e) { - throw new MieleRpcException("Exception occurred while posting data", e); + final ContentResponse contentResponse = request.send(); + final int httpStatus = contentResponse.getStatus(); + if (httpStatus != 200) { + if (httpStatus == 503) { + throw new MieleRpcException("Gateway is temporarily unavailable"); + } + throw new MieleRpcException("Unexpected HTTP status code " + httpStatus); + } + responseData = contentResponse.getContentAsString(); + } catch (TimeoutException e) { + throw new MieleRpcException("Timeout when calling gateway", e); + } catch (ExecutionException e) { + throw new MieleRpcException("Failure when calling gateway", e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new MieleRpcException("Interrupted while calling gateway", e); } - logger.trace("The request '{}' yields '{}'", requestData, responseData); + logger.trace("The request '{}' yields '{}'", requestBody, responseData); JsonObject parsedResponse = null; try { parsedResponse = (JsonObject) JsonParser.parseReader(new StringReader(responseData)); @@ -107,7 +123,7 @@ public class MieleGatewayCommunicationController { String message = (o.has("message") ? o.get("message").getAsString() : null); String data = (o.has("data") ? (o.get("data") instanceof JsonObject ? o.get("data").toString() : o.get("data").getAsString()) - : null); + : ""); throw new MieleRpcException( "Remote exception occurred: '" + code + "':'" + message + "':'" + data + "'"); } else { @@ -122,63 +138,4 @@ public class MieleGatewayCommunicationController { return result; } - - private String post(URL url, Map headers, String data) throws IOException { - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - - for (Map.Entry entry : headers.entrySet()) { - connection.addRequestProperty(entry.getKey(), entry.getValue()); - } - - connection.addRequestProperty("Accept-Encoding", "gzip"); - connection.setRequestMethod("POST"); - connection.setDoOutput(true); - connection.connect(); - - OutputStream out = null; - - try { - out = connection.getOutputStream(); - - out.write(data.getBytes()); - out.flush(); - - int statusCode = connection.getResponseCode(); - if (statusCode != HttpURLConnection.HTTP_OK) { - logger.debug("An unexpected status code was returned: '{}'", statusCode); - } - } finally { - if (out != null) { - out.close(); - } - } - - String responseEncoding = connection.getHeaderField("Content-Encoding"); - responseEncoding = (responseEncoding == null ? "" : responseEncoding.trim()); - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - InputStream in = connection.getInputStream(); - try { - in = connection.getInputStream(); - if ("gzip".equalsIgnoreCase(responseEncoding)) { - in = new GZIPInputStream(in); - } - in = new BufferedInputStream(in); - - byte[] buff = new byte[1024]; - int n; - while ((n = in.read(buff)) > 0) { - bos.write(buff, 0, n); - } - bos.flush(); - bos.close(); - } finally { - if (in != null) { - in.close(); - } - } - - return bos.toString(); - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java index c80239886..7b3ab8979 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java @@ -23,6 +23,7 @@ import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; import org.openhab.binding.miele.internal.discovery.MieleApplianceDiscoveryService; import org.openhab.binding.miele.internal.handler.CoffeeMachineHandler; import org.openhab.binding.miele.internal.handler.DishWasherHandler; @@ -39,6 +40,7 @@ import org.openhab.core.config.core.Configuration; import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.i18n.LocaleProvider; import org.openhab.core.i18n.TranslationProvider; +import org.openhab.core.io.net.http.HttpClientFactory; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; @@ -57,6 +59,7 @@ import org.osgi.service.component.annotations.Reference; * handlers. * * @author Karel Goderis - Initial contribution + * @author Jacob Laursen - Refactored to use framework's HTTP client */ @NonNullByDefault @Component(service = ThingHandlerFactory.class, configurationPid = "binding.miele") @@ -67,14 +70,17 @@ public class MieleHandlerFactory extends BaseThingHandlerFactory { MieleApplianceHandler.SUPPORTED_THING_TYPES.stream()) .collect(Collectors.toSet()); + private final HttpClient httpClient; private final TranslationProvider i18nProvider; private final LocaleProvider localeProvider; private Map> discoveryServiceRegs = new HashMap<>(); @Activate - public MieleHandlerFactory(final @Reference TranslationProvider i18nProvider, - final @Reference LocaleProvider localeProvider, ComponentContext componentContext) { + public MieleHandlerFactory(@Reference final HttpClientFactory httpClientFactory, + final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider, + ComponentContext componentContext) { + this.httpClient = httpClientFactory.getCommonHttpClient(); this.i18nProvider = i18nProvider; this.localeProvider = localeProvider; } @@ -102,7 +108,7 @@ public class MieleHandlerFactory extends BaseThingHandlerFactory { @Override protected @Nullable ThingHandler createHandler(Thing thing) { if (MieleBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) { - MieleBridgeHandler handler = new MieleBridgeHandler((Bridge) thing); + MieleBridgeHandler handler = new MieleBridgeHandler((Bridge) thing, httpClient); registerApplianceDiscoveryService(handler); return handler; } else if (MieleApplianceHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) { diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java index 929c7339a..8a6551052 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java @@ -127,7 +127,7 @@ public abstract class MieleApplianceHandler & ApplianceChannel @Override public void initialize() { - logger.debug("Initializing Miele appliance handler."); + logger.debug("Initializing handler for thing {}", getThing().getUID()); final String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID); if (applianceId == null || applianceId.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java index cf385ed7b..bb14464e4 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java @@ -17,9 +17,9 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; -import java.net.MalformedURLException; import java.net.MulticastSocket; import java.net.SocketTimeoutException; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.IllformedLocaleException; @@ -39,6 +39,7 @@ import java.util.regex.Pattern; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier; import org.openhab.binding.miele.internal.MieleGatewayCommunicationController; import org.openhab.binding.miele.internal.api.dto.DeviceClassObject; @@ -87,7 +88,8 @@ public class MieleBridgeHandler extends BaseBridgeHandler { private boolean lastBridgeConnectionState = false; - private Gson gson = new Gson(); + private final HttpClient httpClient; + private final Gson gson = new Gson(); private @NonNullByDefault({}) MieleGatewayCommunicationController gatewayCommunication; private Set discoveryListeners = ConcurrentHashMap.newKeySet(); @@ -99,21 +101,22 @@ public class MieleBridgeHandler extends BaseBridgeHandler { private Map cachedHomeDevicesByApplianceId = new ConcurrentHashMap<>(); private Map cachedHomeDevicesByRemoteUid = new ConcurrentHashMap<>(); - public MieleBridgeHandler(Bridge bridge) { + public MieleBridgeHandler(Bridge bridge, HttpClient httpClient) { super(bridge); + this.httpClient = httpClient; } @Override public void initialize() { - logger.debug("Initializing the Miele bridge handler."); + logger.debug("Initializing handler for bridge {}", getThing().getUID()); if (!validateConfig(getConfig())) { return; } try { - gatewayCommunication = new MieleGatewayCommunicationController((String) getConfig().get(HOST)); - } catch (MalformedURLException e) { + gatewayCommunication = new MieleGatewayCommunicationController(httpClient, (String) getConfig().get(HOST)); + } catch (URISyntaxException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage()); return; }