]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hdpowerview] Refactor exception handling (#12049)
authorJacob Laursen <jacob-github@vindvejr.dk>
Sat, 15 Jan 2022 18:16:09 +0000 (19:16 +0100)
committerGitHub <noreply@github.com>
Sat, 15 Jan 2022 18:16:09 +0000 (19:16 +0100)
* Refactor exception handling.

Fixes #12048

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
13 files changed:
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HubMaintenanceException.java [deleted file]
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HubProcessingException.java [deleted file]
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/SurveyData.java [new file with mode: 0644]
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Survey.java
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/HDPowerViewShadeDiscoveryService.java
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubException.java [new file with mode: 0644]
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubInvalidResponseException.java [new file with mode: 0644]
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubMaintenanceException.java [new file with mode: 0644]
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubProcessingException.java [new file with mode: 0644]
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java
bundles/org.openhab.binding.hdpowerview/src/test/java/org/openhab/binding/hdpowerview/HDPowerViewJUnitTests.java

index deabb7fb7778abcfe67c0739fb235c37de59fe24..344dc6ab1e485337a5dcea92c7b1957801762df2 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.hdpowerview.internal;
 
 import java.time.Instant;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
@@ -32,15 +33,23 @@ import org.openhab.binding.hdpowerview.internal.api.requests.ShadeStop;
 import org.openhab.binding.hdpowerview.internal.api.responses.FirmwareVersion;
 import org.openhab.binding.hdpowerview.internal.api.responses.FirmwareVersions;
 import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections;
+import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections.SceneCollection;
 import org.openhab.binding.hdpowerview.internal.api.responses.Scenes;
+import org.openhab.binding.hdpowerview.internal.api.responses.Scenes.Scene;
 import org.openhab.binding.hdpowerview.internal.api.responses.ScheduledEvents;
+import org.openhab.binding.hdpowerview.internal.api.responses.ScheduledEvents.ScheduledEvent;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shade;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shades;
+import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData;
 import org.openhab.binding.hdpowerview.internal.api.responses.Survey;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubInvalidResponseException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubProcessingException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.gson.Gson;
+import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParseException;
 import com.google.gson.JsonParser;
@@ -133,22 +142,26 @@ public class HDPowerViewWebTargets {
      * Fetches a JSON package with firmware information for the hub.
      *
      * @return FirmwareVersions class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
     public FirmwareVersions getFirmwareVersions()
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String json = invoke(HttpMethod.GET, firmwareVersion, null, null);
-        FirmwareVersion firmwareVersion = gson.fromJson(json, FirmwareVersion.class);
-        if (firmwareVersion == null) {
-            throw new JsonParseException("Missing firmware response");
-        }
-        FirmwareVersions firmwareVersions = firmwareVersion.firmware;
-        if (firmwareVersions == null) {
-            throw new JsonParseException("Missing 'firmware' element");
+        try {
+            FirmwareVersion firmwareVersion = gson.fromJson(json, FirmwareVersion.class);
+            if (firmwareVersion == null) {
+                throw new HubInvalidResponseException("Missing firmware response");
+            }
+            FirmwareVersions firmwareVersions = firmwareVersion.firmware;
+            if (firmwareVersions == null) {
+                throw new HubInvalidResponseException("Missing 'firmware' element");
+            }
+            return firmwareVersions;
+        } catch (JsonParseException e) {
+            throw new HubInvalidResponseException("Error parsing firmware response", e);
         }
-        return firmwareVersions;
     }
 
     /**
@@ -156,13 +169,25 @@ public class HDPowerViewWebTargets {
      * a Shades class instance
      *
      * @return Shades class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Shades getShades() throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    public Shades getShades() throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String json = invoke(HttpMethod.GET, shades, null, null);
-        return gson.fromJson(json, Shades.class);
+        try {
+            Shades shades = gson.fromJson(json, Shades.class);
+            if (shades == null) {
+                throw new HubInvalidResponseException("Missing shades response");
+            }
+            List<ShadeData> shadeData = shades.shadeData;
+            if (shadeData == null) {
+                throw new HubInvalidResponseException("Missing 'shades.shadeData' element");
+            }
+            return shades;
+        } catch (JsonParseException e) {
+            throw new HubInvalidResponseException("Error parsing shades response", e);
+        }
     }
 
     /**
@@ -170,45 +195,64 @@ public class HDPowerViewWebTargets {
      *
      * @param shadeId id of the shade to be moved
      * @param position instance of ShadePosition containing the new position
-     * @return Shade class instance (with new position)
+     * @return ShadeData class instance (with new position)
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Shade moveShade(int shadeId, ShadePosition position)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    public ShadeData moveShade(int shadeId, ShadePosition position)
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String jsonRequest = gson.toJson(new ShadeMove(position));
         String jsonResponse = invoke(HttpMethod.PUT, shades + Integer.toString(shadeId), null, jsonRequest);
-        return gson.fromJson(jsonResponse, Shade.class);
+        return shadeDataFromJson(jsonResponse);
+    }
+
+    private ShadeData shadeDataFromJson(String json) throws HubInvalidResponseException {
+        try {
+            Shade shade = gson.fromJson(json, Shade.class);
+            if (shade == null) {
+                throw new HubInvalidResponseException("Missing shade response");
+            }
+            ShadeData shadeData = shade.shade;
+            if (shadeData == null) {
+                throw new HubInvalidResponseException("Missing 'shade.shade' element");
+            }
+            return shadeData;
+        } catch (JsonParseException e) {
+            throw new HubInvalidResponseException("Error parsing shade response", e);
+        }
     }
 
     /**
      * Instructs the hub to stop movement of a specific shade
      *
      * @param shadeId id of the shade to be stopped
-     * @return Shade class instance (new position cannot be relied upon)
+     * @return ShadeData class instance (new position cannot be relied upon)
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Shade stopShade(int shadeId)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    public ShadeData stopShade(int shadeId)
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String jsonRequest = gson.toJson(new ShadeStop());
         String jsonResponse = invoke(HttpMethod.PUT, shades + Integer.toString(shadeId), null, jsonRequest);
-        return gson.fromJson(jsonResponse, Shade.class);
+        return shadeDataFromJson(jsonResponse);
     }
 
     /**
      * Instructs the hub to calibrate a specific shade
      *
      * @param shadeId id of the shade to be calibrated
-     * @return Shade class instance
+     * @return ShadeData class instance
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Shade calibrateShade(int shadeId)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    public ShadeData calibrateShade(int shadeId)
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String jsonRequest = gson.toJson(new ShadeCalibrate());
         String jsonResponse = invoke(HttpMethod.PUT, shades + Integer.toString(shadeId), null, jsonRequest);
-        return gson.fromJson(jsonResponse, Shade.class);
+        return shadeDataFromJson(jsonResponse);
     }
 
     /**
@@ -216,13 +260,25 @@ public class HDPowerViewWebTargets {
      * a Scenes class instance
      *
      * @return Scenes class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Scenes getScenes() throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    public Scenes getScenes() throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String json = invoke(HttpMethod.GET, scenes, null, null);
-        return gson.fromJson(json, Scenes.class);
+        try {
+            Scenes scenes = gson.fromJson(json, Scenes.class);
+            if (scenes == null) {
+                throw new HubInvalidResponseException("Missing scenes response");
+            }
+            List<Scene> sceneData = scenes.sceneData;
+            if (sceneData == null) {
+                throw new HubInvalidResponseException("Missing 'scenes.sceneData' element");
+            }
+            return scenes;
+        } catch (JsonParseException e) {
+            throw new HubInvalidResponseException("Error parsing scenes response", e);
+        }
     }
 
     /**
@@ -241,14 +297,26 @@ public class HDPowerViewWebTargets {
      * a SceneCollections class instance
      *
      * @return SceneCollections class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable SceneCollections getSceneCollections()
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    public SceneCollections getSceneCollections()
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String json = invoke(HttpMethod.GET, sceneCollections, null, null);
-        return gson.fromJson(json, SceneCollections.class);
+        try {
+            SceneCollections sceneCollections = gson.fromJson(json, SceneCollections.class);
+            if (sceneCollections == null) {
+                throw new HubInvalidResponseException("Missing sceneCollections response");
+            }
+            List<SceneCollection> sceneCollectionData = sceneCollections.sceneCollectionData;
+            if (sceneCollectionData == null) {
+                throw new HubInvalidResponseException("Missing 'sceneCollections.sceneCollectionData' element");
+            }
+            return sceneCollections;
+        } catch (JsonParseException e) {
+            throw new HubInvalidResponseException("Error parsing sceneCollections response", e);
+        }
     }
 
     /**
@@ -268,14 +336,26 @@ public class HDPowerViewWebTargets {
      * a ScheduledEvents class instance
      *
      * @return ScheduledEvents class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable ScheduledEvents getScheduledEvents()
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    public ScheduledEvents getScheduledEvents()
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String json = invoke(HttpMethod.GET, scheduledEvents, null, null);
-        return gson.fromJson(json, ScheduledEvents.class);
+        try {
+            ScheduledEvents scheduledEvents = gson.fromJson(json, ScheduledEvents.class);
+            if (scheduledEvents == null) {
+                throw new HubInvalidResponseException("Missing scheduledEvents response");
+            }
+            List<ScheduledEvent> scheduledEventData = scheduledEvents.scheduledEventData;
+            if (scheduledEventData == null) {
+                throw new HubInvalidResponseException("Missing 'scheduledEvents.scheduledEventData' element");
+            }
+            return scheduledEvents;
+        } catch (JsonParseException e) {
+            throw new HubInvalidResponseException("Error parsing scheduledEvents response", e);
+        }
     }
 
     /**
@@ -283,19 +363,26 @@ public class HDPowerViewWebTargets {
      * 
      * @param scheduledEventId id of the scheduled event to be enabled or disabled
      * @param enable true to enable scheduled event, false to disable
-     * @throws JsonParseException if there is a JSON parsing error
-     * @throws JsonSyntaxException if there is a JSON syntax error
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
     public void enableScheduledEvent(int scheduledEventId, boolean enable)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         String uri = scheduledEvents + "/" + scheduledEventId;
-        String json = invoke(HttpMethod.GET, uri, null, null);
-        JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
-        JsonObject scheduledEventObject = jsonObject.get("scheduledEvent").getAsJsonObject();
-        scheduledEventObject.addProperty("enabled", enable);
-        invoke(HttpMethod.PUT, uri, null, jsonObject.toString());
+        String jsonResponse = invoke(HttpMethod.GET, uri, null, null);
+        try {
+            JsonObject jsonObject = JsonParser.parseString(jsonResponse).getAsJsonObject();
+            JsonElement scheduledEventElement = jsonObject.get("scheduledEvent");
+            if (scheduledEventElement == null) {
+                throw new HubInvalidResponseException("Missing 'scheduledEvent' element");
+            }
+            JsonObject scheduledEventObject = scheduledEventElement.getAsJsonObject();
+            scheduledEventObject.addProperty("enabled", enable);
+            invoke(HttpMethod.PUT, uri, null, jsonObject.toString());
+        } catch (JsonParseException | IllegalStateException e) {
+            throw new HubInvalidResponseException("Error parsing scheduledEvent response", e);
+        }
     }
 
     /**
@@ -366,15 +453,15 @@ public class HDPowerViewWebTargets {
      * in a Shade class instance
      *
      * @param shadeId id of the shade to be fetched
-     * @return Shade class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @return ShadeData class instance
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Shade getShade(int shadeId)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
-        String json = invoke(HttpMethod.GET, shades + Integer.toString(shadeId), null, null);
-        return gson.fromJson(json, Shade.class);
+    public ShadeData getShade(int shadeId)
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
+        String jsonResponse = invoke(HttpMethod.GET, shades + Integer.toString(shadeId), null, null);
+        return shadeDataFromJson(jsonResponse);
     }
 
     /**
@@ -383,16 +470,16 @@ public class HDPowerViewWebTargets {
      * and wraps it in a Shade class instance
      *
      * @param shadeId id of the shade to be refreshed
-     * @return Shade class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @return ShadeData class instance
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Shade refreshShadePosition(int shadeId)
+    public ShadeData refreshShadePosition(int shadeId)
             throws JsonParseException, HubProcessingException, HubMaintenanceException {
-        String json = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
+        String jsonResponse = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
                 Query.of("refresh", Boolean.toString(true)), null);
-        return gson.fromJson(json, Shade.class);
+        return shadeDataFromJson(jsonResponse);
     }
 
     /**
@@ -403,15 +490,23 @@ public class HDPowerViewWebTargets {
      *
      * @param shadeId id of the shade to be surveyed
      * @return Survey class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Survey getShadeSurvey(int shadeId)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
-        String json = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
+    public Survey getShadeSurvey(int shadeId)
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
+        String jsonResponse = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
                 Query.of("survey", Boolean.toString(true)), null);
-        return gson.fromJson(json, Survey.class);
+        try {
+            Survey survey = gson.fromJson(jsonResponse, Survey.class);
+            if (survey == null) {
+                throw new HubInvalidResponseException("Missing survey response");
+            }
+            return survey;
+        } catch (JsonParseException e) {
+            throw new HubInvalidResponseException("Error parsing survey response", e);
+        }
     }
 
     /**
@@ -420,15 +515,15 @@ public class HDPowerViewWebTargets {
      * and wraps it in a Shade class instance
      *
      * @param shadeId id of the shade to be refreshed
-     * @return Shade class instance
-     * @throws JsonParseException if there is a JSON parsing error
+     * @return ShadeData class instance
+     * @throws HubInvalidResponseException if response is invalid
      * @throws HubProcessingException if there is any processing error
      * @throws HubMaintenanceException if the hub is down for maintenance
      */
-    public @Nullable Shade refreshShadeBatteryLevel(int shadeId)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
-        String json = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
+    public ShadeData refreshShadeBatteryLevel(int shadeId)
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
+        String jsonResponse = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
                 Query.of("updateBatteryLevel", Boolean.toString(true)), null);
-        return gson.fromJson(json, Shade.class);
+        return shadeDataFromJson(jsonResponse);
     }
 }
diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HubMaintenanceException.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HubMaintenanceException.java
deleted file mode 100644 (file)
index 047fb40..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2010-2022 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.hdpowerview.internal;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-
-/**
- * The {@link HubMaintenanceException} is a custom exception for the HD PowerView hub
- *
- * @author Andrew Fiddian-Green - Initial contribution
- */
-@NonNullByDefault
-public class HubMaintenanceException extends Exception {
-
-    private static final long serialVersionUID = -708582495003057343L;
-
-    public HubMaintenanceException(String message) {
-        super(message);
-    }
-}
diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HubProcessingException.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HubProcessingException.java
deleted file mode 100644 (file)
index ade2cea..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2010-2022 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.hdpowerview.internal;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-
-/**
- * The {@link HubProcessingException} is a custom exception for the HD PowerView hub
- *
- * @author Andrew Fiddian-Green - Initial contribution
- */
-@NonNullByDefault
-public class HubProcessingException extends Exception {
-
-    private static final long serialVersionUID = 4307088023775166450L;
-
-    public HubProcessingException(String message) {
-        super(message);
-    }
-}
diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/SurveyData.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/SurveyData.java
new file mode 100644 (file)
index 0000000..bfb5301
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.hdpowerview.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Survey data of a single Shade, as returned by an HD PowerView hub
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class SurveyData {
+    @SerializedName("neighbor_id")
+    public int neighborId;
+    public int rssi;
+
+    @Override
+    public String toString() {
+        return String.format("{neighbor id:%d, rssi:%d}", neighborId, rssi);
+    }
+}
index 636f8b4c9a0c9684f1b4a5514cb6a26e841423ed..268e035c70e97b7a64e60df2705bb6fe37b33e96 100644 (file)
@@ -17,6 +17,7 @@ import java.util.StringJoiner;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.hdpowerview.internal.api.SurveyData;
 
 import com.google.gson.annotations.SerializedName;
 
@@ -33,17 +34,6 @@ public class Survey {
     @SerializedName("survey")
     public List<SurveyData> surveyData;
 
-    public static class SurveyData {
-        @SerializedName("neighbor_id")
-        public int neighborId;
-        public int rssi;
-
-        @Override
-        public String toString() {
-            return String.format("{neighbor id:%d, rssi:%d}", neighborId, rssi);
-        }
-    }
-
     @Override
     public String toString() {
         List<SurveyData> surveyData = this.surveyData;
index ad10709020d58a2cfb7017cbda925f8ed254c7b7..0eecec13794441f220980f016cefb374a6f5a854 100644 (file)
@@ -21,13 +21,14 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
-import org.openhab.binding.hdpowerview.internal.HubMaintenanceException;
-import org.openhab.binding.hdpowerview.internal.HubProcessingException;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shades;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData;
 import org.openhab.binding.hdpowerview.internal.config.HDPowerViewShadeConfiguration;
 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase;
 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase.Capabilities;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubProcessingException;
 import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewHubHandler;
 import org.openhab.core.config.discovery.AbstractDiscoveryService;
 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
@@ -35,8 +36,6 @@ import org.openhab.core.thing.ThingUID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.JsonParseException;
-
 /**
  * Discovers an HD PowerView Shade from an existing hub
  *
@@ -89,7 +88,7 @@ public class HDPowerViewShadeDiscoveryService extends AbstractDiscoveryService {
                     throw new HubProcessingException("Web targets not initialized");
                 }
                 Shades shades = webTargets.getShades();
-                if (shades != null && shades.shadeData != null) {
+                if (shades.shadeData != null) {
                     ThingUID bridgeUID = hub.getThing().getUID();
                     List<ShadeData> shadesData = shades.shadeData;
                     if (shadesData != null) {
@@ -116,10 +115,10 @@ public class HDPowerViewShadeDiscoveryService extends AbstractDiscoveryService {
                         }
                     }
                 }
-            } catch (HubProcessingException | JsonParseException e) {
-                logger.warn("Unexpected error: {}", e.getMessage());
             } catch (HubMaintenanceException e) {
                 // exceptions are logged in HDPowerViewWebTargets
+            } catch (HubException e) {
+                logger.warn("Unexpected error: {}", e.getMessage());
             }
             stopScan();
         };
diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubException.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubException.java
new file mode 100644 (file)
index 0000000..188ca13
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.hdpowerview.internal.exceptions;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link HubException} is a generic custom exception for the HD PowerView Hub
+ * with the intent of being derived into specific exception classes.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class HubException extends Exception {
+
+    private static final long serialVersionUID = 4052375893291196875L;
+
+    public HubException(String message) {
+        super(message);
+    }
+
+    public HubException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubInvalidResponseException.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubInvalidResponseException.java
new file mode 100644 (file)
index 0000000..3305835
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.hdpowerview.internal.exceptions;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link HubInvalidResponseException} is a custom exception for the HD PowerView Hub
+ * which is thrown when a response does not adhere to a defined contract.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class HubInvalidResponseException extends HubProcessingException {
+
+    private static final long serialVersionUID = -2293572741003905474L;
+
+    public HubInvalidResponseException(String message) {
+        super(message);
+    }
+
+    public HubInvalidResponseException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubMaintenanceException.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubMaintenanceException.java
new file mode 100644 (file)
index 0000000..b854d43
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.hdpowerview.internal.exceptions;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link HubMaintenanceException} is a custom exception for the HD PowerView hub
+ *
+ * @author Andrew Fiddian-Green - Initial contribution
+ */
+@NonNullByDefault
+public class HubMaintenanceException extends HubException {
+
+    private static final long serialVersionUID = -708582495003057343L;
+
+    public HubMaintenanceException(String message) {
+        super(message);
+    }
+}
diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubProcessingException.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/exceptions/HubProcessingException.java
new file mode 100644 (file)
index 0000000..e8ae40a
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.hdpowerview.internal.exceptions;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link HubProcessingException} is a custom exception for the HD PowerView hub
+ *
+ * @author Andrew Fiddian-Green - Initial contribution
+ */
+@NonNullByDefault
+public class HubProcessingException extends HubException {
+
+    private static final long serialVersionUID = 4307088023775166450L;
+
+    public HubProcessingException(String message) {
+        super(message);
+    }
+
+    public HubProcessingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
index 464cc23007905599eeaa94d517aa8f7f296e5b85..8b3d2c60e844f1c3341cb157d914a5796e9ebe0f 100644 (file)
@@ -34,8 +34,6 @@ import org.eclipse.jetty.client.HttpClient;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewTranslationProvider;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
-import org.openhab.binding.hdpowerview.internal.HubMaintenanceException;
-import org.openhab.binding.hdpowerview.internal.HubProcessingException;
 import org.openhab.binding.hdpowerview.internal.api.Firmware;
 import org.openhab.binding.hdpowerview.internal.api.responses.FirmwareVersions;
 import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections;
@@ -48,6 +46,10 @@ import org.openhab.binding.hdpowerview.internal.api.responses.Shades;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData;
 import org.openhab.binding.hdpowerview.internal.config.HDPowerViewHubConfiguration;
 import org.openhab.binding.hdpowerview.internal.config.HDPowerViewShadeConfiguration;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubInvalidResponseException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubProcessingException;
 import org.openhab.core.library.CoreItemFactory;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.Bridge;
@@ -66,8 +68,6 @@ import org.openhab.core.types.RefreshType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.JsonParseException;
-
 /**
  * The {@link HDPowerViewHubHandler} is responsible for handling commands, which
  * are sent to one of the channels.
@@ -147,7 +147,7 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
             }
         } catch (HubMaintenanceException e) {
             // exceptions are logged in HDPowerViewWebTargets
-        } catch (NumberFormatException | HubProcessingException e) {
+        } catch (NumberFormatException | HubException e) {
             logger.debug("Unexpected error {}", e.getMessage());
         }
     }
@@ -267,17 +267,23 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
             // Scheduled events should also have their current state updated if event has been
             // enabled or disabled through app or other integration.
             updateScheduledEventStates(scheduledEvents);
-        } catch (JsonParseException e) {
-            logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
-        } catch (HubProcessingException e) {
-            logger.warn("Error connecting to bridge: {}", e.getMessage());
-            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, e.getMessage());
+        } catch (HubInvalidResponseException e) {
+            Throwable cause = e.getCause();
+            if (cause == null) {
+                logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
+            } else {
+                logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage());
+            }
         } catch (HubMaintenanceException e) {
             // exceptions are logged in HDPowerViewWebTargets
+        } catch (HubException e) {
+            logger.warn("Error connecting to bridge: {}", e.getMessage());
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, e.getMessage());
         }
     }
 
-    private void updateFirmwareProperties() throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    private void updateFirmwareProperties()
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         if (firmwareVersions != null) {
             return;
         }
@@ -306,20 +312,16 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
         updateProperties(properties);
     }
 
-    private void pollShades() throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    private void pollShades() throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         HDPowerViewWebTargets webTargets = this.webTargets;
         if (webTargets == null) {
             throw new ProcessingException("Web targets not initialized");
         }
 
         Shades shades = webTargets.getShades();
-        if (shades == null) {
-            throw new JsonParseException("Missing 'shades' element");
-        }
-
         List<ShadeData> shadesData = shades.shadeData;
         if (shadesData == null) {
-            throw new JsonParseException("Missing 'shades.shadeData' element");
+            throw new HubInvalidResponseException("Missing 'shades.shadeData' element");
         }
 
         updateStatus(ThingStatus.ONLINE);
@@ -349,20 +351,17 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
         thingHandler.onReceiveUpdate(shadeData);
     }
 
-    private List<Scene> fetchScenes() throws JsonParseException, HubProcessingException, HubMaintenanceException {
+    private List<Scene> fetchScenes()
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         HDPowerViewWebTargets webTargets = this.webTargets;
         if (webTargets == null) {
             throw new ProcessingException("Web targets not initialized");
         }
 
         Scenes scenes = webTargets.getScenes();
-        if (scenes == null) {
-            throw new JsonParseException("Missing 'scenes' element");
-        }
-
         List<Scene> sceneData = scenes.sceneData;
         if (sceneData == null) {
-            throw new JsonParseException("Missing 'scenes.sceneData' element");
+            throw new HubInvalidResponseException("Missing 'scenes.sceneData' element");
         }
         logger.debug("Received data for {} scenes", sceneData.size());
 
@@ -370,7 +369,7 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
     }
 
     private List<Scene> updateSceneChannels()
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         List<Scene> scenes = fetchScenes();
 
         if (scenes.size() == sceneCache.size() && sceneCache.containsAll(scenes)) {
@@ -445,20 +444,16 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
     }
 
     private List<SceneCollection> fetchSceneCollections()
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         HDPowerViewWebTargets webTargets = this.webTargets;
         if (webTargets == null) {
             throw new ProcessingException("Web targets not initialized");
         }
 
         SceneCollections sceneCollections = webTargets.getSceneCollections();
-        if (sceneCollections == null) {
-            throw new JsonParseException("Missing 'sceneCollections' element");
-        }
-
         List<SceneCollection> sceneCollectionData = sceneCollections.sceneCollectionData;
         if (sceneCollectionData == null) {
-            throw new JsonParseException("Missing 'sceneCollections.sceneCollectionData' element");
+            throw new HubInvalidResponseException("Missing 'sceneCollections.sceneCollectionData' element");
         }
         logger.debug("Received data for {} sceneCollections", sceneCollectionData.size());
 
@@ -466,7 +461,7 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
     }
 
     private List<SceneCollection> updateSceneCollectionChannels()
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         List<SceneCollection> sceneCollections = fetchSceneCollections();
 
         if (sceneCollections.size() == sceneCollectionCache.size()
@@ -502,20 +497,16 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
     }
 
     private List<ScheduledEvent> fetchScheduledEvents()
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         HDPowerViewWebTargets webTargets = this.webTargets;
         if (webTargets == null) {
             throw new ProcessingException("Web targets not initialized");
         }
 
         ScheduledEvents scheduledEvents = webTargets.getScheduledEvents();
-        if (scheduledEvents == null) {
-            throw new JsonParseException("Missing 'scheduledEvents' element");
-        }
-
         List<ScheduledEvent> scheduledEventData = scheduledEvents.scheduledEventData;
         if (scheduledEventData == null) {
-            throw new JsonParseException("Missing 'scheduledEvents.scheduledEventData' element");
+            throw new HubInvalidResponseException("Missing 'scheduledEvents.scheduledEventData' element");
         }
         logger.debug("Received data for {} scheduledEvents", scheduledEventData.size());
 
@@ -524,7 +515,7 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
 
     private List<ScheduledEvent> updateScheduledEventChannels(List<Scene> scenes,
             List<SceneCollection> sceneCollections)
-            throws JsonParseException, HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         List<ScheduledEvent> scheduledEvents = fetchScheduledEvents();
 
         if (scheduledEvents.size() == scheduledEventCache.size() && scheduledEventCache.containsAll(scheduledEvents)) {
index e5e9f7ceee9098948ec05bcddd5d033dcde18341..6b42bf7d01319c05d20edbbe37e3e1be831b5fb6 100644 (file)
@@ -25,17 +25,18 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
-import org.openhab.binding.hdpowerview.internal.HubMaintenanceException;
-import org.openhab.binding.hdpowerview.internal.HubProcessingException;
 import org.openhab.binding.hdpowerview.internal.api.CoordinateSystem;
 import org.openhab.binding.hdpowerview.internal.api.Firmware;
 import org.openhab.binding.hdpowerview.internal.api.ShadePosition;
-import org.openhab.binding.hdpowerview.internal.api.responses.Shade;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData;
 import org.openhab.binding.hdpowerview.internal.api.responses.Survey;
 import org.openhab.binding.hdpowerview.internal.config.HDPowerViewShadeConfiguration;
 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase;
 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase.Capabilities;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubInvalidResponseException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubProcessingException;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.PercentType;
@@ -54,8 +55,6 @@ import org.openhab.core.types.UnDefType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.JsonParseException;
-
 /**
  * Handles commands for an HD PowerView Shade
  *
@@ -171,21 +170,26 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
         }
         try {
             handleShadeCommand(channelId, command, webTargets, shadeId);
-        } catch (JsonParseException e) {
-            logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
-        } catch (HubProcessingException e) {
+        } catch (HubInvalidResponseException e) {
+            Throwable cause = e.getCause();
+            if (cause == null) {
+                logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
+            } else {
+                logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage());
+            }
+        } catch (HubMaintenanceException e) {
+            // exceptions are logged in HDPowerViewWebTargets
+        } catch (HubException e) {
             // ScheduledFutures will be cancelled by dispose(), naturally causing InterruptedException in invoke()
             // for any ongoing requests. Logging this would only cause confusion.
             if (!isDisposing) {
                 logger.warn("Unexpected error: {}", e.getMessage());
             }
-        } catch (HubMaintenanceException e) {
-            // exceptions are logged in HDPowerViewWebTargets
         }
     }
 
     private void handleShadeCommand(String channelId, Command command, HDPowerViewWebTargets webTargets, int shadeId)
-            throws HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         switch (channelId) {
             case CHANNEL_SHADE_POSITION:
                 if (command instanceof PercentType) {
@@ -417,53 +421,36 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
     }
 
     private void moveShade(CoordinateSystem coordSys, int newPercent, HDPowerViewWebTargets webTargets, int shadeId)
-            throws HubProcessingException, HubMaintenanceException {
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
         ShadePosition newPosition = null;
         // (try to) read the positions from the hub
-        Shade shade = webTargets.getShade(shadeId);
-        if (shade != null) {
-            ShadeData shadeData = shade.shade;
-            if (shadeData != null) {
-                updateCapabilities(shadeData);
-                newPosition = shadeData.positions;
-            }
-        }
+        ShadeData shadeData = webTargets.getShade(shadeId);
+        updateCapabilities(shadeData);
+        newPosition = shadeData.positions;
         // if no positions returned, then create a new position
         if (newPosition == null) {
             newPosition = new ShadePosition();
         }
         Capabilities capabilities = getCapabilitiesOrDefault();
         // set the new position value, and write the positions to the hub
-        shade = webTargets.moveShade(shadeId, newPosition.setPosition(capabilities, coordSys, newPercent));
-        if (shade != null) {
-            updateShadePositions(shade);
-        }
+        shadeData = webTargets.moveShade(shadeId, newPosition.setPosition(capabilities, coordSys, newPercent));
+        updateShadePositions(shadeData);
     }
 
     private void stopShade(HDPowerViewWebTargets webTargets, int shadeId)
-            throws HubProcessingException, HubMaintenanceException {
-        Shade shade = webTargets.stopShade(shadeId);
-        if (shade != null) {
-            updateShadePositions(shade);
-        }
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
+        updateShadePositions(webTargets.stopShade(shadeId));
         // Positions in response from stop motion is not updated to to actual positions yet,
         // so we need to request hard refresh.
         requestRefreshShadePosition();
     }
 
     private void calibrateShade(HDPowerViewWebTargets webTargets, int shadeId)
-            throws HubProcessingException, HubMaintenanceException {
-        Shade shade = webTargets.calibrateShade(shadeId);
-        if (shade != null) {
-            updateShadePositions(shade);
-        }
+            throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException {
+        updateShadePositions(webTargets.calibrateShade(shadeId));
     }
 
-    private void updateShadePositions(Shade shade) {
-        ShadeData shadeData = shade.shade;
-        if (shadeData == null) {
-            return;
-        }
+    private void updateShadePositions(ShadeData shadeData) {
         ShadePosition shadePosition = shadeData.positions;
         if (shadePosition == null) {
             return;
@@ -532,44 +519,46 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
             if (webTargets == null) {
                 throw new HubProcessingException("Web targets not initialized");
             }
-            Shade shade;
+            ShadeData shadeData;
             switch (kind) {
                 case POSITION:
-                    shade = webTargets.refreshShadePosition(shadeId);
+                    shadeData = webTargets.refreshShadePosition(shadeId);
                     break;
                 case SURVEY:
                     Survey survey = webTargets.getShadeSurvey(shadeId);
-                    if (survey != null && survey.surveyData != null) {
+                    if (survey.surveyData != null) {
                         logger.debug("Survey response for shade {}: {}", survey.shadeId, survey.toString());
                     } else {
                         logger.warn("No response from shade {} survey", shadeId);
                     }
                     return;
                 case BATTERY_LEVEL:
-                    shade = webTargets.refreshShadeBatteryLevel(shadeId);
+                    shadeData = webTargets.refreshShadeBatteryLevel(shadeId);
                     break;
                 default:
                     throw new NotSupportedException("Unsupported refresh kind " + kind.toString());
             }
-            if (shade != null) {
-                ShadeData shadeData = shade.shade;
-                if (shadeData != null) {
-                    if (Boolean.TRUE.equals(shadeData.timedOut)) {
-                        logger.warn("Shade {} wireless refresh time out", shadeId);
-                    } else if (kind == RefreshKind.POSITION) {
-                        updateShadePositions(shade);
-                        updateHardProperties(shadeData);
-                    }
-                }
+            if (Boolean.TRUE.equals(shadeData.timedOut)) {
+                logger.warn("Shade {} wireless refresh time out", shadeId);
+            } else if (kind == RefreshKind.POSITION) {
+                updateShadePositions(shadeData);
+                updateHardProperties(shadeData);
             }
-        } catch (HubProcessingException e) {
+        } catch (HubInvalidResponseException e) {
+            Throwable cause = e.getCause();
+            if (cause == null) {
+                logger.warn("Bridge returned a bad JSON response: {}", e.getMessage());
+            } else {
+                logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage());
+            }
+        } catch (HubMaintenanceException e) {
+            // exceptions are logged in HDPowerViewWebTargets
+        } catch (HubException e) {
             // ScheduledFutures will be cancelled by dispose(), naturally causing InterruptedException in invoke()
             // for any ongoing requests. Logging this would only cause confusion.
             if (!isDisposing) {
                 logger.warn("Unexpected error: {}", e.getMessage());
             }
-        } catch (HubMaintenanceException e) {
-            // exceptions are logged in HDPowerViewWebTargets
         }
     }
 }
index 8dfbed2f00e0d5cddd91f245ab9f8a83035fe0c3..229468ecb53d89e71eeebbedbe46d1668e74bc35 100644 (file)
@@ -26,18 +26,18 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jetty.client.HttpClient;
 import org.junit.jupiter.api.Test;
 import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
-import org.openhab.binding.hdpowerview.internal.HubMaintenanceException;
-import org.openhab.binding.hdpowerview.internal.HubProcessingException;
 import org.openhab.binding.hdpowerview.internal.api.ShadePosition;
 import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections;
 import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections.SceneCollection;
 import org.openhab.binding.hdpowerview.internal.api.responses.Scenes;
 import org.openhab.binding.hdpowerview.internal.api.responses.Scenes.Scene;
-import org.openhab.binding.hdpowerview.internal.api.responses.Shade;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shades;
 import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData;
 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase;
 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase.Capabilities;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException;
+import org.openhab.binding.hdpowerview.internal.exceptions.HubProcessingException;
 import org.openhab.core.library.types.PercentType;
 import org.openhab.core.types.State;
 import org.openhab.core.types.UnDefType;
@@ -120,30 +120,28 @@ public class HDPowerViewJUnitTests {
             try {
                 shadesX = webTargets.getShades();
                 assertNotNull(shadesX);
-                if (shadesX != null) {
-                    List<ShadeData> shadesData = shadesX.shadeData;
-                    assertNotNull(shadesData);
-
-                    if (shadesData != null) {
-                        assertTrue(!shadesData.isEmpty());
-                        ShadeData shadeData;
-                        shadeData = shadesData.get(0);
-                        assertNotNull(shadeData);
-                        assertTrue(shadeData.getName().length() > 0);
-                        shadePos = shadeData.positions;
-                        assertNotNull(shadePos);
-                        ShadeData shadeZero = shadesData.get(0);
-                        assertNotNull(shadeZero);
-                        shadeId = shadeZero.id;
-                        assertNotEquals(0, shadeId);
-
-                        for (ShadeData shadexData : shadesData) {
-                            String shadeName = shadexData.getName();
-                            assertNotNull(shadeName);
-                        }
+                List<ShadeData> shadesData = shadesX.shadeData;
+                assertNotNull(shadesData);
+
+                if (shadesData != null) {
+                    assertTrue(!shadesData.isEmpty());
+                    ShadeData shadeData;
+                    shadeData = shadesData.get(0);
+                    assertNotNull(shadeData);
+                    assertTrue(shadeData.getName().length() > 0);
+                    shadePos = shadeData.positions;
+                    assertNotNull(shadePos);
+                    ShadeData shadeZero = shadesData.get(0);
+                    assertNotNull(shadeZero);
+                    shadeId = shadeZero.id;
+                    assertNotEquals(0, shadeId);
+
+                    for (ShadeData shadexData : shadesData) {
+                        String shadeName = shadexData.getName();
+                        assertNotNull(shadeName);
                     }
                 }
-            } catch (JsonParseException | HubProcessingException | HubMaintenanceException e) {
+            } catch (HubException e) {
                 fail(e.getMessage());
             }
 
@@ -153,90 +151,71 @@ public class HDPowerViewJUnitTests {
                 Scenes scenes = webTargets.getScenes();
                 assertNotNull(scenes);
 
-                if (scenes != null) {
-                    List<Scene> scenesData = scenes.sceneData;
-                    assertNotNull(scenesData);
+                List<Scene> scenesData = scenes.sceneData;
+                assertNotNull(scenesData);
 
-                    if (scenesData != null) {
-                        assertTrue(!scenesData.isEmpty());
-                        Scene sceneZero = scenesData.get(0);
-                        assertNotNull(sceneZero);
-                        sceneId = sceneZero.id;
-                        assertTrue(sceneId > 0);
+                if (scenesData != null) {
+                    assertTrue(!scenesData.isEmpty());
+                    Scene sceneZero = scenesData.get(0);
+                    assertNotNull(sceneZero);
+                    sceneId = sceneZero.id;
+                    assertTrue(sceneId > 0);
 
-                        for (Scene scene : scenesData) {
-                            String sceneName = scene.getName();
-                            assertNotNull(sceneName);
-                        }
+                    for (Scene scene : scenesData) {
+                        String sceneName = scene.getName();
+                        assertNotNull(sceneName);
                     }
                 }
-            } catch (JsonParseException | HubProcessingException | HubMaintenanceException e) {
+            } catch (HubException e) {
                 fail(e.getMessage());
             }
 
             // ==== refresh a specific shade ====
-            Shade shade = null;
+            ShadeData shadeData = null;
             try {
                 assertNotEquals(0, shadeId);
-                shade = webTargets.refreshShadePosition(shadeId);
-                assertNotNull(shade);
-            } catch (HubProcessingException | HubMaintenanceException e) {
+                shadeData = webTargets.refreshShadePosition(shadeId);
+            } catch (HubException e) {
                 fail(e.getMessage());
             }
 
             // ==== move a specific shade ====
             try {
                 assertNotEquals(0, shadeId);
-                assertNotNull(shade);
-                if (shade != null) {
-                    ShadeData shadeData = shade.shade;
-                    assertNotNull(shadeData);
 
-                    if (shadeData != null) {
-                        ShadePosition positions = shadeData.positions;
-                        assertNotNull(positions);
-
-                        if (positions != null) {
-                            Integer capabilitiesValue = shadeData.capabilities;
-                            assertNotNull(capabilitiesValue);
-
-                            if (capabilitiesValue != null) {
-                                Capabilities capabilities = db.getCapabilities(capabilitiesValue.intValue());
-
-                                State pos = positions.getState(capabilities, PRIMARY_ZERO_IS_CLOSED);
-                                assertEquals(PercentType.class, pos.getClass());
-
-                                int position = ((PercentType) pos).intValue();
-                                position = position + ((position <= 10) ? 5 : -5);
-
-                                ShadePosition targetPosition = new ShadePosition().setPosition(capabilities,
-                                        PRIMARY_ZERO_IS_CLOSED, position);
-                                assertNotNull(targetPosition);
-
-                                if (allowShadeMovementCommands) {
-                                    webTargets.moveShade(shadeId, targetPosition);
-
-                                    Shade newShade = webTargets.getShade(shadeId);
-                                    assertNotNull(newShade);
-                                    if (newShade != null) {
-                                        ShadeData newData = newShade.shade;
-                                        assertNotNull(newData);
-                                        if (newData != null) {
-                                            ShadePosition actualPosition = newData.positions;
-                                            assertNotNull(actualPosition);
-                                            if (actualPosition != null) {
-                                                assertEquals(
-                                                        targetPosition.getState(capabilities, PRIMARY_ZERO_IS_CLOSED),
-                                                        actualPosition.getState(capabilities, PRIMARY_ZERO_IS_CLOSED));
-                                            }
-                                        }
-                                    }
-                                }
+                if (shadeData != null) {
+                    ShadePosition positions = shadeData.positions;
+                    assertNotNull(positions);
+                    Integer capabilitiesValue = shadeData.capabilities;
+                    assertNotNull(capabilitiesValue);
+
+                    if (positions != null && capabilitiesValue != null) {
+                        Capabilities capabilities = db.getCapabilities(capabilitiesValue.intValue());
+
+                        State pos = positions.getState(capabilities, PRIMARY_ZERO_IS_CLOSED);
+                        assertEquals(PercentType.class, pos.getClass());
+
+                        int position = ((PercentType) pos).intValue();
+                        position = position + ((position <= 10) ? 5 : -5);
+
+                        ShadePosition targetPosition = new ShadePosition().setPosition(capabilities,
+                                PRIMARY_ZERO_IS_CLOSED, position);
+                        assertNotNull(targetPosition);
+
+                        if (allowShadeMovementCommands) {
+                            webTargets.moveShade(shadeId, targetPosition);
+
+                            ShadeData newData = webTargets.getShade(shadeId);
+                            ShadePosition actualPosition = newData.positions;
+                            assertNotNull(actualPosition);
+                            if (actualPosition != null) {
+                                assertEquals(targetPosition.getState(capabilities, PRIMARY_ZERO_IS_CLOSED),
+                                        actualPosition.getState(capabilities, PRIMARY_ZERO_IS_CLOSED));
                             }
                         }
                     }
                 }
-            } catch (HubProcessingException | HubMaintenanceException e) {
+            } catch (HubException e) {
                 fail(e.getMessage());
             }
 
@@ -255,7 +234,7 @@ public class HDPowerViewJUnitTests {
                 try {
                     assertNotNull(sceneId);
                     webTargets.stopShade(shadeId);
-                } catch (HubProcessingException | HubMaintenanceException e) {
+                } catch (HubException e) {
                     fail(e.getMessage());
                 }
             }