From 578807f452eb869b6e568ec82524a0d245deb248 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Fri, 11 Dec 2020 23:48:00 +0100 Subject: [PATCH] [remoteopenhab] Asynchronous reading of big API response (#9320) * [remoteopenhab] Asynchronous reading of big API response Fix #9281 Signed-off-by: Laurent Garnier --- .../handler/RemoteopenhabBridgeHandler.java | 12 +--- .../rest/RemoteopenhabRestClient.java | 57 ++++++++++++++----- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java index 06040dfaf..97dfbd957 100644 --- a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java +++ b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java @@ -331,18 +331,12 @@ public class RemoteopenhabBridgeHandler extends BaseBridgeHandler updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "OH 1.x server not supported by the binding"); } else if (getThing().getStatus() != ThingStatus.ONLINE) { - List items = restClient.getRemoteItems("name,type,groupType,stateDescription"); + List items = restClient.getRemoteItems("name,type,groupType,state,stateDescription"); createChannels(items, true); setStateOptions(items); - - try { - items = restClient.getRemoteItems("name,state"); - for (RemoteopenhabItem item : items) { - updateChannelState(item.name, null, item.state, false); - } - } catch (RemoteopenhabException e) { - logger.debug("{}", e.getMessage()); + for (RemoteopenhabItem item : items) { + updateChannelState(item.name, null, item.state, false); } updateStatus(ThingStatus.ONLINE); diff --git a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java index fc6e4a5de..fab3d7cf3 100644 --- a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java +++ b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java @@ -13,6 +13,7 @@ package org.openhab.binding.remoteopenhab.internal.rest; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -37,7 +38,9 @@ import org.eclipse.jdt.annotation.Nullable; 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.api.Response; import org.eclipse.jetty.client.util.InputStreamContentProvider; +import org.eclipse.jetty.client.util.InputStreamResponseListener; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.openhab.binding.remoteopenhab.internal.data.RemoteopenhabChannelTriggerEvent; @@ -128,7 +131,7 @@ public class RemoteopenhabRestClient { public void tryApi() throws RemoteopenhabException { try { - String jsonResponse = executeUrl(HttpMethod.GET, getRestUrl(), "application/json", null, null); + String jsonResponse = executeGetUrl(getRestUrl(), "application/json", false); if (jsonResponse.isEmpty()) { throw new RemoteopenhabException("JSON response is empty"); } @@ -155,7 +158,8 @@ public class RemoteopenhabRestClient { if (fields != null) { url += "&fields=" + fields; } - String jsonResponse = executeUrl(HttpMethod.GET, url, "application/json", null, null); + boolean asyncReading = fields == null || Arrays.asList(fields.split(",")).contains("state"); + String jsonResponse = executeGetUrl(url, "application/json", asyncReading); if (jsonResponse.isEmpty()) { throw new RemoteopenhabException("JSON response is empty"); } @@ -169,7 +173,7 @@ public class RemoteopenhabRestClient { public String getRemoteItemState(String itemName) throws RemoteopenhabException { try { String url = String.format("%s/%s/state", getRestApiUrl("items"), itemName); - return executeUrl(HttpMethod.GET, url, "text/plain", null, null); + return executeGetUrl(url, "text/plain", true); } catch (RemoteopenhabException e) { throw new RemoteopenhabException("Failed to get the state of remote item " + itemName + " using the items REST API: " + e.getMessage(), e); @@ -180,7 +184,7 @@ public class RemoteopenhabRestClient { try { String url = String.format("%s/%s", getRestApiUrl("items"), itemName); InputStream stream = new ByteArrayInputStream(command.toFullString().getBytes(StandardCharsets.UTF_8)); - executeUrl(HttpMethod.POST, url, "application/json", stream, "text/plain"); + executeUrl(HttpMethod.POST, url, "application/json", stream, "text/plain", false); stream.close(); } catch (RemoteopenhabException | IOException e) { throw new RemoteopenhabException("Failed to send command to the remote item " + itemName @@ -190,7 +194,7 @@ public class RemoteopenhabRestClient { public List getRemoteThings() throws RemoteopenhabException { try { - String jsonResponse = executeUrl(HttpMethod.GET, getRestApiUrl("things"), "application/json", null, null); + String jsonResponse = executeGetUrl(getRestApiUrl("things"), "application/json", false); if (jsonResponse.isEmpty()) { throw new RemoteopenhabException("JSON response is empty"); } @@ -204,7 +208,7 @@ public class RemoteopenhabRestClient { public RemoteopenhabThing getRemoteThing(String uid) throws RemoteopenhabException { try { String url = String.format("%s/%s", getRestApiUrl("things"), uid); - String jsonResponse = executeUrl(HttpMethod.GET, url, "application/json", null, null); + String jsonResponse = executeGetUrl(url, "application/json", false); if (jsonResponse.isEmpty()) { throw new RemoteopenhabException("JSON response is empty"); } @@ -462,8 +466,12 @@ public class RemoteopenhabRestClient { return parts[2]; } + public String executeGetUrl(String url, String acceptHeader, boolean asyncReading) throws RemoteopenhabException { + return executeUrl(HttpMethod.GET, url, acceptHeader, null, null, asyncReading); + } + public String executeUrl(HttpMethod httpMethod, String url, String acceptHeader, @Nullable InputStream content, - @Nullable String contentType) throws RemoteopenhabException { + @Nullable String contentType, boolean asyncReading) throws RemoteopenhabException { final Request request = httpClient.newRequest(url).method(httpMethod).timeout(REQUEST_TIMEOUT, TimeUnit.MILLISECONDS); @@ -481,15 +489,34 @@ public class RemoteopenhabRestClient { } try { - ContentResponse response = request.send(); - int statusCode = response.getStatus(); - if (statusCode >= HttpStatus.BAD_REQUEST_400) { - String statusLine = statusCode + " " + response.getReason(); - throw new RemoteopenhabException("HTTP call failed: " + statusLine); + if (asyncReading) { + InputStreamResponseListener listener = new InputStreamResponseListener(); + request.send(listener); + Response response = listener.get(5, TimeUnit.SECONDS); + int statusCode = response.getStatus(); + if (statusCode != HttpStatus.OK_200) { + response.abort(new Exception(response.getReason())); + String statusLine = statusCode + " " + response.getReason(); + throw new RemoteopenhabException("HTTP call failed: " + statusLine); + } + ByteArrayOutputStream responseContent = new ByteArrayOutputStream(); + try (InputStream input = listener.getInputStream()) { + input.transferTo(responseContent); + } + return new String(responseContent.toByteArray(), StandardCharsets.UTF_8.name()); + } else { + ContentResponse response = request.send(); + int statusCode = response.getStatus(); + if (statusCode >= HttpStatus.BAD_REQUEST_400) { + String statusLine = statusCode + " " + response.getReason(); + throw new RemoteopenhabException("HTTP call failed: " + statusLine); + } + String encoding = response.getEncoding() != null ? response.getEncoding().replaceAll("\"", "").trim() + : StandardCharsets.UTF_8.name(); + return new String(response.getContent(), encoding); } - String encoding = response.getEncoding() != null ? response.getEncoding().replaceAll("\"", "").trim() - : StandardCharsets.UTF_8.name(); - return new String(response.getContent(), encoding); + } catch (RemoteopenhabException e) { + throw e; } catch (Exception e) { throw new RemoteopenhabException(e); }