]> git.basschouten.com Git - openhab-addons.git/commitdiff
[bindings a-c] Fix exception handling (Jetty HTTP client) (#10467)
authorlolodomo <lg.hc@free.fr>
Tue, 6 Apr 2021 15:30:12 +0000 (17:30 +0200)
committerGitHub <noreply@github.com>
Tue, 6 Apr 2021 15:30:12 +0000 (17:30 +0200)
Signed-off-by: Laurent Garnier <lg.hc@free.fr>
bundles/org.openhab.binding.autelis/src/main/java/org/openhab/binding/autelis/internal/handler/AutelisHandler.java
bundles/org.openhab.binding.automower/src/main/java/org/openhab/binding/automower/internal/rest/api/automowerconnect/AutomowerConnectApi.java
bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/FritzAhaWebInterface.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandler.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/bridge/BoschSHCBridgeHandler.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/bridge/LongPolling.java

index 3669f87a56ed1e594f3039d3cdb20c9f7b9cc728..0766da21fc19cdbe12e81c5a9f47000786e40782 100644 (file)
@@ -18,8 +18,10 @@ import java.util.Base64;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -190,88 +192,94 @@ public class AutelisHandler extends BaseThingHandler {
 
     @Override
     public void handleCommand(ChannelUID channelUID, Command command) {
-        logger.debug("handleCommand channel: {} command: {}", channelUID.getId(), command);
-        if (AutelisBindingConstants.CMD_LIGHTS.equals(channelUID.getId())) {
-            /*
-             * lighting command possible values, but we will let anything
-             * through. alloff, allon, csync, cset, cswim, party, romance,
-             * caribbean, american, sunset, royalty, blue, green, red, white,
-             * magenta, hold, recall
-             */
-            getUrl(baseURL + "/lights.cgi?val=" + command.toString(), TIMEOUT_SECONDS);
-        } else if (AutelisBindingConstants.CMD_REBOOT.equals(channelUID.getId()) && command == OnOffType.ON) {
-            getUrl(baseURL + "/userreboot.cgi?do=true" + command.toString(), TIMEOUT_SECONDS);
-            updateState(channelUID, OnOffType.OFF);
-        } else {
-            String[] args = channelUID.getId().split("-");
-            if (args.length < 2) {
-                logger.warn("Unown channel {} for command {}", channelUID, command);
-                return;
-            }
-            String type = args[0];
-            String name = args[1];
-
-            if (AutelisBindingConstants.CMD_EQUIPMENT.equals(type)) {
-                String cmd = "value";
-                int value;
-                if (command == OnOffType.OFF) {
-                    value = 0;
-                } else if (command == OnOffType.ON) {
-                    value = 1;
-                } else if (command instanceof DecimalType) {
-                    value = ((DecimalType) command).intValue();
-                    if (!isJandy() && value >= 3) {
-                        // this is a autelis dim type. not sure what 2 does
-                        cmd = "dim";
-                    }
-                } else {
-                    logger.error("command type {} is not supported", command);
+        try {
+            logger.debug("handleCommand channel: {} command: {}", channelUID.getId(), command);
+            if (AutelisBindingConstants.CMD_LIGHTS.equals(channelUID.getId())) {
+                /*
+                 * lighting command possible values, but we will let anything
+                 * through. alloff, allon, csync, cset, cswim, party, romance,
+                 * caribbean, american, sunset, royalty, blue, green, red, white,
+                 * magenta, hold, recall
+                 */
+                getUrl(baseURL + "/lights.cgi?val=" + command.toString(), TIMEOUT_SECONDS);
+            } else if (AutelisBindingConstants.CMD_REBOOT.equals(channelUID.getId()) && command == OnOffType.ON) {
+                getUrl(baseURL + "/userreboot.cgi?do=true" + command.toString(), TIMEOUT_SECONDS);
+                updateState(channelUID, OnOffType.OFF);
+            } else {
+                String[] args = channelUID.getId().split("-");
+                if (args.length < 2) {
+                    logger.warn("Unown channel {} for command {}", channelUID, command);
                     return;
                 }
-                String response = getUrl(baseURL + "/set.cgi?name=" + name + "&" + cmd + "=" + value, TIMEOUT_SECONDS);
-                logger.debug("equipment set {} {} {} : result {}", name, cmd, value, response);
-            } else if (AutelisBindingConstants.CMD_TEMP.equals(type)) {
-                String value;
-                if (command == IncreaseDecreaseType.INCREASE) {
-                    value = "up";
-                } else if (command == IncreaseDecreaseType.DECREASE) {
-                    value = "down";
-                } else if (command == OnOffType.OFF) {
-                    value = "0";
-                } else if (command == OnOffType.ON) {
-                    value = "1";
-                } else {
-                    value = command.toString();
-                }
+                String type = args[0];
+                String name = args[1];
+
+                if (AutelisBindingConstants.CMD_EQUIPMENT.equals(type)) {
+                    String cmd = "value";
+                    int value;
+                    if (command == OnOffType.OFF) {
+                        value = 0;
+                    } else if (command == OnOffType.ON) {
+                        value = 1;
+                    } else if (command instanceof DecimalType) {
+                        value = ((DecimalType) command).intValue();
+                        if (!isJandy() && value >= 3) {
+                            // this is a autelis dim type. not sure what 2 does
+                            cmd = "dim";
+                        }
+                    } else {
+                        logger.error("command type {} is not supported", command);
+                        return;
+                    }
+                    String response = getUrl(baseURL + "/set.cgi?name=" + name + "&" + cmd + "=" + value,
+                            TIMEOUT_SECONDS);
+                    logger.debug("equipment set {} {} {} : result {}", name, cmd, value, response);
+                } else if (AutelisBindingConstants.CMD_TEMP.equals(type)) {
+                    String value;
+                    if (command == IncreaseDecreaseType.INCREASE) {
+                        value = "up";
+                    } else if (command == IncreaseDecreaseType.DECREASE) {
+                        value = "down";
+                    } else if (command == OnOffType.OFF) {
+                        value = "0";
+                    } else if (command == OnOffType.ON) {
+                        value = "1";
+                    } else {
+                        value = command.toString();
+                    }
 
-                String cmd;
-                // name ending in sp are setpoints, ht are heater?
-                if (name.endsWith("sp")) {
-                    cmd = "temp";
-                } else if (name.endsWith("ht")) {
-                    cmd = "hval";
+                    String cmd;
+                    // name ending in sp are setpoints, ht are heater?
+                    if (name.endsWith("sp")) {
+                        cmd = "temp";
+                    } else if (name.endsWith("ht")) {
+                        cmd = "hval";
+                    } else {
+                        logger.error("Unknown temp type {}", name);
+                        return;
+                    }
+                    String response = getUrl(baseURL + "/set.cgi?wait=1&name=" + name + "&" + cmd + "=" + value,
+                            TIMEOUT_SECONDS);
+                    logger.debug("temp set name:{} cmd:{} value:{} : result {}", name, cmd, value, response);
+                } else if (AutelisBindingConstants.CMD_CHEM.equals(type)) {
+                    String response = getUrl(baseURL + "/set.cgi?name=" + name + "&chem=" + command.toString(),
+                            TIMEOUT_SECONDS);
+                    logger.debug("chlrp {} {}: result {}", name, command, response);
+                } else if (AutelisBindingConstants.CMD_PUMPS.equals(type)) {
+                    String response = getUrl(baseURL + "/set.cgi?name=" + name + "&speed=" + command.toString(),
+                            TIMEOUT_SECONDS);
+                    logger.debug("pumps {} {}: result {}", name, command, response);
                 } else {
-                    logger.error("Unknown temp type {}", name);
-                    return;
+                    logger.error("Unsupported type {}", type);
                 }
-                String response = getUrl(baseURL + "/set.cgi?wait=1&name=" + name + "&" + cmd + "=" + value,
-                        TIMEOUT_SECONDS);
-                logger.debug("temp set name:{} cmd:{} value:{} : result {}", name, cmd, value, response);
-            } else if (AutelisBindingConstants.CMD_CHEM.equals(type)) {
-                String response = getUrl(baseURL + "/set.cgi?name=" + name + "&chem=" + command.toString(),
-                        TIMEOUT_SECONDS);
-                logger.debug("chlrp {} {}: result {}", name, command, response);
-            } else if (AutelisBindingConstants.CMD_PUMPS.equals(type)) {
-                String response = getUrl(baseURL + "/set.cgi?name=" + name + "&speed=" + command.toString(),
-                        TIMEOUT_SECONDS);
-                logger.debug("pumps {} {}: result {}", name, command, response);
-            } else {
-                logger.error("Unsupported type {}", type);
             }
+            clearState(true);
+            // reset the schedule for our next poll which at that time will reflect if our command was successful or
+            // not.
+            initPolling(COMMAND_UPDATE_TIME_SECONDS);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
         }
-        clearState(true);
-        // reset the schedule for our next poll which at that time will reflect if our command was successful or not.
-        initPolling(COMMAND_UPDATE_TIME_SECONDS);
     }
 
     /**
@@ -349,7 +357,7 @@ public class AutelisHandler extends BaseThingHandler {
      * Poll the Autelis controller for updates. This will retrieve various xml documents and update channel states from
      * its contents.
      */
-    private void pollAutelisController() {
+    private void pollAutelisController() throws InterruptedException {
         logger.trace("Connecting to {}", baseURL);
 
         // clear our cached stated IF it is time.
@@ -466,16 +474,13 @@ public class AutelisHandler extends BaseThingHandler {
      * @param timeout
      * @return
      */
-    private synchronized String getUrl(String url, int timeout) {
+    private synchronized String getUrl(String url, int timeout) throws InterruptedException {
         // throttle commands for a very short time to avoid 'loosing' them
         long now = System.currentTimeMillis();
         long nextReq = lastRequestTime + THROTTLE_TIME_MILLISECONDS;
         if (nextReq > now) {
-            try {
-                logger.trace("Throttling request for {} mills", nextReq - now);
-                Thread.sleep(nextReq - now);
-            } catch (InterruptedException ignored) {
-            }
+            logger.trace("Throttling request for {} mills", nextReq - now);
+            Thread.sleep(nextReq - now);
         }
         String getURL = url + (url.contains("?") ? "&" : "?") + "timestamp=" + System.currentTimeMillis();
         logger.trace("Getting URL {} ", getURL);
@@ -490,7 +495,7 @@ public class AutelisHandler extends BaseThingHandler {
             }
             lastRequestTime = System.currentTimeMillis();
             return response.getContentAsString();
-        } catch (Exception e) {
+        } catch (ExecutionException | TimeoutException e) {
             logger.debug("Could not make http connection", e);
         }
         return null;
index 98522a5d7665582ebbc2d9d2692e219e23db5137..64b00eab08959441953559dd43a4a3a1b9756ded 100644 (file)
@@ -90,7 +90,10 @@ public class AutomowerConnectApi extends HusqvarnaApi {
         ContentResponse response;
         try {
             response = request.send();
-        } catch (InterruptedException | TimeoutException | ExecutionException e) {
+        } catch (TimeoutException | ExecutionException e) {
+            throw new AutomowerCommunicationException(e);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
             throw new AutomowerCommunicationException(e);
         }
         return response;
index cb298b542a8a076eda5745424c50276f61e41644..8eb2854acb8ac3c400eed53634697e38095d662c 100644 (file)
@@ -242,9 +242,13 @@ public class FritzAhaWebInterface {
             String content = contentResponse.getContentAsString();
             logger.debug("GET response complete: {}", content);
             return content;
-        } catch (ExecutionException | InterruptedException | TimeoutException e) {
+        } catch (ExecutionException | TimeoutException e) {
             logger.debug("response failed: {}", e.getLocalizedMessage(), e);
             return null;
+        } catch (InterruptedException e) {
+            logger.debug("response interrupted: {}", e.getLocalizedMessage(), e);
+            Thread.currentThread().interrupt();
+            return null;
         }
     }
 
index a683a1f5da40a5ff7ab25194ed48bdf6745f859a..98e6d856effb064249f69ec1a86b4d637d088591 100644 (file)
@@ -56,7 +56,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
     class DeviceService<TState extends BoschSHCServiceState> {
         /**
          * Constructor.
-         * 
+         *
          * @param service Service which belongs to the device.
          * @param affectedChannels Channels which are affected by the state of this service.
          */
@@ -99,7 +99,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
 
     /**
      * Returns the unique id of the Bosch device.
-     * 
+     *
      * @return Unique id of the Bosch device.
      */
     public @Nullable String getBoschID() {
@@ -132,7 +132,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
     /**
      * Handles the refresh command of all registered services. Override it to handle custom commands (e.g. to update
      * states of services).
-     * 
+     *
      * @param channelUID {@link ChannelUID} of the channel to which the command was sent
      * @param command {@link Command}
      */
@@ -144,10 +144,15 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
                 if (deviceService.affectedChannels.contains(channelUID.getIdWithoutGroup())) {
                     try {
                         deviceService.service.refreshState();
-                    } catch (InterruptedException | TimeoutException | ExecutionException | BoschSHCException e) {
+                    } catch (TimeoutException | ExecutionException | BoschSHCException e) {
                         this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
                                 String.format("Error when trying to refresh state from service %s: %s",
                                         deviceService.service.getServiceName(), e.getMessage()));
+                    } catch (InterruptedException e) {
+                        this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
+                                String.format("Interrupted refresh state from service %s: %s",
+                                        deviceService.service.getServiceName(), e.getMessage()));
+                        Thread.currentThread().interrupt();
                     }
                 }
             }
@@ -156,7 +161,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
 
     /**
      * Processes an update which is received from the bridge.
-     * 
+     *
      * @param serviceName Name of service the update came from.
      * @param stateData Current state of device service. Serialized as JSON.
      */
@@ -178,7 +183,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
 
     /**
      * Returns the bridge handler for this thing handler.
-     * 
+     *
      * @return Bridge handler for this thing handler. Null if no or an invalid bridge was set in the configuration.
      * @throws BoschSHCException If bridge for handler is not set or an invalid bridge is set.
      */
@@ -196,7 +201,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
 
     /**
      * Query the Bosch Smart Home Controller for the state of the service with the specified name.
-     * 
+     *
      * @note Use services instead of directly requesting a state.
      *
      * @param stateName Name of the service to query
@@ -210,16 +215,21 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
         try {
             BoschSHCBridgeHandler bridgeHandler = this.getBridgeHandler();
             return bridgeHandler.getState(deviceId, stateName, classOfT);
-        } catch (InterruptedException | TimeoutException | ExecutionException | BoschSHCException e) {
+        } catch (TimeoutException | ExecutionException | BoschSHCException e) {
             this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
                     String.format("Error when trying to refresh state from service %s: %s", stateName, e.getMessage()));
             return null;
+        } catch (InterruptedException e) {
+            this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
+                    String.format("Interrupted refresh state from service %s: %s", stateName, e.getMessage()));
+            Thread.currentThread().interrupt();
+            return null;
         }
     }
 
     /**
      * Creates and registers a new service for this device.
-     * 
+     *
      * @param <TService> Type of service.
      * @param <TState> Type of service state.
      * @param newService Supplier function to create a new instance of the service.
@@ -240,7 +250,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
 
     /**
      * Registers a service for this device.
-     * 
+     *
      * @param <TService> Type of service.
      * @param <TState> Type of service state.
      * @param service Service to register.
@@ -269,7 +279,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
     /**
      * Updates the state of a device service.
      * Sets the status of the device to offline if setting the state fails.
-     * 
+     *
      * @param <TService> Type of service.
      * @param <TState> Type of service state.
      * @param service Service to set state for.
@@ -279,15 +289,19 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
             TService service, TState state) {
         try {
             service.setState(state);
-        } catch (InterruptedException | TimeoutException | ExecutionException e) {
+        } catch (TimeoutException | ExecutionException e) {
             this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, String.format(
                     "Error when trying to update state for service %s: %s", service.getServiceName(), e.getMessage()));
+        } catch (InterruptedException e) {
+            this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, String
+                    .format("Interrupted update state for service %s: %s", service.getServiceName(), e.getMessage()));
+            Thread.currentThread().interrupt();
         }
     }
 
     /**
      * Registers a service of this device.
-     * 
+     *
      * @param service Service which belongs to this device
      * @param affectedChannels Channels which are affected by the state of this
      *            service
index aa1a96e21f564ed1548d09876279d7e81110bcda..c575d7586d456217d7118c6c29afc946d7be2d88 100644 (file)
@@ -12,8 +12,7 @@
  */
 package org.openhab.binding.boschshc.internal.devices.bridge;
 
-import static org.eclipse.jetty.http.HttpMethod.GET;
-import static org.eclipse.jetty.http.HttpMethod.PUT;
+import static org.eclipse.jetty.http.HttpMethod.*;
 
 import java.lang.reflect.Type;
 import java.util.ArrayList;
@@ -30,7 +29,10 @@ import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.openhab.binding.boschshc.internal.devices.BoschSHCHandler;
-import org.openhab.binding.boschshc.internal.devices.bridge.dto.*;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceStatusUpdate;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.LongPollResult;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.Room;
 import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
 import org.openhab.binding.boschshc.internal.exceptions.LongPollingFailedException;
 import org.openhab.binding.boschshc.internal.exceptions.PairingFailedException;
@@ -233,12 +235,13 @@ public class BoschSHCBridgeHandler extends BaseBridgeHandler {
 
         } catch (InterruptedException e) {
             this.updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.UNKNOWN.NONE, "@text/offline.interrupted");
+            Thread.currentThread().interrupt();
         }
     }
 
     /**
      * Get a list of connected devices from the Smart-Home Controller
-     * 
+     *
      * @throws InterruptedException in case bridge is stopped
      */
     private boolean getDevices() throws InterruptedException {
@@ -354,7 +357,7 @@ public class BoschSHCBridgeHandler extends BaseBridgeHandler {
 
     /**
      * Get a list of rooms from the Smart-Home controller
-     * 
+     *
      * @throws InterruptedException in case bridge is stopped
      */
     private boolean getRooms() throws InterruptedException {
@@ -451,11 +454,11 @@ public class BoschSHCBridgeHandler extends BaseBridgeHandler {
 
     /**
      * Sends a state change for a device to the controller
-     * 
+     *
      * @param deviceId Id of device to change state for
      * @param serviceName Name of service of device to change state for
      * @param state New state data to set for service
-     * 
+     *
      * @return Response of request
      * @throws InterruptedException
      * @throws ExecutionException
index 96a402251c4a97d6aa2ca7830f98a5bfb0080bf6..9b7b254493eb360c9d41f00c5d999273b408d903 100644 (file)
@@ -37,7 +37,7 @@ import com.google.gson.Gson;
 
 /**
  * Handles the long polling to the Smart Home Controller.
- * 
+ *
  * @author Christian Oeing - Initial contribution
  */
 @NonNullByDefault
@@ -100,7 +100,7 @@ public class LongPolling {
 
     /**
      * Subscribe to events and store the subscription ID needed for long polling.
-     * 
+     *
      * @param httpClient Http client to use for sending subscription request
      * @return Subscription id
      */
@@ -116,16 +116,21 @@ public class LongPolling {
             logger.debug("Subscribe: Got subscription ID: {} {}", response.getResult(), response.getJsonrpc());
             String subscriptionId = response.getResult();
             return subscriptionId;
-        } catch (TimeoutException | ExecutionException | InterruptedException e) {
+        } catch (TimeoutException | ExecutionException e) {
             throw new LongPollingFailedException(
                     String.format("Error on subscribe (Http client: %s): %s", httpClient.toString(), e.getMessage()),
                     e);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new LongPollingFailedException(
+                    String.format("Interrupted subscribe (Http client: %s): %s", httpClient.toString(), e.getMessage()),
+                    e);
         }
     }
 
     /**
      * Create a new subscription for long polling.
-     * 
+     *
      * @param httpClient Http client to send requests to
      */
     private void resubscribe(BoschHttpClient httpClient) {
@@ -171,7 +176,7 @@ public class LongPolling {
 
     /**
      * This is the handler for responses of long poll requests.
-     * 
+     *
      * @param httpClient HTTP client which received the response
      * @param subscriptionId Id of subscription the response is for
      * @param result Complete result of the response