[miele] Use framework's HTTP client (#12545)
* 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>
This commit is contained in:
parent
a2a5c2e6ff
commit
8c6534300a
@ -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<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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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())) {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user