]> git.basschouten.com Git - openhab-addons.git/commitdiff
[wemo] add annotations and remove usage of apache.commons.* (#9829)
authorHans-Jörg Merk <github@hmerk.de>
Thu, 8 Apr 2021 20:46:46 +0000 (22:46 +0200)
committerGitHub <noreply@github.com>
Thu, 8 Apr 2021 20:46:46 +0000 (22:46 +0200)
* [wemo] add annotations and remove usage of apache.commons.*

Also-by: Wouter Born <github@maindrain.net>
Signed-off-by: Hans-Jörg Merk <github@hmerk.de>
24 files changed:
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoBindingConstants.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHandlerFactory.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHttpCallFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoUtil.java [new file with mode: 0644]
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryParticipant.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryService.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoLinkDiscoveryService.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/AbstractWemoHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBridgeHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCoffeeHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCrockpotHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoDimmerHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHolmesHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoLightHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMakerHandler.java
bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/http/WemoHttpCall.java
itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/discovery/test/WemoDiscoveryParticipantTest.java
itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerOSGiTest.java
itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerTest.java
itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoLightHandlerOSGiTest.java
itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoMakerHandlerOSGiTest.java
itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoLightOSGiTestParent.java
itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoOSGiTest.java

index 81374f34a19d5bd88495b0ca056c5aba63e6ac4f..c094db7e592e59863fe0ce47edc1fffc0ccedd2d 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.core.thing.ThingTypeUID;
 
 /**
@@ -26,6 +27,7 @@ import org.openhab.core.thing.ThingTypeUID;
  * @author Hans-Jörg Merk - Initial contribution
  * @author Mihir Patil - Added standby switch
  */
+@NonNullByDefault
 public class WemoBindingConstants {
 
     public static final String BINDING_ID = "wemo";
@@ -109,8 +111,8 @@ public class WemoBindingConstants {
     public static final String UDN = "udn";
     public static final String DEVICE_ID = "deviceID";
     public static final String POLLINGINTERVALL = "pollingInterval";
-
-    public static final int SUBSCRIPTION_DURATION = 600;
+    public static final int DEFAULT_REFRESH_INTERVALL_SECONDS = 60;
+    public static final int SUBSCRIPTION_DURATION_SECONDS = 600;
     public static final int LINK_DISCOVERY_SERVICE_INITIAL_DELAY = 5;
     public static final String HTTP_CALL_CONTENT_HEADER = "text/xml; charset=utf-8";
 
index 4dbef6902af0d3817e9c3daaca57372ae2396dee..0b25b1e0ac7d185f30ae8b501ba222998006670b 100644 (file)
@@ -19,6 +19,8 @@ import java.util.Hashtable;
 import java.util.Map;
 import java.util.Set;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.discovery.WemoLinkDiscoveryService;
 import org.openhab.binding.wemo.internal.handler.WemoBridgeHandler;
 import org.openhab.binding.wemo.internal.handler.WemoCoffeeHandler;
@@ -39,8 +41,11 @@ import org.openhab.core.thing.binding.BaseThingHandlerFactory;
 import org.openhab.core.thing.binding.ThingHandler;
 import org.openhab.core.thing.binding.ThingHandlerFactory;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,15 +56,17 @@ import org.slf4j.LoggerFactory;
  * @author Hans-Jörg Merk - Initial contribution
  * @author Kai Kreuzer - some refactoring for performance and simplification
  */
+@NonNullByDefault
 @Component(service = ThingHandlerFactory.class, configurationPid = "binding.wemo")
 public class WemoHandlerFactory extends BaseThingHandlerFactory {
 
     private final Logger logger = LoggerFactory.getLogger(WemoHandlerFactory.class);
 
-    private UpnpIOService upnpIOService;
-
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = WemoBindingConstants.SUPPORTED_THING_TYPES;
 
+    private UpnpIOService upnpIOService;
+    private @Nullable WemoHttpCallFactory wemoHttpCallFactory;
+
     @Override
     public boolean supportsThingType(ThingTypeUID thingTypeUID) {
         return SUPPORTED_THING_TYPES.contains(thingTypeUID);
@@ -67,70 +74,73 @@ public class WemoHandlerFactory extends BaseThingHandlerFactory {
 
     private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
 
-    @SuppressWarnings({ "null", "unused" })
-    @Override
-    protected ThingHandler createHandler(Thing thing) {
-        ThingTypeUID thingTypeUID = thing.getThingTypeUID();
-        if (thingTypeUID != null) {
-            logger.debug("Trying to create a handler for ThingType '{}", thingTypeUID);
-
-            WemoHttpCall wemoHttpcaller = new WemoHttpCall();
-
-            if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_BRIDGE)) {
-                logger.debug("Creating a WemoBridgeHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get(UDN));
-                WemoBridgeHandler handler = new WemoBridgeHandler((Bridge) thing);
-                registerDeviceDiscoveryService(handler, wemoHttpcaller);
-                return handler;
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MAKER)) {
-                logger.debug("Creating a WemoMakerHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get(UDN));
-                return new WemoMakerHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (WemoBindingConstants.SUPPORTED_DEVICE_THING_TYPES.contains(thing.getThingTypeUID())) {
-                logger.debug("Creating a WemoHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get(UDN));
-                return new WemoHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_COFFEE)) {
-                logger.debug("Creating a WemoCoffeeHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get(UDN));
-                return new WemoCoffeeHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_DIMMER)) {
-                logger.debug("Creating a WemoDimmerHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get("udn"));
-                return new WemoDimmerHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_CROCKPOT)) {
-                logger.debug("Creating a WemoCockpotHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get("udn"));
-                return new WemoCrockpotHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_PURIFIER)) {
-                logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get("udn"));
-                return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HUMIDIFIER)) {
-                logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get("udn"));
-                return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HEATER)) {
-                logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
-                        thing.getConfiguration().get("udn"));
-                return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
-            } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MZ100)) {
-                return new WemoLightHandler(thing, upnpIOService, wemoHttpcaller);
-            } else {
-                logger.warn("ThingHandler not found for {}", thingTypeUID);
-                return null;
-            }
-        }
-        return null;
+    @Activate
+    public WemoHandlerFactory(final @Reference UpnpIOService upnpIOService) {
+        this.upnpIOService = upnpIOService;
     }
 
-    @Reference
-    protected void setUpnpIOService(UpnpIOService upnpIOService) {
-        this.upnpIOService = upnpIOService;
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
+    public void setWemoHttpCallFactory(WemoHttpCallFactory wemoHttpCallFactory) {
+        this.wemoHttpCallFactory = wemoHttpCallFactory;
+    }
+
+    public void unsetWemoHttpCallFactory(WemoHttpCallFactory wemoHttpCallFactory) {
+        this.wemoHttpCallFactory = null;
     }
 
-    protected void unsetUpnpIOService(UpnpIOService upnpIOService) {
-        this.upnpIOService = null;
+    @Override
+    protected @Nullable ThingHandler createHandler(Thing thing) {
+        ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+        logger.debug("Trying to create a handler for ThingType '{}", thingTypeUID);
+
+        WemoHttpCallFactory wemoHttpCallFactory = this.wemoHttpCallFactory;
+        WemoHttpCall wemoHttpcaller = wemoHttpCallFactory == null ? new WemoHttpCall()
+                : wemoHttpCallFactory.createHttpCall();
+
+        if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_BRIDGE)) {
+            logger.debug("Creating a WemoBridgeHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get(UDN));
+            WemoBridgeHandler handler = new WemoBridgeHandler((Bridge) thing);
+            registerDeviceDiscoveryService(handler, wemoHttpcaller);
+            return handler;
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MAKER)) {
+            logger.debug("Creating a WemoMakerHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get(UDN));
+            return new WemoMakerHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (WemoBindingConstants.SUPPORTED_DEVICE_THING_TYPES.contains(thing.getThingTypeUID())) {
+            logger.debug("Creating a WemoHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get(UDN));
+            return new WemoHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_COFFEE)) {
+            logger.debug("Creating a WemoCoffeeHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get(UDN));
+            return new WemoCoffeeHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_DIMMER)) {
+            logger.debug("Creating a WemoDimmerHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get("udn"));
+            return new WemoDimmerHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_CROCKPOT)) {
+            logger.debug("Creating a WemoCockpotHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get("udn"));
+            return new WemoCrockpotHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_PURIFIER)) {
+            logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get("udn"));
+            return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HUMIDIFIER)) {
+            logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get("udn"));
+            return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HEATER)) {
+            logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
+                    thing.getConfiguration().get("udn"));
+            return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
+        } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MZ100)) {
+            return new WemoLightHandler(thing, upnpIOService, wemoHttpcaller);
+        } else {
+            logger.warn("ThingHandler not found for {}", thingTypeUID);
+            return null;
+        }
     }
 
     @Override
diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHttpCallFactory.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHttpCallFactory.java
new file mode 100644 (file)
index 0000000..45ef542
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2010-2021 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.wemo.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.wemo.internal.http.WemoHttpCall;
+
+/**
+ * {@link WemoHttpCallFactory} creates {@WemoHttpCall}s.
+ *
+ * @author Wouter Born - Initial contribution
+ */
+@NonNullByDefault
+public interface WemoHttpCallFactory {
+
+    WemoHttpCall createHttpCall();
+}
diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoUtil.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoUtil.java
new file mode 100644 (file)
index 0000000..a89a55b
--- /dev/null
@@ -0,0 +1,158 @@
+/**
+ * Copyright (c) 2010-2021 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.wemo.internal;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.io.net.http.HttpUtil;
+
+/**
+ * {@link WemoUtil} implements some helper functions.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class WemoUtil {
+
+    public static BiFunction<String, Integer, Boolean> serviceAvailableFunction = WemoUtil::servicePing;
+
+    public static String substringBefore(@Nullable String string, String pattern) {
+        if (string != null) {
+            int pos = string.indexOf(pattern);
+            if (pos > 0) {
+                return string.substring(0, pos);
+            }
+        }
+        return "";
+    }
+
+    public static String substringBetween(@Nullable String string, String begin, String end) {
+        if (string != null) {
+            int s = string.indexOf(begin);
+            if (s != -1) {
+                String result = string.substring(s + begin.length());
+                return substringBefore(result, end);
+            }
+        }
+        return "";
+    }
+
+    public static String unescape(final String text) {
+        StringBuilder result = new StringBuilder(text.length());
+        int i = 0;
+        int n = text.length();
+        while (i < n) {
+            char charAt = text.charAt(i);
+            if (charAt != '&') {
+                result.append(charAt);
+                i++;
+            } else {
+                if (text.startsWith("&amp;", i)) {
+                    result.append('&');
+                    i += 5;
+                } else if (text.startsWith("&apos;", i)) {
+                    result.append('\'');
+                    i += 6;
+                } else if (text.startsWith("&quot;", i)) {
+                    result.append('"');
+                    i += 6;
+                } else if (text.startsWith("&lt;", i)) {
+                    result.append('<');
+                    i += 4;
+                } else if (text.startsWith("&gt;", i)) {
+                    result.append('>');
+                    i += 4;
+                } else {
+                    i++;
+                }
+            }
+        }
+        return result.toString();
+    }
+
+    public static String unescapeXml(final String xml) {
+        Pattern xmlEntityRegex = Pattern.compile("&(#?)([^;]+);");
+        // Unfortunately, Matcher requires a StringBuffer instead of a StringBuilder
+        StringBuffer unescapedOutput = new StringBuffer(xml.length());
+
+        Matcher m = xmlEntityRegex.matcher(xml);
+        Map<String, String> builtinEntities = null;
+        String entity;
+        String hashmark;
+        String ent;
+        int code;
+        while (m.find()) {
+            ent = m.group(2);
+            hashmark = m.group(1);
+            if ((hashmark != null) && (hashmark.length() > 0)) {
+                code = Integer.parseInt(ent);
+                entity = Character.toString((char) code);
+            } else {
+                // must be a non-numerical entity
+                if (builtinEntities == null) {
+                    builtinEntities = buildBuiltinXMLEntityMap();
+                }
+                entity = builtinEntities.get(ent);
+                if (entity == null) {
+                    // not a known entity - ignore it
+                    entity = "&" + ent + ';';
+                }
+            }
+            m.appendReplacement(unescapedOutput, entity);
+        }
+        m.appendTail(unescapedOutput);
+
+        return unescapedOutput.toString();
+    }
+
+    public static @Nullable String getWemoURL(URL descriptorURL, String actionService) {
+        int portCheckStart = 49151;
+        int portCheckStop = 49157;
+        String port = null;
+        String host = substringBetween(descriptorURL.toString(), "://", ":");
+        for (int i = portCheckStart; i < portCheckStop; i++) {
+            if (serviceAvailableFunction.apply(host, i)) {
+                port = String.valueOf(i);
+                break;
+            }
+        }
+        return port == null ? null : "http://" + host + ":" + port + "/upnp/control/" + actionService + "1";
+    }
+
+    private static boolean servicePing(String host, int port) {
+        try {
+            HttpUtil.executeUrl("GET", "http://" + host + ":" + port, 250);
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    private static Map<String, String> buildBuiltinXMLEntityMap() {
+        Map<String, String> entities = new HashMap<String, String>(10);
+        entities.put("lt", "<");
+        entities.put("gt", ">");
+        entities.put("amp", "&");
+        entities.put("apos", "'");
+        entities.put("quot", "\"");
+        return entities;
+    }
+}
index 09767ff1a160a8574ee7cdb470d08e1b2115b30d..940946c7b630c0464bdbd52d1c5ec01325cbd5ce 100644 (file)
@@ -18,6 +18,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.jupnp.model.meta.RemoteDevice;
 import org.openhab.binding.wemo.internal.WemoBindingConstants;
@@ -39,6 +40,7 @@ import org.slf4j.LoggerFactory;
  * @author Kai Kreuzer - some refactoring for performance and simplification
  *
  */
+@NonNullByDefault
 @Component(service = UpnpDiscoveryParticipant.class)
 public class WemoDiscoveryParticipant implements UpnpDiscoveryParticipant {
 
@@ -50,7 +52,7 @@ public class WemoDiscoveryParticipant implements UpnpDiscoveryParticipant {
     }
 
     @Override
-    public DiscoveryResult createResult(RemoteDevice device) {
+    public @Nullable DiscoveryResult createResult(RemoteDevice device) {
         ThingUID uid = getThingUID(device);
         if (uid != null) {
             Map<String, Object> properties = new HashMap<>(2);
@@ -75,7 +77,7 @@ public class WemoDiscoveryParticipant implements UpnpDiscoveryParticipant {
     }
 
     @Override
-    public ThingUID getThingUID(@Nullable RemoteDevice device) {
+    public @Nullable ThingUID getThingUID(@Nullable RemoteDevice device) {
         if (device != null) {
             if (device.getDetails().getManufacturerDetails().getManufacturer() != null) {
                 if (device.getDetails().getManufacturerDetails().getManufacturer().toUpperCase().contains("BELKIN")) {
index 0442dd606e399cf31398f8fe8970ae2705790761..531fa6c457aaa7a21a0c673aad68142146c7ef58 100644 (file)
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.wemo.internal.discovery;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.jupnp.UpnpService;
 import org.jupnp.model.message.header.RootDeviceHeader;
 import org.openhab.core.config.discovery.AbstractDiscoveryService;
@@ -28,6 +30,7 @@ import org.slf4j.LoggerFactory;
  * @author Hans-Jörg Merk - Initial contribution
  *
  */
+@NonNullByDefault
 @Component(service = DiscoveryService.class, configurationPid = "discovery.wemo")
 public class WemoDiscoveryService extends AbstractDiscoveryService {
 
@@ -37,7 +40,7 @@ public class WemoDiscoveryService extends AbstractDiscoveryService {
         super(5);
     }
 
-    private UpnpService upnpService;
+    private @Nullable UpnpService upnpService;
 
     @Reference
     protected void setUpnpService(UpnpService upnpService) {
index 368bb103cc2c2ef835192b6a0a9ca217f30a0140..40d7d03cf029b29e6ed1d7fe515862424124496f 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.wemo.internal.discovery;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
 import java.io.StringReader;
 import java.net.URL;
@@ -26,8 +27,8 @@ import java.util.concurrent.TimeUnit;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.handler.WemoBridgeHandler;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.discovery.AbstractDiscoveryService;
@@ -53,6 +54,7 @@ import org.xml.sax.InputSource;
  * @author Hans-Jörg Merk - Initial contribution
  *
  */
+@NonNullByDefault
 public class WemoLinkDiscoveryService extends AbstractDiscoveryService implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoLinkDiscoveryService.class);
@@ -84,7 +86,7 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement
     /**
      * Schedule for scanning
      */
-    private ScheduledFuture<?> scanningJob;
+    private @Nullable ScheduledFuture<?> scanningJob;
 
     /**
      * The Upnp service
@@ -96,20 +98,12 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement
     public WemoLinkDiscoveryService(WemoBridgeHandler wemoBridgeHandler, UpnpIOService upnpIOService,
             WemoHttpCall wemoHttpCaller) {
         super(SEARCH_TIME);
+        this.service = upnpIOService;
         this.wemoBridgeHandler = wemoBridgeHandler;
 
         this.wemoHttpCaller = wemoHttpCaller;
 
-        if (upnpIOService != null) {
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
-
         this.scanningRunnable = new WemoLinkScan();
-        if (wemoBridgeHandler == null) {
-            logger.warn("no bridge handler for scan given");
-        }
         this.activate(null);
     }
 
@@ -134,7 +128,7 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement
             URL descriptorURL = service.getDescriptorURL(this);
 
             if (descriptorURL != null) {
-                String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml");
+                String deviceURL = substringBefore(descriptorURL.toString(), "/setup.xml");
                 String wemoURL = deviceURL + "/upnp/control/bridge1";
 
                 String endDeviceRequest = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
@@ -143,10 +137,9 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement
                     logger.trace("endDeviceRequest answered '{}'", endDeviceRequest);
 
                     try {
-                        String stringParser = StringUtils.substringBetween(endDeviceRequest, "<DeviceLists>",
-                                "</DeviceLists>");
+                        String stringParser = substringBetween(endDeviceRequest, "<DeviceLists>", "</DeviceLists>");
 
-                        stringParser = StringEscapeUtils.unescapeXml(stringParser);
+                        stringParser = unescapeXml(stringParser);
 
                         // check if there are already paired devices with WeMo Link
                         if ("0".equals(stringParser)) {
@@ -245,7 +238,9 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement
     protected void startBackgroundDiscovery() {
         logger.trace("Start WeMo device background discovery");
 
-        if (scanningJob == null || scanningJob.isCancelled()) {
+        ScheduledFuture<?> job = scanningJob;
+
+        if (job == null || job.isCancelled()) {
             this.scanningJob = scheduler.scheduleWithFixedDelay(this.scanningRunnable,
                     LINK_DISCOVERY_SERVICE_INITIAL_DELAY, SCAN_INTERVAL, TimeUnit.SECONDS);
         } else {
@@ -257,10 +252,11 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement
     protected void stopBackgroundDiscovery() {
         logger.debug("Stop WeMo device background discovery");
 
-        if (scanningJob != null && !scanningJob.isCancelled()) {
-            scanningJob.cancel(true);
-            scanningJob = null;
+        ScheduledFuture<?> job = scanningJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        scanningJob = null;
     }
 
     @Override
@@ -269,11 +265,11 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
     }
 
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
     }
 
     @Override
index dce551b1d4f45bab8b98fab496647cd34cc63b1f..1702b3e28e37d7c863bf29c255cb7c16b531eee3 100644 (file)
  */
 package org.openhab.binding.wemo.internal.handler;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.binding.BaseThingHandler;
 
 /**
- *
- * @author Stefan Triller
- *
+ * @author Stefan Triller - Initial contribution
  */
+@NonNullByDefault
 public abstract class AbstractWemoHandler extends BaseThingHandler {
 
-    public AbstractWemoHandler(Thing thing) {
-        super(thing);
-    }
-
     protected WemoHttpCall wemoHttpCaller;
 
-    public void setWemoHttpCaller(WemoHttpCall wemoHttpCaller) {
+    public AbstractWemoHandler(Thing thing, WemoHttpCall wemoHttpCaller) {
+        super(thing);
         this.wemoHttpCaller = wemoHttpCaller;
     }
 }
index d115fb74184976438eec086989ef4ac380d00c31..abdda3d28903b804c9e303c8021044713b0a95a8 100644 (file)
@@ -17,6 +17,7 @@ import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
 import java.util.Collections;
 import java.util.Set;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.ChannelUID;
@@ -34,6 +35,7 @@ import org.slf4j.LoggerFactory;
  *
  * @author Hans-Jörg Merk - Initial contribution
  */
+@NonNullByDefault
 public class WemoBridgeHandler extends BaseBridgeHandler {
 
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BRIDGE);
index 2e5ebbe1c192377137b41dcfdeb5aa087f919076..a39d63f2f81c3d1720d6c55b53cf1f725c6dacda 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.wemo.internal.handler;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
 import java.io.StringReader;
 import java.math.BigDecimal;
@@ -30,8 +31,8 @@ import java.util.concurrent.TimeUnit;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
@@ -64,7 +65,7 @@ import org.xml.sax.InputSource;
  * @author Hans-Jörg Merk - Initial contribution
  * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType
  */
-
+@NonNullByDefault
 public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoCoffeeHandler.class);
@@ -73,16 +74,11 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
 
     private Map<String, Boolean> subscriptionState = new HashMap<>();
 
-    protected static final int SUBSCRIPTION_DURATION = 600;
-
     private UpnpIOService service;
 
-    /**
-     * The default refresh interval in Seconds.
-     */
-    private final int REFRESH_INTERVAL = 60;
+    private WemoHttpCall wemoCall;
 
-    private ScheduledFuture<?> refreshJob;
+    private @Nullable ScheduledFuture<?> refreshJob;
 
     private final Runnable refreshRunnable = new Runnable() {
 
@@ -102,18 +98,13 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
         }
     };
 
-    public WemoCoffeeHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpcaller) {
-        super(thing);
+    public WemoCoffeeHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
+        super(thing, wemoHttpCaller);
 
-        this.wemoHttpCaller = wemoHttpcaller;
+        this.wemoCall = wemoHttpCaller;
+        this.service = upnpIOService;
 
         logger.debug("Creating a WemoCoffeeHandler V0.4 for thing '{}'", getThing().getUID());
-
-        if (upnpIOService != null) {
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
     }
 
     @Override
@@ -134,12 +125,12 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
     public void dispose() {
         logger.debug("WeMoCoffeeHandler disposed.");
 
-        removeSubscription();
-
-        if (refreshJob != null && !refreshJob.isCancelled()) {
-            refreshJob.cancel(true);
-            refreshJob = null;
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        refreshJob = null;
+        removeSubscription();
     }
 
     @Override
@@ -171,10 +162,11 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
                                 + "&lt;attribute&gt;&lt;name&gt;Cleaning&lt;/name&gt;&lt;value&gt;NULL&lt;/value&gt;&lt;/attribute&gt;</attributeList>"
                                 + "</u:SetAttributes>" + "</s:Body>" + "</s:Envelope>";
 
-                        String wemoURL = getWemoURL("deviceevent");
+                        URL descriptorURL = service.getDescriptorURL(this);
+                        String wemoURL = getWemoURL(descriptorURL, "basicevent");
 
                         if (wemoURL != null) {
-                            String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                            String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                             if (wemoCallResponse != null) {
                                 updateState(CHANNEL_STATE, OnOffType.ON);
                                 State newMode = new StringType("Brewing");
@@ -195,13 +187,16 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
-        logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed");
-        subscriptionState.put(service, succeeded);
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
+        if (service != null) {
+            logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service,
+                    succeeded ? "succeeded" : "failed");
+            subscriptionState.put(service, succeeded);
+        }
     }
 
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
         // We can subscribe to GENA events, but there is no usefull response right now.
     }
 
@@ -210,9 +205,9 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
             logger.debug("Checking WeMo GENA subscription for '{}'", this);
 
             String subscription = "deviceevent1";
-            if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) == null) {
                 logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription);
-                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION);
+                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS);
                 subscriptionState.put(subscription, true);
             }
         } else {
@@ -226,7 +221,7 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
 
         if (service.isRegistered(this)) {
             String subscription = "deviceevent1";
-            if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) != null) {
                 logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription);
                 service.removeSubscription(this, subscription);
             }
@@ -237,9 +232,10 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
     }
 
     private synchronized void onUpdate() {
-        if (refreshJob == null || refreshJob.isCancelled()) {
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
             Configuration config = getThing().getConfiguration();
-            int refreshInterval = REFRESH_INTERVAL;
+            int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS;
             Object refreshConfig = config.get("pollingInterval");
             if (refreshConfig != null) {
                 refreshInterval = ((BigDecimal) refreshConfig).intValue();
@@ -272,17 +268,18 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
                 + action + ">" + "</s:Body>" + "</s:Envelope>";
 
         try {
-            String wemoURL = getWemoURL(actionService);
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, actionService);
+
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
                     try {
-                        String stringParser = StringUtils.substringBetween(wemoCallResponse, "<attributeList>",
-                                "</attributeList>");
+                        String stringParser = substringBetween(wemoCallResponse, "<attributeList>", "</attributeList>");
 
                         // Due to Belkins bad response formatting, we need to run this twice.
-                        stringParser = StringEscapeUtils.unescapeXml(stringParser);
-                        stringParser = StringEscapeUtils.unescapeXml(stringParser);
+                        stringParser = unescapeXml(stringParser);
+                        stringParser = unescapeXml(stringParser);
 
                         logger.trace("CoffeeMaker response '{}' for device '{}' received", stringParser,
                                 getThing().getUID());
@@ -321,6 +318,8 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
                             switch (attributeName) {
                                 case "Mode":
                                     State newMode = new StringType("Brewing");
+                                    State newAttributeValue;
+
                                     switch (attributeValue) {
                                         case "0":
                                             updateState(CHANNEL_STATE, OnOffType.ON);
@@ -370,51 +369,35 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
                                     }
                                     break;
                                 case "ModeTime":
-                                    if (attributeValue != null) {
-                                        State newAttributeValue = new DecimalType(attributeValue);
-                                        updateState(CHANNEL_MODETIME, newAttributeValue);
-                                    }
+                                    newAttributeValue = new DecimalType(attributeValue);
+                                    updateState(CHANNEL_MODETIME, newAttributeValue);
                                     break;
                                 case "TimeRemaining":
-                                    if (attributeValue != null) {
-                                        State newAttributeValue = new DecimalType(attributeValue);
-                                        updateState(CHANNEL_TIMEREMAINING, newAttributeValue);
-                                    }
+                                    newAttributeValue = new DecimalType(attributeValue);
+                                    updateState(CHANNEL_TIMEREMAINING, newAttributeValue);
                                     break;
                                 case "WaterLevelReached":
-                                    if (attributeValue != null) {
-                                        State newAttributeValue = new DecimalType(attributeValue);
-                                        updateState(CHANNEL_WATERLEVELREACHED, newAttributeValue);
-                                    }
+                                    newAttributeValue = new DecimalType(attributeValue);
+                                    updateState(CHANNEL_WATERLEVELREACHED, newAttributeValue);
                                     break;
                                 case "CleanAdvise":
-                                    if (attributeValue != null) {
-                                        State newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF
-                                                : OnOffType.ON;
-                                        updateState(CHANNEL_CLEANADVISE, newAttributeValue);
-                                    }
+                                    newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF : OnOffType.ON;
+                                    updateState(CHANNEL_CLEANADVISE, newAttributeValue);
                                     break;
                                 case "FilterAdvise":
-                                    if (attributeValue != null) {
-                                        State newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF
-                                                : OnOffType.ON;
-                                        updateState(CHANNEL_FILTERADVISE, newAttributeValue);
-                                    }
+                                    newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF : OnOffType.ON;
+                                    updateState(CHANNEL_FILTERADVISE, newAttributeValue);
                                     break;
                                 case "Brewed":
-                                    if (attributeValue != null) {
-                                        State newAttributeValue = getDateTimeState(attributeValue);
-                                        if (newAttributeValue != null) {
-                                            updateState(CHANNEL_BREWED, newAttributeValue);
-                                        }
+                                    newAttributeValue = getDateTimeState(attributeValue);
+                                    if (newAttributeValue != null) {
+                                        updateState(CHANNEL_BREWED, newAttributeValue);
                                     }
                                     break;
                                 case "LastCleaned":
-                                    if (attributeValue != null) {
-                                        State newAttributeValue = getDateTimeState(attributeValue);
-                                        if (newAttributeValue != null) {
-                                            updateState(CHANNEL_LASTCLEANED, newAttributeValue);
-                                        }
+                                    newAttributeValue = getDateTimeState(attributeValue);
+                                    if (newAttributeValue != null) {
+                                        updateState(CHANNEL_LASTCLEANED, newAttributeValue);
                                     }
                                     break;
                             }
@@ -430,37 +413,19 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart
         }
     }
 
-    @SuppressWarnings("null")
-    public State getDateTimeState(String attributeValue) {
-        if (attributeValue != null) {
-            long value = 0;
-            try {
-                value = Long.parseLong(attributeValue) * 1000; // convert s to ms
-            } catch (NumberFormatException e) {
-                logger.error("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue,
-                        getThing().getUID());
-                return null;
-            }
-            ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(value),
-                    TimeZone.getDefault().toZoneId());
-            State dateTimeState = new DateTimeType(zoned);
-            if (dateTimeState != null) {
-                logger.trace("New attribute brewed '{}' received", dateTimeState);
-                return dateTimeState;
-            }
-        }
-        return null;
-    }
-
-    public String getWemoURL(String actionService) {
-        URL descriptorURL = service.getDescriptorURL(this);
-        String wemoURL = null;
-        if (descriptorURL != null) {
-            String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml");
-            wemoURL = deviceURL + "/upnp/control/" + actionService + "1";
-            return wemoURL;
+    public @Nullable State getDateTimeState(String attributeValue) {
+        long value = 0;
+        try {
+            value = Long.parseLong(attributeValue);
+        } catch (NumberFormatException e) {
+            logger.error("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue,
+                    getThing().getUID());
+            return null;
         }
-        return null;
+        ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochSecond(value), TimeZone.getDefault().toZoneId());
+        State dateTimeState = new DateTimeType(zoned);
+        logger.trace("New attribute brewed '{}' received", dateTimeState);
+        return dateTimeState;
     }
 
     public static String getCharacterDataFromElement(Element e) {
index 4ca69f11012e910402b31e2f4ac5d29189190471..b76e2e7d071884d5de77faf4f37e1e36d3335f0d 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.wemo.internal.handler;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
 import java.math.BigDecimal;
 import java.net.URL;
@@ -23,7 +24,8 @@ import java.util.Set;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
@@ -47,22 +49,21 @@ import org.slf4j.LoggerFactory;
  *
  * @author Hans-Jörg Merk - Initial contribution;
  */
-
+@NonNullByDefault
 public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoCrockpotHandler.class);
 
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_CROCKPOT);
-    /**
-     * The default refresh interval in Seconds.
-     */
-    private static final int DEFAULT_REFRESH_INTERVAL_SECONDS = 120;
+
     private final Map<String, Boolean> subscriptionState = new HashMap<>();
     private final Map<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
 
     private UpnpIOService service;
 
-    private ScheduledFuture<?> refreshJob;
+    private WemoHttpCall wemoCall;
+
+    private @Nullable ScheduledFuture<?> refreshJob;
 
     private final Runnable refreshRunnable = () -> {
         updateWemoState();
@@ -73,18 +74,13 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
         }
     };
 
-    public WemoCrockpotHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) {
-        super(thing);
+    public WemoCrockpotHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
+        super(thing, wemoHttpCaller);
 
-        this.wemoHttpCaller = wemohttpCaller;
+        this.wemoCall = wemoHttpCaller;
+        this.service = upnpIOService;
 
         logger.debug("Creating a WemoCrockpotHandler for thing '{}'", getThing().getUID());
-
-        if (upnpIOService != null) {
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
     }
 
     @Override
@@ -106,12 +102,12 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
     public void dispose() {
         logger.debug("WeMoCrockpotHandler disposed.");
 
-        removeSubscription();
-
-        if (refreshJob != null && !refreshJob.isCancelled()) {
-            refreshJob.cancel(true);
-            refreshJob = null;
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        refreshJob = null;
+        removeSubscription();
     }
 
     @Override
@@ -146,10 +142,12 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
                         + "<s:Body>" + "<u:SetCrockpotState xmlns:u=\"urn:Belkin:service:basicevent:1\">" + "<mode>"
                         + mode + "</mode>" + "<time>" + time + "</time>" + "</u:SetCrockpotState>" + "</s:Body>"
                         + "</s:Envelope>";
-                String wemoURL = getWemoURL("basicevent");
+
+                URL descriptorURL = service.getDescriptorURL(this);
+                String wemoURL = getWemoURL(descriptorURL, "basicevent");
 
                 if (wemoURL != null) {
-                    wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                    wemoCall.executeCall(wemoURL, soapHeader, content);
                 }
             } catch (RuntimeException e) {
                 logger.debug("Failed to send command '{}' for device '{}':", command, getThing().getUID(), e);
@@ -160,18 +158,23 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
-        logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed");
-        subscriptionState.put(service, succeeded);
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
+        if (service != null) {
+            logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service,
+                    succeeded ? "succeeded" : "failed");
+            subscriptionState.put(service, succeeded);
+        }
     }
 
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
         logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", variable, value, service,
                 this.getThing().getUID());
 
         updateStatus(ThingStatus.ONLINE);
-        this.stateMap.put(variable, value);
+        if (variable != null && value != null) {
+            this.stateMap.put(variable, value);
+        }
     }
 
     private synchronized void onSubscription() {
@@ -180,9 +183,9 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
 
             String subscription = "basicevent1";
 
-            if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) == null) {
                 logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription);
-                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION);
+                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS);
                 subscriptionState.put(subscription, true);
             }
 
@@ -198,7 +201,7 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
         if (service.isRegistered(this)) {
             String subscription = "basicevent1";
 
-            if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) != null) {
                 logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription);
                 service.removeSubscription(this, subscription);
             }
@@ -209,11 +212,12 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
     }
 
     private synchronized void onUpdate() {
-        if (refreshJob == null || refreshJob.isCancelled()) {
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
             Configuration config = getThing().getConfiguration();
-            int refreshInterval = DEFAULT_REFRESH_INTERVAL_SECONDS;
+            int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS;
             Object refreshConfig = config.get("refresh");
-            refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVAL_SECONDS
+            refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVALL_SECONDS
                     : ((BigDecimal) refreshConfig).intValue();
             refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS);
         }
@@ -244,42 +248,41 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
                 + action + ">" + "</s:Body>" + "</s:Envelope>";
 
         try {
-            String wemoURL = getWemoURL(actionService);
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, actionService);
+
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
                     logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID());
-                    String mode = StringUtils.substringBetween(wemoCallResponse, "<mode>", "</mode>");
-                    String time = StringUtils.substringBetween(wemoCallResponse, "<time>", "</time>");
-                    String coockedTime = StringUtils.substringBetween(wemoCallResponse, "<coockedTime>",
-                            "</coockedTime>");
-
-                    if (mode != null && time != null && coockedTime != null) {
-                        State newMode = new StringType(mode);
-                        State newCoockedTime = DecimalType.valueOf(coockedTime);
-                        switch (mode) {
-                            case "0":
-                                newMode = new StringType("OFF");
-                                break;
-                            case "50":
-                                newMode = new StringType("WARM");
-                                State warmTime = DecimalType.valueOf(time);
-                                updateState(CHANNEL_WARMCOOKTIME, warmTime);
-                                break;
-                            case "51":
-                                newMode = new StringType("LOW");
-                                State lowTime = DecimalType.valueOf(time);
-                                updateState(CHANNEL_LOWCOOKTIME, lowTime);
-                                break;
-                            case "52":
-                                newMode = new StringType("HIGH");
-                                State highTime = DecimalType.valueOf(time);
-                                updateState(CHANNEL_HIGHCOOKTIME, highTime);
-                                break;
-                        }
-                        updateState(CHANNEL_COOKMODE, newMode);
-                        updateState(CHANNEL_COOKEDTIME, newCoockedTime);
+                    String mode = substringBetween(wemoCallResponse, "<mode>", "</mode>");
+                    String time = substringBetween(wemoCallResponse, "<time>", "</time>");
+                    String coockedTime = substringBetween(wemoCallResponse, "<coockedTime>", "</coockedTime>");
+
+                    State newMode = new StringType(mode);
+                    State newCoockedTime = DecimalType.valueOf(coockedTime);
+                    switch (mode) {
+                        case "0":
+                            newMode = new StringType("OFF");
+                            break;
+                        case "50":
+                            newMode = new StringType("WARM");
+                            State warmTime = DecimalType.valueOf(time);
+                            updateState(CHANNEL_WARMCOOKTIME, warmTime);
+                            break;
+                        case "51":
+                            newMode = new StringType("LOW");
+                            State lowTime = DecimalType.valueOf(time);
+                            updateState(CHANNEL_LOWCOOKTIME, lowTime);
+                            break;
+                        case "52":
+                            newMode = new StringType("HIGH");
+                            State highTime = DecimalType.valueOf(time);
+                            updateState(CHANNEL_HIGHCOOKTIME, highTime);
+                            break;
                     }
+                    updateState(CHANNEL_COOKMODE, newMode);
+                    updateState(CHANNEL_COOKEDTIME, newCoockedTime);
                 }
             }
         } catch (RuntimeException e) {
@@ -289,17 +292,6 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa
         updateStatus(ThingStatus.ONLINE);
     }
 
-    public String getWemoURL(String actionService) {
-        URL descriptorURL = service.getDescriptorURL(this);
-        String wemoURL = null;
-        if (descriptorURL != null) {
-            String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml");
-            wemoURL = deviceURL + "/upnp/control/" + actionService + "1";
-            return wemoURL;
-        }
-        return null;
-    }
-
     @Override
     public void onStatusChanged(boolean status) {
     }
index cfd6fa622abacfd8eca1390d69e61d6c627f7bb2..3496ae3e3fbf8fee0655976447b2ecfb9611eba6 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.wemo.internal.handler;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
 import java.math.BigDecimal;
 import java.net.URL;
@@ -26,7 +27,8 @@ import java.util.TimeZone;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
@@ -53,27 +55,28 @@ import org.slf4j.LoggerFactory;
  *
  * @author Hans-Jörg Merk - Initial contribution
  */
-
+@NonNullByDefault
 public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoDimmerHandler.class);
+
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DIMMER);
+
     private Map<String, Boolean> subscriptionState = new HashMap<>();
     private Map<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
-    protected static final int SUBSCRIPTION_DURATION = 600;
+
     private UpnpIOService service;
+    private WemoHttpCall wemoCall;
+
     private int currentBrightness;
     private int currentNightModeBrightness;
-    private String currentNightModeState = null;
+    private @Nullable String currentNightModeState;
     /**
      * Set dimming stepsize to 5%
      */
     private static final int DIM_STEPSIZE = 5;
-    /**
-     * The default refresh interval in Seconds.
-     */
-    private int DEFAULT_REFRESH_INTERVAL = 60;
-    private ScheduledFuture<?> refreshJob;
+
+    private @Nullable ScheduledFuture<?> refreshJob;
     private Runnable refreshRunnable = new Runnable() {
 
         @Override
@@ -90,15 +93,13 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
         }
     };
 
-    public WemoDimmerHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) {
-        super(thing);
-        this.wemoHttpCaller = wemohttpCaller;
+    public WemoDimmerHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
+        super(thing, wemoHttpCaller);
+
+        this.service = upnpIOService;
+        this.wemoCall = wemoHttpCaller;
+
         logger.debug("Creating a WemoDimmerHandler for thing '{}'", getThing().getUID());
-        if (upnpIOService != null) {
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
     }
 
     @Override
@@ -117,11 +118,14 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
     @Override
     public void dispose() {
         logger.debug("WeMoDimmerHandler disposed.");
-        removeSubscription();
-        if (refreshJob != null && !refreshJob.isCancelled()) {
-            refreshJob.cancel(true);
-            refreshJob = null;
+
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        refreshJob = null;
+
+        removeSubscription();
     }
 
     @Override
@@ -140,6 +144,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
             String timeStamp = null;
             switch (channelUID.getId()) {
                 case CHANNEL_BRIGHTNESS:
+                    String binaryState = this.stateMap.get("BinaryState");
                     if (command instanceof OnOffType) {
                         value = command.equals(OnOffType.OFF) ? "0" : "1";
                         setBinaryState(action, argument, value);
@@ -163,7 +168,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
                             value = "0";
                             argument = "BinaryState";
                             setBinaryState(action, argument, "0");
-                        } else if (this.stateMap.get("BinaryState").equals("0")) {
+                        } else if ("0".equals(binaryState)) {
                             argument = "BinaryState";
                             setBinaryState(action, argument, "1");
                         }
@@ -197,7 +202,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
                             value = "0";
                             argument = "BinaryState";
                             setBinaryState(action, argument, "0");
-                        } else if (this.stateMap.get("BinaryState").equals("0")) {
+                        } else if ("0".equals(binaryState)) {
                             argument = "BinaryState";
                             setBinaryState(action, argument, "1");
                         }
@@ -235,12 +240,15 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
                     logger.info("timestamp '{}' created", timeStamp);
                     String faderSeconds = null;
                     String faderEnabled = null;
-                    String[] splitFader = this.stateMap.get("fader").split(":");
-                    if (splitFader[0] != null) {
-                        faderSeconds = splitFader[0];
-                    }
-                    if (splitFader[0] != null) {
-                        faderEnabled = splitFader[2];
+                    String fader = this.stateMap.get("fader");
+                    if (fader != null) {
+                        String[] splitFader = fader.split(":");
+                        if (splitFader[0] != null) {
+                            faderSeconds = splitFader[0];
+                        }
+                        if (splitFader[0] != null) {
+                            faderEnabled = splitFader[2];
+                        }
                     }
                     if (faderSeconds != null && faderEnabled != null) {
                         if (command.equals(OnOffType.ON)) {
@@ -311,82 +319,100 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
-        logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed");
-        subscriptionState.put(service, succeeded);
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
+        if (service != null) {
+            logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service,
+                    succeeded ? "succeeded" : "failed");
+            subscriptionState.put(service, succeeded);
+        }
     }
 
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
         logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'",
                 new Object[] { variable, value, service, this.getThing().getUID() });
         updateStatus(ThingStatus.ONLINE);
-        this.stateMap.put(variable, value);
-        switch (variable) {
-            case "BinaryState":
-                State state = value.equals("0") ? OnOffType.OFF : OnOffType.ON;
-                logger.debug("State '{}' for device '{}' received", state, getThing().getUID());
-                updateState(CHANNEL_BRIGHTNESS, state);
-                if (state.equals(OnOffType.OFF)) {
-                    updateState(CHANNEL_TIMERSTART, OnOffType.OFF);
-                }
-                break;
-            case "brightness":
-                logger.debug("brightness '{}' for device '{}' received", value, getThing().getUID());
-                int newBrightnessValue = Integer.valueOf(value);
-                State newBrightnessState = new PercentType(newBrightnessValue);
-                if (this.stateMap.get("BinaryState").equals("1")) {
-                    updateState(CHANNEL_BRIGHTNESS, newBrightnessState);
-                }
-                currentBrightness = newBrightnessValue;
-                break;
-            case "fader":
-                logger.debug("fader '{}' for device '{}' received", value, getThing().getUID());
-                String[] splitFader = value.split(":");
-                if (splitFader[0] != null) {
-                    int faderSeconds = Integer.valueOf(splitFader[0]);
-                    State faderMinutes = new DecimalType(faderSeconds / 60);
-                    logger.debug("faderTime '{} minutes' for device '{}' received", faderMinutes, getThing().getUID());
-                    updateState(CHANNEL_FADERCOUNTDOWNTIME, faderMinutes);
-                }
-                if (splitFader[1] != null) {
-                    State isTimerRunning = splitFader[1].equals("-1") ? OnOffType.OFF : OnOffType.ON;
-                    logger.debug("isTimerRunning '{}' for device '{}' received", isTimerRunning, getThing().getUID());
-                    updateState(CHANNEL_TIMERSTART, isTimerRunning);
-                    if (isTimerRunning.equals(OnOffType.ON)) {
-                        updateState(CHANNEL_STATE, OnOffType.ON);
+        if (variable != null && value != null) {
+            this.stateMap.put(variable, value);
+        }
+        if (variable != null && value != null) {
+            switch (variable) {
+                case "BinaryState":
+                    State state = value.equals("0") ? OnOffType.OFF : OnOffType.ON;
+                    logger.debug("State '{}' for device '{}' received", state, getThing().getUID());
+                    updateState(CHANNEL_BRIGHTNESS, state);
+                    if (state.equals(OnOffType.OFF)) {
+                        updateState(CHANNEL_TIMERSTART, OnOffType.OFF);
                     }
-                }
-                if (splitFader[2] != null) {
-                    State isFaderEnabled = splitFader[1].equals("0") ? OnOffType.OFF : OnOffType.ON;
-                    logger.debug("isFaderEnabled '{}' for device '{}' received", isFaderEnabled, getThing().getUID());
-                    updateState(CHANNEL_FADERENABLED, isFaderEnabled);
-                }
-                break;
-            case "nightMode":
-                State nightModeState = value.equals("0") ? OnOffType.OFF : OnOffType.ON;
-                currentNightModeState = value;
-                logger.debug("nightModeState '{}' for device '{}' received", nightModeState, getThing().getUID());
-                updateState(CHANNEL_NIGHTMODE, nightModeState);
-                break;
-            case "startTime":
-                State startTimeState = getDateTimeState(value);
-                logger.debug("startTimeState '{}' for device '{}' received", startTimeState, getThing().getUID());
-                updateState(CHANNEL_STARTTIME, startTimeState);
-                break;
-            case "endTime":
-                State endTimeState = getDateTimeState(value);
-                logger.debug("endTimeState '{}' for device '{}' received", endTimeState, getThing().getUID());
-                updateState(CHANNEL_ENDTIME, endTimeState);
-                break;
-            case "nightModeBrightness":
-                int nightModeBrightnessValue = Integer.valueOf(value);
-                currentNightModeBrightness = nightModeBrightnessValue;
-                State nightModeBrightnessState = new PercentType(nightModeBrightnessValue);
-                logger.debug("nightModeBrightnessState '{}' for device '{}' received", nightModeBrightnessState,
-                        getThing().getUID());
-                updateState(CHANNEL_NIGHTMODEBRIGHTNESS, nightModeBrightnessState);
-                break;
+                    break;
+                case "brightness":
+                    logger.debug("brightness '{}' for device '{}' received", value, getThing().getUID());
+                    int newBrightnessValue = Integer.valueOf(value);
+                    State newBrightnessState = new PercentType(newBrightnessValue);
+                    String binaryState = this.stateMap.get("BinaryState");
+                    if (binaryState != null) {
+                        if (binaryState.equals("1")) {
+                            updateState(CHANNEL_BRIGHTNESS, newBrightnessState);
+                        }
+                    }
+                    currentBrightness = newBrightnessValue;
+                    break;
+                case "fader":
+                    logger.debug("fader '{}' for device '{}' received", value, getThing().getUID());
+                    String[] splitFader = value.split(":");
+                    if (splitFader[0] != null) {
+                        int faderSeconds = Integer.valueOf(splitFader[0]);
+                        State faderMinutes = new DecimalType(faderSeconds / 60);
+                        logger.debug("faderTime '{} minutes' for device '{}' received", faderMinutes,
+                                getThing().getUID());
+                        updateState(CHANNEL_FADERCOUNTDOWNTIME, faderMinutes);
+                    }
+                    if (splitFader[1] != null) {
+                        State isTimerRunning = splitFader[1].equals("-1") ? OnOffType.OFF : OnOffType.ON;
+                        logger.debug("isTimerRunning '{}' for device '{}' received", isTimerRunning,
+                                getThing().getUID());
+                        updateState(CHANNEL_TIMERSTART, isTimerRunning);
+                        if (isTimerRunning.equals(OnOffType.ON)) {
+                            updateState(CHANNEL_STATE, OnOffType.ON);
+                        }
+                    }
+                    if (splitFader[2] != null) {
+                        State isFaderEnabled = splitFader[1].equals("0") ? OnOffType.OFF : OnOffType.ON;
+                        logger.debug("isFaderEnabled '{}' for device '{}' received", isFaderEnabled,
+                                getThing().getUID());
+                        updateState(CHANNEL_FADERENABLED, isFaderEnabled);
+                    }
+                    break;
+                case "nightMode":
+                    State nightModeState = value.equals("0") ? OnOffType.OFF : OnOffType.ON;
+                    currentNightModeState = value;
+                    logger.debug("nightModeState '{}' for device '{}' received", nightModeState, getThing().getUID());
+                    updateState(CHANNEL_NIGHTMODE, nightModeState);
+                    break;
+                case "startTime":
+                    State startTimeState = getDateTimeState(value);
+                    logger.debug("startTimeState '{}' for device '{}' received", startTimeState, getThing().getUID());
+                    if (startTimeState != null) {
+                        updateState(CHANNEL_STARTTIME, startTimeState);
+                    }
+                    break;
+                case "endTime":
+                    State endTimeState = getDateTimeState(value);
+                    logger.debug("endTimeState '{}' for device '{}' received", endTimeState, getThing().getUID());
+                    if (endTimeState != null) {
+                        updateState(CHANNEL_ENDTIME, endTimeState);
+                    }
+                    break;
+                case "nightModeBrightness":
+                    int nightModeBrightnessValue = Integer.valueOf(value);
+                    currentNightModeBrightness = nightModeBrightnessValue;
+                    State nightModeBrightnessState = new PercentType(nightModeBrightnessValue);
+                    logger.debug("nightModeBrightnessState '{}' for device '{}' received", nightModeBrightnessState,
+                            getThing().getUID());
+                    updateState(CHANNEL_NIGHTMODEBRIGHTNESS, nightModeBrightnessState);
+                    break;
+            }
+
         }
     }
 
@@ -394,9 +420,9 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
         if (service.isRegistered(this)) {
             logger.debug("Checking WeMo GENA subscription for '{}'", this);
             String subscription = "basicevent1";
-            if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) == null) {
                 logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription);
-                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION);
+                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS);
                 subscriptionState.put(subscription, true);
             }
         } else {
@@ -409,7 +435,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
         logger.debug("Removing WeMo GENA subscription for '{}'", this);
         if (service.isRegistered(this)) {
             String subscription = "basicevent1";
-            if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) != null) {
                 logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription);
                 service.removeSubscription(this, subscription);
             }
@@ -419,9 +445,10 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
     }
 
     private synchronized void onUpdate() {
-        if (refreshJob == null || refreshJob.isCancelled()) {
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
             Configuration config = getThing().getConfiguration();
-            int refreshInterval = DEFAULT_REFRESH_INTERVAL;
+            int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS;
             Object refreshConfig = config.get("refresh");
             if (refreshConfig != null) {
                 refreshInterval = ((BigDecimal) refreshConfig).intValue();
@@ -455,29 +482,25 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
                 + "<s:Body>" + "<u:" + action + " xmlns:u=\"urn:Belkin:service:" + actionService + ":1\">" + "</u:"
                 + action + ">" + "</s:Body>" + "</s:Envelope>";
         try {
-            String wemoURL = getWemoURL(actionService);
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, "basicevent");
+
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
                     logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID());
-                    value = StringUtils.substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
-                    if (value != null) {
-                        variable = "BinaryState";
-                        logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
-                    }
-                    value = StringUtils.substringBetween(wemoCallResponse, "<brightness>", "</brightness>");
-                    if (value != null) {
-                        variable = "brightness";
-                        logger.trace("New brightness '{}' for device '{}' received", value, getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
-                    }
-                    value = StringUtils.substringBetween(wemoCallResponse, "<fader>", "</fader>");
-                    if (value != null) {
-                        variable = "fader";
-                        logger.trace("New fader value '{}' for device '{}' received", value, getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
-                    }
+                    value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
+                    variable = "BinaryState";
+                    logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
+                    value = substringBetween(wemoCallResponse, "<brightness>", "</brightness>");
+                    variable = "brightness";
+                    logger.trace("New brightness '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
+                    value = substringBetween(wemoCallResponse, "<fader>", "</fader>");
+                    variable = "fader";
+                    logger.trace("New fader value '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
                 }
             }
         } catch (Exception e) {
@@ -494,38 +517,30 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
                 + "<s:Body>" + "<u:" + action + " xmlns:u=\"urn:Belkin:service:" + actionService + ":1\">" + "</u:"
                 + action + ">" + "</s:Body>" + "</s:Envelope>";
         try {
-            String wemoURL = getWemoURL(actionService);
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, "basicevent");
+
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
                     logger.trace("GetNightModeConfiguration response '{}' for device '{}' received", wemoCallResponse,
                             getThing().getUID());
-                    value = StringUtils.substringBetween(wemoCallResponse, "<startTime>", "</startTime>");
-                    if (value != null) {
-                        variable = "startTime";
-                        logger.trace("New startTime '{}' for device '{}' received", value, getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
-                    }
-                    value = StringUtils.substringBetween(wemoCallResponse, "<endTime>", "</endTime>");
-                    if (value != null) {
-                        variable = "endTime";
-                        logger.trace("New endTime '{}' for device '{}' received", value, getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
-                    }
-                    value = StringUtils.substringBetween(wemoCallResponse, "<nightMode>", "</nightMode>");
-                    if (value != null) {
-                        variable = "nightMode";
-                        logger.trace("New nightMode state '{}' for device '{}' received", value, getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
-                    }
-                    value = StringUtils.substringBetween(wemoCallResponse, "<nightModeBrightness>",
-                            "</nightModeBrightness>");
-                    if (value != null) {
-                        variable = "nightModeBrightness";
-                        logger.trace("New nightModeBrightness  '{}' for device '{}' received", value,
-                                getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
-                    }
+                    value = substringBetween(wemoCallResponse, "<startTime>", "</startTime>");
+                    variable = "startTime";
+                    logger.trace("New startTime '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
+                    value = substringBetween(wemoCallResponse, "<endTime>", "</endTime>");
+                    variable = "endTime";
+                    logger.trace("New endTime '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
+                    value = substringBetween(wemoCallResponse, "<nightMode>", "</nightMode>");
+                    variable = "nightMode";
+                    logger.trace("New nightMode state '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
+                    value = substringBetween(wemoCallResponse, "<nightModeBrightness>", "</nightModeBrightness>");
+                    variable = "nightModeBrightness";
+                    logger.trace("New nightModeBrightness  '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
                 }
             }
         } catch (Exception e) {
@@ -536,37 +551,19 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
         updateStatus(ThingStatus.ONLINE);
     }
 
-    public String getWemoURL(String actionService) {
-        URL descriptorURL = service.getDescriptorURL(this);
-        String wemoURL = null;
-        if (descriptorURL != null) {
-            String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml");
-            wemoURL = deviceURL + "/upnp/control/" + actionService + "1";
-            return wemoURL;
-        }
-        return null;
-    }
-
-    @SuppressWarnings("null")
-    public State getDateTimeState(String attributeValue) {
-        if (attributeValue != null) {
-            long value = 0;
-            try {
-                value = Long.parseLong(attributeValue) * 1000; // convert s to ms
-            } catch (NumberFormatException e) {
-                logger.warn("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue,
-                        getThing().getUID());
-                return null;
-            }
-            ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(value),
-                    TimeZone.getDefault().toZoneId());
-            State dateTimeState = new DateTimeType(zoned);
-            if (dateTimeState != null) {
-                logger.trace("New attribute '{}' received", dateTimeState);
-                return dateTimeState;
-            }
+    public @Nullable State getDateTimeState(String attributeValue) {
+        long value = 0;
+        try {
+            value = Long.parseLong(attributeValue);
+        } catch (NumberFormatException e) {
+            logger.error("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue,
+                    getThing().getUID());
+            return null;
         }
-        return null;
+        ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochSecond(value), TimeZone.getDefault().toZoneId());
+        State dateTimeState = new DateTimeType(zoned);
+        logger.trace("New attribute brewed '{}' received", dateTimeState);
+        return dateTimeState;
     }
 
     public void setBinaryState(String action, String argument, String value) {
@@ -576,10 +573,12 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
                     + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                     + "<s:Body>" + "<u:" + action + " xmlns:u=\"urn:Belkin:service:basicevent:1\">" + "<" + argument
                     + ">" + value + "</" + argument + ">" + "</u:" + action + ">" + "</s:Body>" + "</s:Envelope>";
-            String wemoURL = getWemoURL("basicevent");
+
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, "basicevent");
+
             if (wemoURL != null) {
-                logger.trace("About to send content to Dimmer {}", content);
-                wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                wemoCall.executeCall(wemoURL, soapHeader, content);
             }
         } catch (Exception e) {
             logger.debug("Failed to set binaryState '{}' for device '{}': {}", value, getThing().getUID(),
@@ -595,10 +594,12 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart
                     + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                     + "<s:Body>" + "<u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\">" + value
                     + "</u:SetBinaryState>" + "</s:Body>" + "</s:Envelope>";
-            String wemoURL = getWemoURL("basicevent");
+
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, "basicevent");
+
             if (wemoURL != null) {
-                logger.trace("About to send content to Dimmer {}", content);
-                wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                wemoCall.executeCall(wemoURL, soapHeader, content);
             }
         } catch (Exception e) {
             logger.debug("Failed to set binaryState '{}' for device '{}': {}", value, getThing().getUID(),
index d1fe489b7542715a3fa5e1cff46a42008b90fe2f..41a53c4deb5fb136d823d28d217c8aa26155825e 100644 (file)
@@ -13,8 +13,8 @@
 package org.openhab.binding.wemo.internal.handler;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
-import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.net.URL;
@@ -30,10 +30,10 @@ import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
-import org.openhab.core.io.net.http.HttpUtil;
 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
 import org.openhab.core.io.transport.upnp.UpnpIOService;
 import org.openhab.core.library.types.DateTimeType;
@@ -54,13 +54,13 @@ import org.slf4j.LoggerFactory;
  * The {@link WemoHandler} is responsible for handling commands, which are
  * sent to one of the channels and to update their states.
  *
- * @author Hans-Jörg Merk - Initial contribution; Added support for WeMo Insight energy measurement
+ * @author Hans-Jörg Merk - Initial contribution
  * @author Kai Kreuzer - some refactoring for performance and simplification
  * @author Stefan Bußweiler - Added new thing status handling
  * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType
  * @author Mihir Patil - Added standby switch
  */
-
+@NonNullByDefault
 public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoHandler.class);
@@ -73,16 +73,10 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
 
     private final Map<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
 
-    // protected static final int SUBSCRIPTION_DURATION = WemoBindingConstants.SUBSCRIPTION_DURATION;
-
-    private UpnpIOService service;
+    protected UpnpIOService service;
+    private WemoHttpCall wemoCall;
 
-    /**
-     * The default refresh interval in Seconds.
-     */
-    private final int DEFAULT_REFRESH_INTERVAL = 120;
-
-    private ScheduledFuture<?> refreshJob;
+    private @Nullable ScheduledFuture<?> refreshJob;
 
     private final Runnable refreshRunnable = new Runnable() {
 
@@ -102,18 +96,13 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
         }
     };
 
-    public WemoHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) {
-        super(thing);
+    public WemoHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
+        super(thing, wemoHttpCaller);
 
-        this.wemoHttpCaller = wemohttpCaller;
+        this.service = upnpIOService;
+        this.wemoCall = wemoHttpCaller;
 
         logger.debug("Creating a WemoHandler for thing '{}'", getThing().getUID());
-
-        if (upnpIOService != null) {
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
     }
 
     @Override
@@ -135,12 +124,12 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
     public void dispose() {
         logger.debug("WeMoHandler disposed.");
 
-        removeSubscription();
-
-        if (refreshJob != null && !refreshJob.isCancelled()) {
-            refreshJob.cancel(true);
-            refreshJob = null;
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        refreshJob = null;
+        removeSubscription();
     }
 
     @Override
@@ -172,10 +161,11 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
                             + "<BinaryState>" + binaryState + "</BinaryState>" + "</u:SetBinaryState>" + "</s:Body>"
                             + "</s:Envelope>";
 
-                    String wemoURL = getWemoURL("basicevent");
+                    URL descriptorURL = service.getDescriptorURL(this);
+                    String wemoURL = getWemoURL(descriptorURL, "basicevent");
 
                     if (wemoURL != null) {
-                        wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                        wemoCall.executeCall(wemoURL, soapHeader, content);
                     }
                 } catch (Exception e) {
                     logger.error("Failed to send command '{}' for device '{}': {}", command, getThing().getUID(),
@@ -188,20 +178,24 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
-        logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed");
-        subscriptionState.put(service, succeeded);
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
+        if (service != null) {
+            logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service,
+                    succeeded ? "succeeded" : "failed");
+            subscriptionState.put(service, succeeded);
+        }
     }
 
-    @SuppressWarnings("null")
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
         logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'",
                 new Object[] { variable, value, service, this.getThing().getUID() });
 
         updateStatus(ThingStatus.ONLINE);
 
-        this.stateMap.put(variable, value);
+        if (variable != null && value != null) {
+            this.stateMap.put(variable, value);
+        }
 
         if (getThing().getThingTypeUID().getId().equals("insight")) {
             String insightParams = stateMap.get("InsightParams");
@@ -212,11 +206,9 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
                 if (splitInsightParams[0] != null) {
                     OnOffType binaryState = null;
                     binaryState = splitInsightParams[0].equals("0") ? OnOffType.OFF : OnOffType.ON;
-                    if (binaryState != null) {
-                        logger.trace("New InsightParam binaryState '{}' for device '{}' received", binaryState,
-                                getThing().getUID());
-                        updateState(CHANNEL_STATE, binaryState);
-                    }
+                    logger.trace("New InsightParam binaryState '{}' for device '{}' received", binaryState,
+                            getThing().getUID());
+                    updateState(CHANNEL_STATE, binaryState);
                 }
 
                 long lastChangedAt = 0;
@@ -237,77 +229,57 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
                 }
 
                 State lastOnFor = DecimalType.valueOf(splitInsightParams[2]);
-                if (lastOnFor != null) {
-                    logger.trace("New InsightParam lastOnFor '{}' for device '{}' received", lastOnFor,
-                            getThing().getUID());
-                    updateState(CHANNEL_LASTONFOR, lastOnFor);
-                }
+                logger.trace("New InsightParam lastOnFor '{}' for device '{}' received", lastOnFor,
+                        getThing().getUID());
+                updateState(CHANNEL_LASTONFOR, lastOnFor);
 
                 State onToday = DecimalType.valueOf(splitInsightParams[3]);
-                if (onToday != null) {
-                    logger.trace("New InsightParam onToday '{}' for device '{}' received", onToday,
-                            getThing().getUID());
-                    updateState(CHANNEL_ONTODAY, onToday);
-                }
+                logger.trace("New InsightParam onToday '{}' for device '{}' received", onToday, getThing().getUID());
+                updateState(CHANNEL_ONTODAY, onToday);
 
                 State onTotal = DecimalType.valueOf(splitInsightParams[4]);
-                if (onTotal != null) {
-                    logger.trace("New InsightParam onTotal '{}' for device '{}' received", onTotal,
-                            getThing().getUID());
-                    updateState(CHANNEL_ONTOTAL, onTotal);
-                }
+                logger.trace("New InsightParam onTotal '{}' for device '{}' received", onTotal, getThing().getUID());
+                updateState(CHANNEL_ONTOTAL, onTotal);
 
                 State timespan = DecimalType.valueOf(splitInsightParams[5]);
-                if (timespan != null) {
-                    logger.trace("New InsightParam timespan '{}' for device '{}' received", timespan,
-                            getThing().getUID());
-                    updateState(CHANNEL_TIMESPAN, timespan);
-                }
+                logger.trace("New InsightParam timespan '{}' for device '{}' received", timespan, getThing().getUID());
+                updateState(CHANNEL_TIMESPAN, timespan);
 
                 State averagePower = DecimalType.valueOf(splitInsightParams[6]); // natively given in W
-                if (averagePower != null) {
-                    logger.trace("New InsightParam averagePower '{}' for device '{}' received", averagePower,
-                            getThing().getUID());
-                    updateState(CHANNEL_AVERAGEPOWER, averagePower);
-                }
+                logger.trace("New InsightParam averagePower '{}' for device '{}' received", averagePower,
+                        getThing().getUID());
+                updateState(CHANNEL_AVERAGEPOWER, averagePower);
 
                 BigDecimal currentMW = new BigDecimal(splitInsightParams[7]);
                 State currentPower = new DecimalType(currentMW.divide(new BigDecimal(1000), RoundingMode.HALF_UP)); // recalculate
                 // mW to W
-                if (currentPower != null) {
-                    logger.trace("New InsightParam currentPower '{}' for device '{}' received", currentPower,
-                            getThing().getUID());
-                    updateState(CHANNEL_CURRENTPOWER, currentPower);
-                }
+                logger.trace("New InsightParam currentPower '{}' for device '{}' received", currentPower,
+                        getThing().getUID());
+                updateState(CHANNEL_CURRENTPOWER, currentPower);
 
                 BigDecimal energyTodayMWMin = new BigDecimal(splitInsightParams[8]);
                 // recalculate mW-mins to Wh
                 State energyToday = new DecimalType(
                         energyTodayMWMin.divide(new BigDecimal(60000), RoundingMode.HALF_UP));
-                if (energyToday != null) {
-                    logger.trace("New InsightParam energyToday '{}' for device '{}' received", energyToday,
-                            getThing().getUID());
-                    updateState(CHANNEL_ENERGYTODAY, energyToday);
-                }
+                logger.trace("New InsightParam energyToday '{}' for device '{}' received", energyToday,
+                        getThing().getUID());
+                updateState(CHANNEL_ENERGYTODAY, energyToday);
 
                 BigDecimal energyTotalMWMin = new BigDecimal(splitInsightParams[9]);
                 // recalculate mW-mins to Wh
                 State energyTotal = new DecimalType(
                         energyTotalMWMin.divide(new BigDecimal(60000), RoundingMode.HALF_UP));
-                if (energyTotal != null) {
-                    logger.trace("New InsightParam energyTotal '{}' for device '{}' received", energyTotal,
-                            getThing().getUID());
-                    updateState(CHANNEL_ENERGYTOTAL, energyTotal);
-                }
+                logger.trace("New InsightParam energyTotal '{}' for device '{}' received", energyTotal,
+                        getThing().getUID());
+                updateState(CHANNEL_ENERGYTOTAL, energyTotal);
 
                 BigDecimal standByLimitMW = new BigDecimal(splitInsightParams[10]);
                 State standByLimit = new DecimalType(standByLimitMW.divide(new BigDecimal(1000), RoundingMode.HALF_UP)); // recalculate
                 // mW to W
-                if (standByLimit != null) {
-                    logger.trace("New InsightParam standByLimit '{}' for device '{}' received", standByLimit,
-                            getThing().getUID());
-                    updateState(CHANNEL_STANDBYLIMIT, standByLimit);
-                }
+                logger.trace("New InsightParam standByLimit '{}' for device '{}' received", standByLimit,
+                        getThing().getUID());
+                updateState(CHANNEL_STANDBYLIMIT, standByLimit);
+
                 if (currentMW.divide(new BigDecimal(1000), RoundingMode.HALF_UP).intValue() > standByLimitMW
                         .divide(new BigDecimal(1000), RoundingMode.HALF_UP).intValue()) {
                     updateState(CHANNEL_ONSTANDBY, OnOffType.OFF);
@@ -316,11 +288,10 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
                 }
             }
         } else {
-            State state = stateMap.get("BinaryState").equals("0") ? OnOffType.OFF : OnOffType.ON;
-
-            logger.debug("State '{}' for device '{}' received", state, getThing().getUID());
-
-            if (state != null) {
+            String binaryState = stateMap.get("BinaryState");
+            if (binaryState != null) {
+                State state = binaryState.equals("0") ? OnOffType.OFF : OnOffType.ON;
+                logger.debug("State '{}' for device '{}' received", state, getThing().getUID());
                 if (getThing().getThingTypeUID().getId().equals("motion")) {
                     updateState(CHANNEL_MOTIONDETECTION, state);
                     if (state.equals(OnOffType.ON)) {
@@ -341,19 +312,18 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
             ThingTypeUID thingTypeUID = thing.getThingTypeUID();
             String subscription = "basicevent1";
 
-            if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) == null) {
                 logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription);
-                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION);
+                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS);
                 subscriptionState.put(subscription, true);
             }
 
             if (thingTypeUID.equals(THING_TYPE_INSIGHT)) {
                 subscription = "insight1";
-                if ((subscriptionState.get(subscription) == null)
-                        || !subscriptionState.get(subscription).booleanValue()) {
+                if (subscriptionState.get(subscription) == null) {
                     logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(),
                             subscription);
-                    service.addSubscription(this, subscription, SUBSCRIPTION_DURATION);
+                    service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS);
                     subscriptionState.put(subscription, true);
                 }
             }
@@ -370,15 +340,14 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
             ThingTypeUID thingTypeUID = thing.getThingTypeUID();
             String subscription = "basicevent1";
 
-            if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) != null) {
                 logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription);
                 service.removeSubscription(this, subscription);
             }
 
             if (thingTypeUID.equals(THING_TYPE_INSIGHT)) {
                 subscription = "insight1";
-                if ((subscriptionState.get(subscription) != null)
-                        && subscriptionState.get(subscription).booleanValue()) {
+                if (subscriptionState.get(subscription) != null) {
                     logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription);
                     service.removeSubscription(this, subscription);
                 }
@@ -389,9 +358,10 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
     }
 
     private synchronized void onUpdate() {
-        if (refreshJob == null || refreshJob.isCancelled()) {
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
             Configuration config = getThing().getConfiguration();
-            int refreshInterval = DEFAULT_REFRESH_INTERVAL;
+            int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS;
             Object refreshConfig = config.get("refresh");
             if (refreshConfig != null) {
                 refreshInterval = ((BigDecimal) refreshConfig).intValue();
@@ -433,20 +403,20 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
                 + action + ">" + "</s:Body>" + "</s:Envelope>";
 
         try {
-            String wemoURL = getWemoURL(actionService);
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, actionService);
+
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
                     logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID());
                     if (variable.equals("InsightParams")) {
-                        value = StringUtils.substringBetween(wemoCallResponse, "<InsightParams>", "</InsightParams>");
+                        value = substringBetween(wemoCallResponse, "<InsightParams>", "</InsightParams>");
                     } else {
-                        value = StringUtils.substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
-                    }
-                    if (value != null) {
-                        logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
-                        this.onValueReceived(variable, value, actionService + "1");
+                        value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
                     }
+                    logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
+                    this.onValueReceived(variable, value, actionService + "1");
                 }
             }
         } catch (Exception e) {
@@ -454,43 +424,6 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan
         }
     }
 
-    public String getWemoURL(String actionService) {
-        URL descriptorURL = service.getDescriptorURL(this);
-        int portCheckStart = 49151;
-        int portCheckStop = 49157;
-        String wemoURL = null;
-        String host = null;
-        String port = null;
-        if (descriptorURL != null) {
-            host = StringUtils.substringBetween(descriptorURL.toString(), "://", ":");
-            for (int i = portCheckStart; i < portCheckStop; i++) {
-                try {
-                    boolean portFound = servicePing(host, i);
-                    if (portFound) {
-                        logger.trace("WeMo device {} responded at Port {}", getUDN(), i);
-                        port = String.valueOf(i);
-                        break;
-                    }
-                } catch (Exception e) {
-                }
-            }
-            wemoURL = "http://" + host + ":" + port + "/upnp/control/" + actionService + "1";
-            logger.trace("WeMo url {}", wemoURL);
-            return wemoURL;
-        }
-        return wemoURL;
-    }
-
-    public boolean servicePing(String host, int port) {
-        logger.trace("Ping WeMo device at '{}:{}'", host, port);
-        try {
-            HttpUtil.executeUrl("GET", "http://" + host + ":" + port, 250);
-        } catch (IOException e) {
-            return false;
-        }
-        return true;
-    }
-
     @Override
     public void onStatusChanged(boolean status) {
     }
index 0017e9395a4b994bae0aa07a76ed5705d4390602..52a8f9ca52ef6c23d2e93674518634bad0e5f07f 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.wemo.internal.handler;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
 import java.io.IOException;
 import java.io.StringReader;
@@ -29,8 +30,8 @@ import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
@@ -62,25 +63,22 @@ import org.xml.sax.SAXException;
  *
  * @author Hans-Jörg Merk - Initial contribution;
  */
-
+@NonNullByDefault
 public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoHolmesHandler.class);
 
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_PURIFIER);
 
-    /**
-     * The default refresh interval in Seconds.
-     */
-    private static final int DEFAULT_REFRESH_INTERVAL_SECONDS = 120;
     private static final int FILTER_LIFE_DAYS = 330;
     private static final int FILTER_LIFE_MINS = FILTER_LIFE_DAYS * 24 * 60;
     private final Map<String, Boolean> subscriptionState = new HashMap<>();
     private final Map<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
 
     private UpnpIOService service;
+    private WemoHttpCall wemoCall;
 
-    private ScheduledFuture<?> refreshJob;
+    private @Nullable ScheduledFuture<?> refreshJob;
 
     private final Runnable refreshRunnable = () -> {
         if (!isUpnpDeviceRegistered()) {
@@ -91,18 +89,13 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
         }
     };
 
-    public WemoHolmesHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) {
-        super(thing);
+    public WemoHolmesHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
+        super(thing, wemoHttpCaller);
 
-        this.wemoHttpCaller = wemohttpCaller;
+        this.service = upnpIOService;
+        this.wemoCall = wemoHttpCaller;
 
         logger.debug("Creating a WemoHolmesHandler for thing '{}'", getThing().getUID());
-
-        if (upnpIOService != null) {
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
     }
 
     @Override
@@ -124,12 +117,12 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
     public void dispose() {
         logger.debug("WemoHolmesHandler disposed.");
 
-        removeSubscription();
-
-        if (refreshJob != null && !refreshJob.isCancelled()) {
-            refreshJob.cancel(true);
-            refreshJob = null;
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        refreshJob = null;
+        removeSubscription();
     }
 
     @Override
@@ -243,10 +236,12 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
                     + "<attributeList>&lt;attribute&gt;&lt;name&gt;" + attribute + "&lt;/name&gt;&lt;value&gt;" + value
                     + "&lt;/value&gt;&lt;/attribute&gt;</attributeList>" + "</u:SetAttributes>" + "</s:Body>"
                     + "</s:Envelope>";
-            String wemoURL = getWemoURL("deviceevent");
+
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, "deviceevent");
 
             if (wemoURL != null) {
-                wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                wemoCall.executeCall(wemoURL, soapHeader, content);
             }
         } catch (RuntimeException e) {
             logger.debug("Failed to send command '{}' for device '{}':", command, getThing().getUID(), e);
@@ -256,18 +251,23 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
-        logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed");
-        subscriptionState.put(service, succeeded);
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
+        if (service != null) {
+            logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service,
+                    succeeded ? "succeeded" : "failed");
+            subscriptionState.put(service, succeeded);
+        }
     }
 
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
         logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", variable, value, service,
                 this.getThing().getUID());
 
         updateStatus(ThingStatus.ONLINE);
-        this.stateMap.put(variable, value);
+        if (variable != null && value != null) {
+            this.stateMap.put(variable, value);
+        }
     }
 
     private synchronized void onSubscription() {
@@ -276,9 +276,9 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
 
             String subscription = "basicevent1";
 
-            if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) == null) {
                 logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription);
-                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION);
+                service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS);
                 subscriptionState.put(subscription, true);
             }
 
@@ -294,7 +294,7 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
         if (service.isRegistered(this)) {
             String subscription = "basicevent1";
 
-            if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) {
+            if (subscriptionState.get(subscription) != null) {
                 logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription);
                 service.removeSubscription(this, subscription);
             }
@@ -305,11 +305,12 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
     }
 
     private synchronized void onUpdate() {
-        if (refreshJob == null || refreshJob.isCancelled()) {
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
             Configuration config = getThing().getConfiguration();
-            int refreshInterval = DEFAULT_REFRESH_INTERVAL_SECONDS;
+            int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS;
             Object refreshConfig = config.get("refresh");
-            refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVAL_SECONDS
+            refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVALL_SECONDS
                     : ((BigDecimal) refreshConfig).intValue();
             refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS);
         }
@@ -340,18 +341,19 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
                 + action + ">" + "</s:Body>" + "</s:Envelope>";
 
         try {
-            String wemoURL = getWemoURL(actionService);
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, actionService);
+
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
                     logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID());
 
-                    String stringParser = StringUtils.substringBetween(wemoCallResponse, "<attributeList>",
-                            "</attributeList>");
+                    String stringParser = substringBetween(wemoCallResponse, "<attributeList>", "</attributeList>");
 
                     // Due to Belkins bad response formatting, we need to run this twice.
-                    stringParser = StringEscapeUtils.unescapeXml(stringParser);
-                    stringParser = StringEscapeUtils.unescapeXml(stringParser);
+                    stringParser = unescapeXml(stringParser);
+                    stringParser = unescapeXml(stringParser);
 
                     logger.trace("AirPurifier response '{}' for device '{}' received", stringParser,
                             getThing().getUID());
@@ -557,17 +559,6 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart
         updateStatus(ThingStatus.ONLINE);
     }
 
-    public String getWemoURL(String actionService) {
-        URL descriptorURL = service.getDescriptorURL(this);
-        String wemoURL = null;
-        if (descriptorURL != null) {
-            String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml");
-            wemoURL = deviceURL + "/upnp/control/" + actionService + "1";
-            return wemoURL;
-        }
-        return null;
-    }
-
     public static String getCharacterDataFromElement(Element e) {
         Node child = e.getFirstChild();
         if (child instanceof CharacterData) {
index 59c0969680b7389ee4ff2f31fcc34bef8ace6e9a..3ed10f1f5170879c0f9610f46a5ccfb2f480f5a9 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.wemo.internal.handler;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
 import java.math.BigDecimal;
 import java.net.URL;
@@ -21,8 +22,8 @@ import java.util.Map;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
@@ -49,6 +50,7 @@ import org.slf4j.LoggerFactory;
  *
  * @author Hans-Jörg Merk - Initial contribution
  */
+@NonNullByDefault
 public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoLightHandler.class);
@@ -56,10 +58,11 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
     private Map<String, Boolean> subscriptionState = new HashMap<>();
 
     private UpnpIOService service;
+    private WemoHttpCall wemoCall;
 
-    private WemoBridgeHandler wemoBridgeHandler;
+    private @Nullable WemoBridgeHandler wemoBridgeHandler;
 
-    private String wemoLightID;
+    private @Nullable String wemoLightID;
 
     private int currentBrightness;
 
@@ -70,19 +73,12 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
 
     protected static final String SUBSCRIPTION = "bridge1";
 
-    protected static final int SUBSCRIPTION_DURATION = 600;
-
-    /**
-     * The default refresh interval in Seconds.
-     */
-    private final int DEFAULT_REFRESH_INTERVAL = 60;
-
     /**
      * The default refresh initial delay in Seconds.
      */
     private static final int DEFAULT_REFRESH_INITIAL_DELAY = 15;
 
-    private ScheduledFuture<?> refreshJob;
+    private @Nullable ScheduledFuture<?> refreshJob;
 
     private final Runnable refreshRunnable = new Runnable() {
 
@@ -103,16 +99,10 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
     };
 
     public WemoLightHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpcaller) {
-        super(thing);
+        super(thing, wemoHttpcaller);
 
-        this.wemoHttpCaller = wemoHttpcaller;
-
-        if (upnpIOService != null) {
-            logger.debug("UPnPIOService '{}'", upnpIOService);
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
+        this.service = upnpIOService;
+        this.wemoCall = wemoHttpcaller;
     }
 
     @Override
@@ -120,17 +110,13 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
         // initialize() is only called if the required parameter 'deviceID' is available
         wemoLightID = (String) getConfig().get(DEVICE_ID);
 
-        if (getBridge() != null) {
-            logger.debug("Initializing WemoLightHandler for LightID '{}'", wemoLightID);
-            if (getBridge().getStatus() == ThingStatus.ONLINE) {
-                updateStatus(ThingStatus.ONLINE);
-                onSubscription();
-                onUpdate();
-            } else {
-                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.BRIDGE_OFFLINE);
-            }
+        final Bridge bridge = getBridge();
+        if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) {
+            updateStatus(ThingStatus.ONLINE);
+            onSubscription();
+            onUpdate();
         } else {
-            updateStatus(ThingStatus.OFFLINE);
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.BRIDGE_OFFLINE);
         }
     }
 
@@ -142,10 +128,11 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
             onUpdate();
         } else {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.BRIDGE_OFFLINE);
-            if (refreshJob != null && !refreshJob.isCancelled()) {
-                refreshJob.cancel(true);
-                refreshJob = null;
+            ScheduledFuture<?> job = refreshJob;
+            if (job != null && !job.isCancelled()) {
+                job.cancel(true);
             }
+            refreshJob = null;
         }
     }
 
@@ -153,28 +140,26 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
     public void dispose() {
         logger.debug("WeMoLightHandler disposed.");
 
-        removeSubscription();
-
-        if (refreshJob != null && !refreshJob.isCancelled()) {
-            refreshJob.cancel(true);
-            refreshJob = null;
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        refreshJob = null;
+        removeSubscription();
     }
 
-    private synchronized WemoBridgeHandler getWemoBridgeHandler() {
-        if (this.wemoBridgeHandler == null) {
-            Bridge bridge = getBridge();
-            if (bridge == null) {
-                logger.error("Required bridge not defined for device {}.", wemoLightID);
-                return null;
-            }
-            ThingHandler handler = bridge.getHandler();
-            if (handler instanceof WemoBridgeHandler) {
-                this.wemoBridgeHandler = (WemoBridgeHandler) handler;
-            } else {
-                logger.debug("No available bridge handler found for {} bridge {} .", wemoLightID, bridge.getUID());
-                return null;
-            }
+    private synchronized @Nullable WemoBridgeHandler getWemoBridgeHandler() {
+        Bridge bridge = getBridge();
+        if (bridge == null) {
+            logger.error("Required bridge not defined for device {}.", wemoLightID);
+            return null;
+        }
+        ThingHandler handler = bridge.getHandler();
+        if (handler instanceof WemoBridgeHandler) {
+            this.wemoBridgeHandler = (WemoBridgeHandler) handler;
+        } else {
+            logger.debug("No available bridge handler found for {} bridge {} .", wemoLightID, bridge.getUID());
+            return null;
         }
         return this.wemoBridgeHandler;
     }
@@ -266,10 +251,11 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
                         + "&lt;/CapabilityValue&gt;&lt;/DeviceStatus&gt;" + "</DeviceStatusList>"
                         + "</u:SetDeviceStatus>" + "</s:Body>" + "</s:Envelope>";
 
-                String wemoURL = getWemoURL();
+                URL descriptorURL = service.getDescriptorURL(this);
+                String wemoURL = getWemoURL(descriptorURL, "bridge");
 
                 if (wemoURL != null && capability != null && value != null) {
-                    String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                    String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                     if (wemoCallResponse != null) {
                         if (capability.equals("10008")) {
                             OnOffType binaryState = null;
@@ -285,7 +271,7 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
     }
 
     @Override
-    public String getUDN() {
+    public @Nullable String getUDN() {
         WemoBridgeHandler wemoBridge = getWemoBridgeHandler();
         if (wemoBridge == null) {
             logger.debug("wemoBridgeHandler not found");
@@ -307,14 +293,14 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
                     + "<s:Body>" + "<u:GetDeviceStatus xmlns:u=\"urn:Belkin:service:bridge:1\">" + "<DeviceIDs>"
                     + wemoLightID + "</DeviceIDs>" + "</u:GetDeviceStatus>" + "</s:Body>" + "</s:Envelope>";
 
-            String wemoURL = getWemoURL();
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, "bridge");
 
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
-                    wemoCallResponse = StringEscapeUtils.unescapeXml(wemoCallResponse);
-                    String response = StringUtils.substringBetween(wemoCallResponse, "<CapabilityValue>",
-                            "</CapabilityValue>");
+                    wemoCallResponse = unescapeXml(wemoCallResponse);
+                    String response = substringBetween(wemoCallResponse, "<CapabilityValue>", "</CapabilityValue>");
                     logger.trace("wemoNewLightState = {}", response);
                     String[] splitResponse = response.split(",");
                     if (splitResponse[0] != null) {
@@ -341,15 +327,15 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
     }
 
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
         logger.trace("Received pair '{}':'{}' (service '{}') for thing '{}'",
                 new Object[] { variable, value, service, this.getThing().getUID() });
-        String capabilityId = StringUtils.substringBetween(value, "<CapabilityId>", "</CapabilityId>");
-        String newValue = StringUtils.substringBetween(value, "<Value>", "</Value>");
+        String capabilityId = substringBetween(value, "<CapabilityId>", "</CapabilityId>");
+        String newValue = substringBetween(value, "<Value>", "</Value>");
         switch (capabilityId) {
             case "10006":
                 OnOffType binaryState = null;
@@ -377,9 +363,9 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
         if (service.isRegistered(this)) {
             logger.debug("Checking WeMo GENA subscription for '{}'", this);
 
-            if ((subscriptionState.get(SUBSCRIPTION) == null) || !subscriptionState.get(SUBSCRIPTION).booleanValue()) {
+            if (subscriptionState.get(SUBSCRIPTION) == null) {
                 logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), SUBSCRIPTION);
-                service.addSubscription(this, SUBSCRIPTION, SUBSCRIPTION_DURATION);
+                service.addSubscription(this, SUBSCRIPTION, SUBSCRIPTION_DURATION_SECONDS);
                 subscriptionState.put(SUBSCRIPTION, true);
             }
         } else {
@@ -392,7 +378,7 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
         if (service.isRegistered(this)) {
             logger.debug("Removing WeMo GENA subscription for '{}'", this);
 
-            if ((subscriptionState.get(SUBSCRIPTION) != null) && subscriptionState.get(SUBSCRIPTION).booleanValue()) {
+            if (subscriptionState.get(SUBSCRIPTION) != null) {
                 logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), SUBSCRIPTION);
                 service.removeSubscription(this, SUBSCRIPTION);
             }
@@ -403,9 +389,10 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
     }
 
     private synchronized void onUpdate() {
-        if (refreshJob == null || refreshJob.isCancelled()) {
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
             Configuration config = getThing().getConfiguration();
-            int refreshInterval = DEFAULT_REFRESH_INTERVAL;
+            int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS;
             Object refreshConfig = config.get("refresh");
             if (refreshConfig != null) {
                 refreshInterval = ((BigDecimal) refreshConfig).intValue();
@@ -419,15 +406,4 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti
     private boolean isUpnpDeviceRegistered() {
         return service.isRegistered(this);
     }
-
-    public String getWemoURL() {
-        URL descriptorURL = service.getDescriptorURL(this);
-        String wemoURL = null;
-        if (descriptorURL != null) {
-            String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml");
-            wemoURL = deviceURL + "/upnp/control/bridge1";
-            return wemoURL;
-        }
-        return null;
-    }
 }
index c8ac1f286295d12a9dc015d4df396dfc4f681a30..f36314beb500fa949cebbbaa39192ec998f674c7 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.wemo.internal.handler;
 
 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+import static org.openhab.binding.wemo.internal.WemoUtil.*;
 
 import java.io.StringReader;
 import java.math.BigDecimal;
@@ -25,8 +26,8 @@ import java.util.concurrent.TimeUnit;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
@@ -55,7 +56,7 @@ import org.xml.sax.InputSource;
  *
  * @author Hans-Jörg Merk - Initial contribution
  */
-
+@NonNullByDefault
 public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParticipant {
 
     private final Logger logger = LoggerFactory.getLogger(WemoMakerHandler.class);
@@ -63,13 +64,9 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_MAKER);
 
     private UpnpIOService service;
+    private WemoHttpCall wemoCall;
 
-    /**
-     * The default refresh interval in Seconds.
-     */
-    private final int DEFAULT_REFRESH_INTERVAL = 15;
-
-    private ScheduledFuture<?> refreshJob;
+    private @Nullable ScheduledFuture<?> refreshJob;
 
     private final Runnable refreshRunnable = new Runnable() {
 
@@ -85,17 +82,12 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
     };
 
     public WemoMakerHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpcaller) {
-        super(thing);
+        super(thing, wemoHttpcaller);
 
-        this.wemoHttpCaller = wemoHttpcaller;
+        this.service = upnpIOService;
+        this.wemoCall = wemoHttpcaller;
 
         logger.debug("Creating a WemoMakerHandler for thing '{}'", getThing().getUID());
-
-        if (upnpIOService != null) {
-            this.service = upnpIOService;
-        } else {
-            logger.debug("upnpIOService not set.");
-        }
     }
 
     @Override
@@ -115,10 +107,11 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
     public void dispose() {
         logger.debug("WeMoMakerHandler disposed.");
 
-        if (refreshJob != null && !refreshJob.isCancelled()) {
-            refreshJob.cancel(true);
-            refreshJob = null;
+        ScheduledFuture<?> job = refreshJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
         }
+        refreshJob = null;
     }
 
     @Override
@@ -150,11 +143,11 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
                             + "<BinaryState>" + binaryState + "</BinaryState>" + "</u:SetBinaryState>" + "</s:Body>"
                             + "</s:Envelope>";
 
-                    String wemoURL = getWemoURL("basicevent");
+                    URL descriptorURL = service.getDescriptorURL(this);
+                    String wemoURL = getWemoURL(descriptorURL, "basicevent");
 
                     if (wemoURL != null) {
-                        @SuppressWarnings("unused")
-                        String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                        wemoCall.executeCall(wemoURL, soapHeader, content);
                     }
                 } catch (Exception e) {
                     logger.error("Failed to send command '{}' for device '{}' ", command, getThing().getUID(), e);
@@ -172,16 +165,15 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
     }
 
     private synchronized void onUpdate() {
-        if (service.isRegistered(this)) {
-            if (refreshJob == null || refreshJob.isCancelled()) {
-                Configuration config = getThing().getConfiguration();
-                int refreshInterval = DEFAULT_REFRESH_INTERVAL;
-                Object refreshConfig = config.get("refresh");
-                if (refreshConfig != null) {
-                    refreshInterval = ((BigDecimal) refreshConfig).intValue();
-                }
-                refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS);
+        ScheduledFuture<?> job = refreshJob;
+        if (job == null || job.isCancelled()) {
+            Configuration config = getThing().getConfiguration();
+            int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS;
+            Object refreshConfig = config.get("refresh");
+            if (refreshConfig != null) {
+                refreshInterval = ((BigDecimal) refreshConfig).intValue();
             }
+            refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS);
         }
     }
 
@@ -193,7 +185,6 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
     /**
      * The {@link updateWemoState} polls the actual state of a WeMo Maker.
      */
-    @SuppressWarnings("null")
     protected void updateWemoState() {
         String action = "GetAttributes";
         String actionService = "deviceevent";
@@ -205,18 +196,20 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
                 + action + ">" + "</s:Body>" + "</s:Envelope>";
 
         try {
-            String wemoURL = getWemoURL(actionService);
+            URL descriptorURL = service.getDescriptorURL(this);
+            String wemoURL = getWemoURL(descriptorURL, actionService);
+
             if (wemoURL != null) {
-                String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
+                String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content);
                 if (wemoCallResponse != null) {
                     try {
-                        String stringParser = StringUtils.substringBetween(wemoCallResponse, "<attributeList>",
-                                "</attributeList>");
+                        String stringParser = substringBetween(wemoCallResponse, "<attributeList>", "</attributeList>");
+                        logger.trace("Escaped Maker response for device '{}' :", getThing().getUID());
+                        logger.trace("'{}'", stringParser);
 
                         // Due to Belkins bad response formatting, we need to run this twice.
-                        stringParser = StringEscapeUtils.unescapeXml(stringParser);
-                        stringParser = StringEscapeUtils.unescapeXml(stringParser);
-
+                        stringParser = unescapeXml(stringParser);
+                        stringParser = unescapeXml(stringParser);
                         logger.trace("Maker response '{}' for device '{}' received", stringParser, getThing().getUID());
 
                         stringParser = "<data>" + stringParser + "</data>";
@@ -253,19 +246,15 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
                             switch (attributeName) {
                                 case "Switch":
                                     State relayState = attributeValue.equals("0") ? OnOffType.OFF : OnOffType.ON;
-                                    if (relayState != null) {
-                                        logger.debug("New relayState '{}' for device '{}' received", relayState,
-                                                getThing().getUID());
-                                        updateState(CHANNEL_RELAY, relayState);
-                                    }
+                                    logger.debug("New relayState '{}' for device '{}' received", relayState,
+                                            getThing().getUID());
+                                    updateState(CHANNEL_RELAY, relayState);
                                     break;
                                 case "Sensor":
                                     State sensorState = attributeValue.equals("1") ? OnOffType.OFF : OnOffType.ON;
-                                    if (sensorState != null) {
-                                        logger.debug("New sensorState '{}' for device '{}' received", sensorState,
-                                                getThing().getUID());
-                                        updateState(CHANNEL_SENSOR, sensorState);
-                                    }
+                                    logger.debug("New sensorState '{}' for device '{}' received", sensorState,
+                                            getThing().getUID());
+                                    updateState(CHANNEL_SENSOR, sensorState);
                                     break;
                             }
                         }
@@ -279,17 +268,6 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
         }
     }
 
-    public String getWemoURL(String actionService) {
-        URL descriptorURL = service.getDescriptorURL(this);
-        String wemoURL = null;
-        if (descriptorURL != null) {
-            String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml");
-            wemoURL = deviceURL + "/upnp/control/" + actionService + "1";
-            return wemoURL;
-        }
-        return null;
-    }
-
     public static String getCharacterDataFromElement(Element e) {
         Node child = e.getFirstChild();
         if (child instanceof CharacterData) {
@@ -304,10 +282,10 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti
     }
 
     @Override
-    public void onServiceSubscribed(String service, boolean succeeded) {
+    public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
     }
 
     @Override
-    public void onValueReceived(String variable, String value, String service) {
+    public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
     }
 }
index 54fe051f104d173b0b914e16bcad0591566f95c5..d7198aa9fb3c692ec703ae7da072e7d54f93a80c 100644 (file)
@@ -18,6 +18,8 @@ import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.Properties;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.wemo.internal.WemoBindingConstants;
 import org.openhab.core.io.net.http.HttpUtil;
 import org.slf4j.Logger;
@@ -28,12 +30,12 @@ import org.slf4j.LoggerFactory;
  *
  * @author Hans-Jörg Merk - Initial contribution
  */
-
+@NonNullByDefault
 public class WemoHttpCall {
 
     private final Logger logger = LoggerFactory.getLogger(WemoHttpCall.class);
 
-    public String executeCall(String wemoURL, String soapHeader, String content) {
+    public @Nullable String executeCall(String wemoURL, String soapHeader, String content) {
         try {
             Properties wemoHeaders = new Properties();
             wemoHeaders.setProperty("CONTENT-TYPE", WemoBindingConstants.HTTP_CALL_CONTENT_HEADER);
index 945e5c85f38090cd9c0042a6c70b3fe669820a6d..ce5a2f0375aa0a3db6e0d11e114b92f825137615 100644 (file)
@@ -48,8 +48,8 @@ import org.openhab.core.thing.ThingUID;
 public class WemoDiscoveryParticipantTest {
     UpnpDiscoveryParticipant participant = new WemoDiscoveryParticipant();
 
-    private final String DEVICE_UDN = GenericWemoOSGiTest.DEVICE_MANUFACTURER + "_3434xxx";
-    private final String DEVICE_FRIENDLY_NAME = "Wemo Test";
+    private static final String DEVICE_UDN = GenericWemoOSGiTest.DEVICE_MANUFACTURER + "_3434xxx";
+    private static final String DEVICE_FRIENDLY_NAME = "Wemo Test";
 
     RemoteDevice createUpnpDevice(String modelName)
             throws MalformedURLException, ValidationException, URISyntaxException {
index 2431d5f6a55c742636ace7bf67bdeacb5a5d1d02..efdd5c4e87bab1376f7987355e925bb10204134d 100644 (file)
@@ -28,10 +28,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.jupnp.model.ValidationException;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
 import org.openhab.binding.wemo.internal.WemoBindingConstants;
 import org.openhab.binding.wemo.internal.handler.WemoHandler;
-import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.binding.wemo.internal.test.GenericWemoOSGiTest;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
@@ -50,14 +48,14 @@ import org.openhab.core.types.RefreshType;
 public class WemoHandlerOSGiTest extends GenericWemoOSGiTest {
 
     // Thing information
-    private final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE;
-    private final String DEFAULT_TEST_CHANNEL_TYPE = "Switch";
-    private final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_SOCKET;
+    private static final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE;
+    private static final String DEFAULT_TEST_CHANNEL_TYPE = "Switch";
+    private static final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_SOCKET;
 
     // UPnP information
-    private final String MODEL_NAME = WemoBindingConstants.THING_TYPE_SOCKET.getId();
-    private final String SERVICE_ID = "basicevent";
-    private final String SERVICE_NUMBER = "1";
+    private static final String MODEL_NAME = WemoBindingConstants.THING_TYPE_SOCKET.getId();
+    private static final String SERVICE_ID = "basicevent";
+    private static final String SERVICE_NUMBER = "1";
 
     @BeforeEach
     public void setUp() throws IOException {
@@ -74,8 +72,7 @@ public class WemoHandlerOSGiTest extends GenericWemoOSGiTest {
             throws MalformedURLException, URISyntaxException, ValidationException {
         Command command = OnOffType.OFF;
 
-        WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall());
-        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller);
+        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE);
 
         waitForAssert(() -> {
             assertThat(thing.getStatus(), is(ThingStatus.ONLINE));
@@ -111,8 +108,7 @@ public class WemoHandlerOSGiTest extends GenericWemoOSGiTest {
             throws MalformedURLException, URISyntaxException, ValidationException {
         Command command = RefreshType.REFRESH;
 
-        WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall());
-        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller);
+        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE);
 
         waitForAssert(() -> {
             assertThat(thing.getStatus(), is(ThingStatus.ONLINE));
index 8c716a4cdc54496819e9d40a532b7751177b1e54..144fa25e62329811ca082855620247926d5a95fb 100644 (file)
@@ -40,23 +40,23 @@ import org.openhab.core.types.State;
  */
 public class WemoHandlerTest {
 
-    private final ThingTypeUID THING_TYPE = WemoBindingConstants.THING_TYPE_INSIGHT;
-    private final String THING_ID = "test";
+    private static final ThingTypeUID THING_TYPE = WemoBindingConstants.THING_TYPE_INSIGHT;
+    private static final String THING_ID = "test";
 
     private MockWemoHandler handler;
 
-    private final String SERVICE_ID = "insight";
-    private final String PARAMS_NAME = "InsightParams";
+    private static final String SERVICE_ID = "insight";
+    private static final String PARAMS_NAME = "InsightParams";
     private WemoInsightParams insightParams;
 
     /** Used for all tests, where expected value is time in seconds **/
-    private final int TIME_PARAM = 4702;
+    private static final int TIME_PARAM = 4702;
 
     /** Represents a state parameter, where 1 stays for ON and 0 stays for OFF **/
-    private final int STATE_PARAM = 1;
+    private static final int STATE_PARAM = 1;
 
     /** Represents power in Wats **/
-    private final int POWER_PARAM = 54;
+    private static final int POWER_PARAM = 54;
 
     private final Thing thing = mock(Thing.class);
 
index 74c87460434d9e1539d2d64cdf30fb632fe2bfcc..af7966b8c8dc6483e0add5c6d389b6e353fd6ac2 100644 (file)
@@ -28,10 +28,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.jupnp.model.ValidationException;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
 import org.openhab.binding.wemo.internal.WemoBindingConstants;
 import org.openhab.binding.wemo.internal.handler.WemoLightHandler;
-import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.binding.wemo.internal.test.GenericWemoLightOSGiTestParent;
 import org.openhab.core.library.types.IncreaseDecreaseType;
 import org.openhab.core.library.types.OnOffType;
@@ -154,8 +152,7 @@ public class WemoLightHandlerOSGiTest extends GenericWemoLightOSGiTestParent {
             String capitability) throws MalformedURLException, URISyntaxException, ValidationException {
         Thing bridge = createBridge(BRIDGE_TYPE_UID);
 
-        WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall());
-        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller);
+        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE);
 
         waitForAssert(() -> {
             assertThat(bridge.getStatus(), is(ThingStatus.ONLINE));
index aa4668c9801ca6c3405a18479c316619f22287ed..354c71a8b2fc463c2c421876a2482db5f50bc6a4 100644 (file)
@@ -28,10 +28,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.jupnp.model.ValidationException;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
 import org.openhab.binding.wemo.internal.WemoBindingConstants;
 import org.openhab.binding.wemo.internal.handler.WemoMakerHandler;
-import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.binding.wemo.internal.test.GenericWemoOSGiTest;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
@@ -51,14 +49,14 @@ import org.openhab.core.types.RefreshType;
 public class WemoMakerHandlerOSGiTest extends GenericWemoOSGiTest {
 
     // Specific Thing information
-    private final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_RELAY;
-    private final String DEFAULT_TEST_CHANNEL_TYPE = "Switch";
-    private final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MAKER;
+    private static final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_RELAY;
+    private static final String DEFAULT_TEST_CHANNEL_TYPE = "Switch";
+    private static final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MAKER;
 
     // Specific UpnP service information
-    private final String MODEL = THING_TYPE_UID.getId();
-    private final String BASIC_EVENT_SERVICE_ID = "basicevent";
-    private final String SERVICE_NUMBER = "1";
+    private static final String MODEL = THING_TYPE_UID.getId();
+    private static final String BASIC_EVENT_SERVICE_ID = "basicevent";
+    private static final String SERVICE_NUMBER = "1";
 
     @BeforeEach
     public void setUp() throws IOException {
@@ -75,8 +73,7 @@ public class WemoMakerHandlerOSGiTest extends GenericWemoOSGiTest {
             throws MalformedURLException, URISyntaxException, ValidationException {
         Command command = OnOffType.OFF;
 
-        WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall());
-        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller);
+        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE);
 
         waitForAssert(() -> {
             assertThat(thing.getStatus(), is(ThingStatus.ONLINE));
@@ -111,8 +108,7 @@ public class WemoMakerHandlerOSGiTest extends GenericWemoOSGiTest {
             throws MalformedURLException, URISyntaxException, ValidationException {
         Command command = RefreshType.REFRESH;
 
-        WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall());
-        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller);
+        Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE);
 
         waitForAssert(() -> {
             assertThat(thing.getStatus(), is(ThingStatus.ONLINE));
index db6207ed69e04b081cbdf9702f44092cf2033cbd..86e5a824cee3b1192dce07269b95948b56b4aaa6 100644 (file)
@@ -17,7 +17,6 @@ import static org.hamcrest.MatcherAssert.assertThat;
 
 import org.openhab.binding.wemo.internal.WemoBindingConstants;
 import org.openhab.binding.wemo.internal.handler.AbstractWemoHandler;
-import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.Channel;
@@ -42,19 +41,19 @@ import org.openhab.core.thing.type.ChannelKind;
 public class GenericWemoLightOSGiTestParent extends GenericWemoOSGiTest {
 
     // Thing information
-    protected ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MZ100;
-    protected ThingTypeUID BRIDGE_TYPE_UID = WemoBindingConstants.THING_TYPE_BRIDGE;
-    protected String WEMO_BRIDGE_ID = BRIDGE_TYPE_UID.getId();
-    protected String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE;
-    protected String DEFAULT_TEST_CHANNEL_TYPE = "Switch";
+    protected static final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MZ100;
+    protected static final ThingTypeUID BRIDGE_TYPE_UID = WemoBindingConstants.THING_TYPE_BRIDGE;
+    protected static final String WEMO_BRIDGE_ID = BRIDGE_TYPE_UID.getId();
+    protected static final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE;
+    protected static final String DEFAULT_TEST_CHANNEL_TYPE = "Switch";
 
-    private final String WEMO_LIGHT_ID = THING_TYPE_UID.getId();
+    private static final String WEMO_LIGHT_ID = THING_TYPE_UID.getId();
 
     // UPnP service information
-    protected String DEVICE_MODEL_NAME = WEMO_LIGHT_ID;
-    protected String SERVICE_ID = "bridge";
-    protected String SERVICE_NUMBER = "1";
-    protected String SERVLET_URL = DEVICE_CONTROL_PATH + SERVICE_ID + SERVICE_NUMBER;
+    protected static final String DEVICE_MODEL_NAME = WEMO_LIGHT_ID;
+    protected static final String SERVICE_ID = "bridge";
+    protected static final String SERVICE_NUMBER = "1";
+    protected static final String SERVLET_URL = DEVICE_CONTROL_PATH + SERVICE_ID + SERVICE_NUMBER;
 
     private Bridge bridge;
 
@@ -71,8 +70,7 @@ public class GenericWemoLightOSGiTestParent extends GenericWemoOSGiTest {
     }
 
     @Override
-    protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType,
-            WemoHttpCall wemoHttpCaller) {
+    protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType) {
         Configuration configuration = new Configuration();
         configuration.put(WemoBindingConstants.DEVICE_ID, WEMO_LIGHT_ID);
 
@@ -91,7 +89,6 @@ public class GenericWemoLightOSGiTestParent extends GenericWemoOSGiTest {
         ThingHandler handler = thing.getHandler();
         if (handler != null) {
             AbstractWemoHandler h = (AbstractWemoHandler) handler;
-            h.setWemoHttpCaller(wemoHttpCaller);
         }
 
         return thing;
index cf87e867b415623e154cf997140daf2c4c17fae4..82f640c23cf7f8ff513b48130137e624e1611c99 100644 (file)
@@ -37,8 +37,10 @@ import org.jupnp.model.types.DeviceType;
 import org.jupnp.model.types.ServiceId;
 import org.jupnp.model.types.ServiceType;
 import org.jupnp.model.types.UDN;
+import org.mockito.Mockito;
 import org.openhab.binding.wemo.internal.WemoBindingConstants;
-import org.openhab.binding.wemo.internal.handler.AbstractWemoHandler;
+import org.openhab.binding.wemo.internal.WemoHttpCallFactory;
+import org.openhab.binding.wemo.internal.WemoUtil;
 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.io.transport.upnp.UpnpIOService;
@@ -52,7 +54,6 @@ import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingRegistry;
 import org.openhab.core.thing.ThingTypeUID;
 import org.openhab.core.thing.ThingUID;
-import org.openhab.core.thing.binding.ThingHandler;
 import org.openhab.core.thing.binding.builder.ChannelBuilder;
 import org.openhab.core.thing.binding.builder.ThingBuilder;
 import org.openhab.core.thing.type.ChannelKind;
@@ -69,35 +70,39 @@ import org.openhab.core.thing.type.ChannelTypeUID;
  */
 public abstract class GenericWemoOSGiTest extends JavaOSGiTest {
 
-    public static MockUpnpService mockUpnpService;
     public static final String DEVICE_MANUFACTURER = "Belkin";
 
     // This port is included in the run configuration
-    private final int ORG_OSGI_SERVICE_HTTP_PORT = 9090;
+    private static final int ORG_OSGI_SERVICE_HTTP_PORT = 9090;
 
     // Thing information
-    protected String TEST_THING_ID = "TestThing";
+    protected static final String TEST_THING_ID = "TestThing";
 
     // UPnP Device information
-    public static String DEVICE_UDN = "Test-1_0-22124";
+    public static final String DEVICE_UDN = "Test-1_0-22124";
 
-    private final String DEVICE_TYPE = "Test";
-    private final int DEVICE_VERSION = 1;
-    private final String DEVICE_URL = "http://127.0.0.1:" + ORG_OSGI_SERVICE_HTTP_PORT;
-    private final String DEVICE_DESCRIPTION_PATH = "/setup.xml";
+    private static final String DEVICE_TYPE = "Test";
+    private static final int DEVICE_VERSION = 1;
+    private static final String DEVICE_URL = "http://127.0.0.1:" + ORG_OSGI_SERVICE_HTTP_PORT;
+    private static final String DEVICE_DESCRIPTION_PATH = "/setup.xml";
 
-    protected final String DEVICE_FRIENDLY_NAME = "WeMo Test";
-    protected final String DEVICE_CONTROL_PATH = "/upnp/control/";
-    protected final ChannelTypeUID DEFAULT_CHANNEL_TYPE_UID = new ChannelTypeUID(
+    protected static final String DEVICE_FRIENDLY_NAME = "WeMo Test";
+    protected static final String DEVICE_CONTROL_PATH = "/upnp/control/";
+    protected static final ChannelTypeUID DEFAULT_CHANNEL_TYPE_UID = new ChannelTypeUID(
             WemoBindingConstants.BINDING_ID + ":channelType");
 
     protected ManagedThingProvider managedThingProvider;
     protected UpnpIOService upnpIOService;
     protected ThingRegistry thingRegistry;
 
+    protected WemoHttpCall mockCaller;
+    protected MockUpnpService mockUpnpService;
+
     protected Thing thing;
 
     protected void setUpServices() throws IOException {
+        WemoUtil.serviceAvailableFunction = (host, port) -> true;
+
         // StorageService is required from the ManagedThingProvider
         VolatileStorageService volatileStorageService = new VolatileStorageService();
         registerService(volatileStorageService);
@@ -117,14 +122,17 @@ public abstract class GenericWemoOSGiTest extends JavaOSGiTest {
         upnpIOService = getService(UpnpIOService.class);
         assertThat(upnpIOService, is(notNullValue()));
 
+        mockCaller = Mockito.spy(new WemoHttpCall());
+        WemoHttpCallFactory wemoHttpCallFactory = () -> mockCaller;
+        registerService(wemoHttpCallFactory, WemoHttpCallFactory.class.getName());
+
         ChannelTypeProvider channelTypeProvider = mock(ChannelTypeProvider.class);
         when(channelTypeProvider.getChannelType(any(ChannelTypeUID.class), any(Locale.class))).thenReturn(
                 ChannelTypeBuilder.state(DEFAULT_CHANNEL_TYPE_UID, "label", CoreItemFactory.SWITCH).build());
         registerService(channelTypeProvider);
     }
 
-    protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType,
-            WemoHttpCall wemoHttpCaller) {
+    protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType) {
         Configuration configuration = new Configuration();
         configuration.put(WemoBindingConstants.UDN, DEVICE_UDN);
 
@@ -138,13 +146,6 @@ public abstract class GenericWemoOSGiTest extends JavaOSGiTest {
                 .build();
 
         managedThingProvider.add(thing);
-
-        ThingHandler handler = thing.getHandler();
-        if (handler != null) {
-            AbstractWemoHandler h = (AbstractWemoHandler) handler;
-            h.setWemoHttpCaller(wemoHttpCaller);
-        }
-
         return thing;
     }
 
@@ -153,8 +154,8 @@ public abstract class GenericWemoOSGiTest extends JavaOSGiTest {
         UDN udn = new UDN(DEVICE_UDN);
         URL deviceURL = new URL(DEVICE_URL + DEVICE_DESCRIPTION_PATH);
 
-        RemoteDeviceIdentity identity = new RemoteDeviceIdentity(udn, WemoBindingConstants.SUBSCRIPTION_DURATION,
-                deviceURL, new byte[1], null);
+        RemoteDeviceIdentity identity = new RemoteDeviceIdentity(udn,
+                WemoBindingConstants.SUBSCRIPTION_DURATION_SECONDS, deviceURL, new byte[1], null);
         DeviceType type = new DeviceType(DEVICE_MANUFACTURER, DEVICE_TYPE, DEVICE_VERSION);
 
         ManufacturerDetails manufacturerDetails = new ManufacturerDetails(DEVICE_MANUFACTURER);