]> git.basschouten.com Git - openhab-addons.git/commitdiff
[miele] Use framework's HTTP client (#12545)
authorJacob Laursen <jacob-github@vindvejr.dk>
Wed, 30 Mar 2022 05:03:46 +0000 (07:03 +0200)
committerGitHub <noreply@github.com>
Wed, 30 Mar 2022 05:03:46 +0000 (07:03 +0200)
* Refactor to use framework's Jetty HTTP client
* Do not try to parse HTML as JSON on failed HTTP calls
* Improve handler initialization log messages

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleGatewayCommunicationController.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java

index 58f5363b3d1058b4e9a3ea1c4178e5db0c2afb72..566f4627f52e6b71899d052d68c0d83e95226c85 100644 (file)
  */
 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<String, String> headers, String data) throws IOException {
-        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-
-        for (Map.Entry<String, String> 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();
-    }
 }
index c802398866cb2947bb88a74696cb5eb8d1f65215..7b3ab897947dc3ecd221f65106d3cc9d48e94b6e 100644 (file)
@@ -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<ThingUID, ServiceRegistration<?>> 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())) {
index 929c7339a57cce9f39e5ddf7151d9285f797a254..8a655105269a88e275ba292131d30cf3c9e21c19 100644 (file)
@@ -127,7 +127,7 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & 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,
index cf385ed7b0d7567eee5b1837f385e8550f6d74a7..bb14464e4295a372298af760c52a6175148f6909 100644 (file)
@@ -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<DiscoveryListener> discoveryListeners = ConcurrentHashMap.newKeySet();
@@ -99,21 +101,22 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
     private Map<String, HomeDevice> cachedHomeDevicesByApplianceId = new ConcurrentHashMap<>();
     private Map<String, HomeDevice> 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;
         }