diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java index 686ecd6a5377e..12ba5584119b3 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java @@ -51,7 +51,7 @@ */ public abstract class RpcClient { private final Logger logger = LoggerFactory.getLogger(RpcClient.class); - protected static final int MAX_RPC_RETRY = 1; + protected static final int MAX_RPC_RETRY = 3; protected static final int RESP_BUFFER_SIZE = 8192; protected HomematicConfig config; diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java index 5aa5d1cd08793..82ece040f30a8 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java @@ -16,9 +16,15 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.xml.parsers.ParserConfigurationException; import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.util.BytesContentProvider; import org.eclipse.jetty.client.util.InputStreamResponseListener; @@ -31,6 +37,7 @@ import org.openhab.binding.homematic.internal.communicator.parser.RpcResponseParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; /** * Client implementation for sending messages via XML-RPC to the Homematic server. @@ -68,14 +75,30 @@ protected synchronized Object[] sendMessage(int port, RpcRequest request if (logger.isTraceEnabled()) { logger.trace("Client XmlRpcRequest (port {}):\n{}", port, request); } - return sendMessage(port, request, 0); + IOException reason = new IOException(); + for (int rpcRetryCounter = 1; rpcRetryCounter <= MAX_RPC_RETRY; rpcRetryCounter++) { + try { + byte[] response = send(port, request); + Object[] data = new XmlRpcResponse(new ByteArrayInputStream(response), config.getEncoding()) + .getResponseData(); + return new RpcResponseParser(request).parse(data); + } catch (UnknownRpcFailureException | UnknownParameterSetException ex) { + throw ex; + } catch (SAXException | ParserConfigurationException ex) { + throw new IOException(ex); + } catch (IOException ex) { + reason = ex; + if ("init".equals(request.getMethodName())) { // no retries for "init" request + break; + } + logger.debug("XmlRpcMessage failed, sending message again {}/{}", rpcRetryCounter, MAX_RPC_RETRY); + } + } + throw reason; } - /** - * Sends the message, retries if there was an error. - */ - private synchronized Object[] sendMessage(int port, RpcRequest request, int rpcRetryCounter) - throws IOException { + private byte[] send(int port, RpcRequest request) throws IOException { + byte[] ret = new byte[0]; try { BytesContentProvider content = new BytesContentProvider( request.createMessage().getBytes(config.getEncoding())); @@ -83,42 +106,43 @@ private synchronized Object[] sendMessage(int port, RpcRequest request, if (port == config.getGroupPort()) { url += "/groups"; } - InputStreamResponseListener respListener = new InputStreamResponseListener(); - httpClient.POST(url).content(content) - .header(HttpHeader.CONTENT_TYPE, "text/xml;charset=" + config.getEncoding()).send(respListener); - Response resp = respListener.get(config.getTimeout(), TimeUnit.SECONDS); - ByteArrayOutputStream respData = new ByteArrayOutputStream(RESP_BUFFER_SIZE); - int httpStatus = resp.getStatus(); - if (httpStatus == HttpStatus.OK_200) { - byte[] recvBuffer = new byte[RESP_BUFFER_SIZE]; - InputStream input = respListener.getInputStream(); - while (true) { - int read = input.read(recvBuffer); - if (read == -1) { - break; + Request req = httpClient.POST(url).content(content).timeout(config.getTimeout(), TimeUnit.SECONDS) + .header(HttpHeader.CONTENT_TYPE, "text/xml;charset=" + config.getEncoding()); + try { + ret = req.send().getContent(); + } catch (IllegalArgumentException e) { // Returned buffer too large + logger.info("Blocking XmlRpcRequest failed: {}, trying non-blocking request", e.getMessage()); + InputStreamResponseListener respListener = new InputStreamResponseListener(); + req.send(respListener); + Response resp = respListener.get(config.getTimeout(), TimeUnit.SECONDS); + ByteArrayOutputStream respData = new ByteArrayOutputStream(RESP_BUFFER_SIZE); + + int httpStatus = resp.getStatus(); + if (httpStatus == HttpStatus.OK_200) { + byte[] recvBuffer = new byte[RESP_BUFFER_SIZE]; + try (InputStream input = respListener.getInputStream()) { + while (true) { + int read = input.read(recvBuffer); + if (read == -1) { + break; + } + respData.write(recvBuffer, 0, read); + } + ret = respData.toByteArray(); } - respData.write(recvBuffer, 0, read); + } else { + logger.warn("Non-blocking XmlRpcRequest failed, status code: {} / request: {}", httpStatus, + request); + resp.abort(new IOException()); } - } else { - logger.warn("XmlRpcRequest failure, status code: {} / request was: {}", httpStatus, request); - resp.abort(new Exception()); } if (logger.isTraceEnabled()) { - logger.trace("Client XmlRpcResponse: (port {}):\n{}", port, respData.toString(config.getEncoding())); - } - Object[] data = new XmlRpcResponse(new ByteArrayInputStream(respData.toByteArray()), config.getEncoding()) - .getResponseData(); - return new RpcResponseParser(request).parse(data); - } catch (UnknownRpcFailureException | UnknownParameterSetException ex) { - throw ex; - } catch (Exception ex) { - if ("init".equals(request.getMethodName()) || rpcRetryCounter >= MAX_RPC_RETRY) { - throw new IOException(ex.getMessage(), ex); - } else { - rpcRetryCounter++; - logger.debug("XmlRpcMessage failure, sending message again {}/{}", rpcRetryCounter, MAX_RPC_RETRY); - return sendMessage(port, request, rpcRetryCounter); + String result = new String(ret, config.getEncoding()); + logger.trace("Client XmlRpcResponse (port {}):\n{}", port, result); } + } catch (UnsupportedEncodingException | ExecutionException | TimeoutException | InterruptedException e) { + throw new IOException(e); } + return ret; } }