Skip to content

Commit fdada9a

Browse files
authored
[wemo] add annotations and remove usage of apache.commons.* (openhab#9829)
* [wemo] add annotations and remove usage of apache.commons.* Also-by: Wouter Born <[email protected]> Signed-off-by: Hans-Jörg Merk <[email protected]>
1 parent 8521756 commit fdada9a

24 files changed

+905
-883
lines changed

bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoBindingConstants.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.util.stream.Collectors;
1818
import java.util.stream.Stream;
1919

20+
import org.eclipse.jdt.annotation.NonNullByDefault;
2021
import org.openhab.core.thing.ThingTypeUID;
2122

2223
/**
@@ -26,6 +27,7 @@
2627
* @author Hans-Jörg Merk - Initial contribution
2728
* @author Mihir Patil - Added standby switch
2829
*/
30+
@NonNullByDefault
2931
public class WemoBindingConstants {
3032

3133
public static final String BINDING_ID = "wemo";
@@ -109,8 +111,8 @@ public class WemoBindingConstants {
109111
public static final String UDN = "udn";
110112
public static final String DEVICE_ID = "deviceID";
111113
public static final String POLLINGINTERVALL = "pollingInterval";
112-
113-
public static final int SUBSCRIPTION_DURATION = 600;
114+
public static final int DEFAULT_REFRESH_INTERVALL_SECONDS = 60;
115+
public static final int SUBSCRIPTION_DURATION_SECONDS = 600;
114116
public static final int LINK_DISCOVERY_SERVICE_INITIAL_DELAY = 5;
115117
public static final String HTTP_CALL_CONTENT_HEADER = "text/xml; charset=utf-8";
116118

bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHandlerFactory.java

+72-62
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.Map;
2020
import java.util.Set;
2121

22+
import org.eclipse.jdt.annotation.NonNullByDefault;
23+
import org.eclipse.jdt.annotation.Nullable;
2224
import org.openhab.binding.wemo.internal.discovery.WemoLinkDiscoveryService;
2325
import org.openhab.binding.wemo.internal.handler.WemoBridgeHandler;
2426
import org.openhab.binding.wemo.internal.handler.WemoCoffeeHandler;
@@ -39,8 +41,11 @@
3941
import org.openhab.core.thing.binding.ThingHandler;
4042
import org.openhab.core.thing.binding.ThingHandlerFactory;
4143
import org.osgi.framework.ServiceRegistration;
44+
import org.osgi.service.component.annotations.Activate;
4245
import org.osgi.service.component.annotations.Component;
4346
import org.osgi.service.component.annotations.Reference;
47+
import org.osgi.service.component.annotations.ReferenceCardinality;
48+
import org.osgi.service.component.annotations.ReferencePolicy;
4449
import org.slf4j.Logger;
4550
import org.slf4j.LoggerFactory;
4651

@@ -51,86 +56,91 @@
5156
* @author Hans-Jörg Merk - Initial contribution
5257
* @author Kai Kreuzer - some refactoring for performance and simplification
5358
*/
59+
@NonNullByDefault
5460
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.wemo")
5561
public class WemoHandlerFactory extends BaseThingHandlerFactory {
5662

5763
private final Logger logger = LoggerFactory.getLogger(WemoHandlerFactory.class);
5864

59-
private UpnpIOService upnpIOService;
60-
6165
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = WemoBindingConstants.SUPPORTED_THING_TYPES;
6266

67+
private UpnpIOService upnpIOService;
68+
private @Nullable WemoHttpCallFactory wemoHttpCallFactory;
69+
6370
@Override
6471
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
6572
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
6673
}
6774

6875
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
6976

70-
@SuppressWarnings({ "null", "unused" })
71-
@Override
72-
protected ThingHandler createHandler(Thing thing) {
73-
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
74-
if (thingTypeUID != null) {
75-
logger.debug("Trying to create a handler for ThingType '{}", thingTypeUID);
76-
77-
WemoHttpCall wemoHttpcaller = new WemoHttpCall();
78-
79-
if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_BRIDGE)) {
80-
logger.debug("Creating a WemoBridgeHandler for thing '{}' with UDN '{}'", thing.getUID(),
81-
thing.getConfiguration().get(UDN));
82-
WemoBridgeHandler handler = new WemoBridgeHandler((Bridge) thing);
83-
registerDeviceDiscoveryService(handler, wemoHttpcaller);
84-
return handler;
85-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MAKER)) {
86-
logger.debug("Creating a WemoMakerHandler for thing '{}' with UDN '{}'", thing.getUID(),
87-
thing.getConfiguration().get(UDN));
88-
return new WemoMakerHandler(thing, upnpIOService, wemoHttpcaller);
89-
} else if (WemoBindingConstants.SUPPORTED_DEVICE_THING_TYPES.contains(thing.getThingTypeUID())) {
90-
logger.debug("Creating a WemoHandler for thing '{}' with UDN '{}'", thing.getUID(),
91-
thing.getConfiguration().get(UDN));
92-
return new WemoHandler(thing, upnpIOService, wemoHttpcaller);
93-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_COFFEE)) {
94-
logger.debug("Creating a WemoCoffeeHandler for thing '{}' with UDN '{}'", thing.getUID(),
95-
thing.getConfiguration().get(UDN));
96-
return new WemoCoffeeHandler(thing, upnpIOService, wemoHttpcaller);
97-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_DIMMER)) {
98-
logger.debug("Creating a WemoDimmerHandler for thing '{}' with UDN '{}'", thing.getUID(),
99-
thing.getConfiguration().get("udn"));
100-
return new WemoDimmerHandler(thing, upnpIOService, wemoHttpcaller);
101-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_CROCKPOT)) {
102-
logger.debug("Creating a WemoCockpotHandler for thing '{}' with UDN '{}'", thing.getUID(),
103-
thing.getConfiguration().get("udn"));
104-
return new WemoCrockpotHandler(thing, upnpIOService, wemoHttpcaller);
105-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_PURIFIER)) {
106-
logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
107-
thing.getConfiguration().get("udn"));
108-
return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
109-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HUMIDIFIER)) {
110-
logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
111-
thing.getConfiguration().get("udn"));
112-
return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
113-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HEATER)) {
114-
logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
115-
thing.getConfiguration().get("udn"));
116-
return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
117-
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MZ100)) {
118-
return new WemoLightHandler(thing, upnpIOService, wemoHttpcaller);
119-
} else {
120-
logger.warn("ThingHandler not found for {}", thingTypeUID);
121-
return null;
122-
}
123-
}
124-
return null;
77+
@Activate
78+
public WemoHandlerFactory(final @Reference UpnpIOService upnpIOService) {
79+
this.upnpIOService = upnpIOService;
12580
}
12681

127-
@Reference
128-
protected void setUpnpIOService(UpnpIOService upnpIOService) {
129-
this.upnpIOService = upnpIOService;
82+
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
83+
public void setWemoHttpCallFactory(WemoHttpCallFactory wemoHttpCallFactory) {
84+
this.wemoHttpCallFactory = wemoHttpCallFactory;
85+
}
86+
87+
public void unsetWemoHttpCallFactory(WemoHttpCallFactory wemoHttpCallFactory) {
88+
this.wemoHttpCallFactory = null;
13089
}
13190

132-
protected void unsetUpnpIOService(UpnpIOService upnpIOService) {
133-
this.upnpIOService = null;
91+
@Override
92+
protected @Nullable ThingHandler createHandler(Thing thing) {
93+
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
94+
logger.debug("Trying to create a handler for ThingType '{}", thingTypeUID);
95+
96+
WemoHttpCallFactory wemoHttpCallFactory = this.wemoHttpCallFactory;
97+
WemoHttpCall wemoHttpcaller = wemoHttpCallFactory == null ? new WemoHttpCall()
98+
: wemoHttpCallFactory.createHttpCall();
99+
100+
if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_BRIDGE)) {
101+
logger.debug("Creating a WemoBridgeHandler for thing '{}' with UDN '{}'", thing.getUID(),
102+
thing.getConfiguration().get(UDN));
103+
WemoBridgeHandler handler = new WemoBridgeHandler((Bridge) thing);
104+
registerDeviceDiscoveryService(handler, wemoHttpcaller);
105+
return handler;
106+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MAKER)) {
107+
logger.debug("Creating a WemoMakerHandler for thing '{}' with UDN '{}'", thing.getUID(),
108+
thing.getConfiguration().get(UDN));
109+
return new WemoMakerHandler(thing, upnpIOService, wemoHttpcaller);
110+
} else if (WemoBindingConstants.SUPPORTED_DEVICE_THING_TYPES.contains(thing.getThingTypeUID())) {
111+
logger.debug("Creating a WemoHandler for thing '{}' with UDN '{}'", thing.getUID(),
112+
thing.getConfiguration().get(UDN));
113+
return new WemoHandler(thing, upnpIOService, wemoHttpcaller);
114+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_COFFEE)) {
115+
logger.debug("Creating a WemoCoffeeHandler for thing '{}' with UDN '{}'", thing.getUID(),
116+
thing.getConfiguration().get(UDN));
117+
return new WemoCoffeeHandler(thing, upnpIOService, wemoHttpcaller);
118+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_DIMMER)) {
119+
logger.debug("Creating a WemoDimmerHandler for thing '{}' with UDN '{}'", thing.getUID(),
120+
thing.getConfiguration().get("udn"));
121+
return new WemoDimmerHandler(thing, upnpIOService, wemoHttpcaller);
122+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_CROCKPOT)) {
123+
logger.debug("Creating a WemoCockpotHandler for thing '{}' with UDN '{}'", thing.getUID(),
124+
thing.getConfiguration().get("udn"));
125+
return new WemoCrockpotHandler(thing, upnpIOService, wemoHttpcaller);
126+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_PURIFIER)) {
127+
logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
128+
thing.getConfiguration().get("udn"));
129+
return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
130+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HUMIDIFIER)) {
131+
logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
132+
thing.getConfiguration().get("udn"));
133+
return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
134+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HEATER)) {
135+
logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(),
136+
thing.getConfiguration().get("udn"));
137+
return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller);
138+
} else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MZ100)) {
139+
return new WemoLightHandler(thing, upnpIOService, wemoHttpcaller);
140+
} else {
141+
logger.warn("ThingHandler not found for {}", thingTypeUID);
142+
return null;
143+
}
134144
}
135145

136146
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright (c) 2010-2021 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.wemo.internal;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.openhab.binding.wemo.internal.http.WemoHttpCall;
17+
18+
/**
19+
* {@link WemoHttpCallFactory} creates {@WemoHttpCall}s.
20+
*
21+
* @author Wouter Born - Initial contribution
22+
*/
23+
@NonNullByDefault
24+
public interface WemoHttpCallFactory {
25+
26+
WemoHttpCall createHttpCall();
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/**
2+
* Copyright (c) 2010-2021 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.wemo.internal;
14+
15+
import java.io.IOException;
16+
import java.net.URL;
17+
import java.util.HashMap;
18+
import java.util.Map;
19+
import java.util.function.BiFunction;
20+
import java.util.regex.Matcher;
21+
import java.util.regex.Pattern;
22+
23+
import org.eclipse.jdt.annotation.NonNullByDefault;
24+
import org.eclipse.jdt.annotation.Nullable;
25+
import org.openhab.core.io.net.http.HttpUtil;
26+
27+
/**
28+
* {@link WemoUtil} implements some helper functions.
29+
*
30+
* @author Hans-Jörg Merk - Initial contribution
31+
*/
32+
@NonNullByDefault
33+
public class WemoUtil {
34+
35+
public static BiFunction<String, Integer, Boolean> serviceAvailableFunction = WemoUtil::servicePing;
36+
37+
public static String substringBefore(@Nullable String string, String pattern) {
38+
if (string != null) {
39+
int pos = string.indexOf(pattern);
40+
if (pos > 0) {
41+
return string.substring(0, pos);
42+
}
43+
}
44+
return "";
45+
}
46+
47+
public static String substringBetween(@Nullable String string, String begin, String end) {
48+
if (string != null) {
49+
int s = string.indexOf(begin);
50+
if (s != -1) {
51+
String result = string.substring(s + begin.length());
52+
return substringBefore(result, end);
53+
}
54+
}
55+
return "";
56+
}
57+
58+
public static String unescape(final String text) {
59+
StringBuilder result = new StringBuilder(text.length());
60+
int i = 0;
61+
int n = text.length();
62+
while (i < n) {
63+
char charAt = text.charAt(i);
64+
if (charAt != '&') {
65+
result.append(charAt);
66+
i++;
67+
} else {
68+
if (text.startsWith("&amp;", i)) {
69+
result.append('&');
70+
i += 5;
71+
} else if (text.startsWith("&apos;", i)) {
72+
result.append('\'');
73+
i += 6;
74+
} else if (text.startsWith("&quot;", i)) {
75+
result.append('"');
76+
i += 6;
77+
} else if (text.startsWith("&lt;", i)) {
78+
result.append('<');
79+
i += 4;
80+
} else if (text.startsWith("&gt;", i)) {
81+
result.append('>');
82+
i += 4;
83+
} else {
84+
i++;
85+
}
86+
}
87+
}
88+
return result.toString();
89+
}
90+
91+
public static String unescapeXml(final String xml) {
92+
Pattern xmlEntityRegex = Pattern.compile("&(#?)([^;]+);");
93+
// Unfortunately, Matcher requires a StringBuffer instead of a StringBuilder
94+
StringBuffer unescapedOutput = new StringBuffer(xml.length());
95+
96+
Matcher m = xmlEntityRegex.matcher(xml);
97+
Map<String, String> builtinEntities = null;
98+
String entity;
99+
String hashmark;
100+
String ent;
101+
int code;
102+
while (m.find()) {
103+
ent = m.group(2);
104+
hashmark = m.group(1);
105+
if ((hashmark != null) && (hashmark.length() > 0)) {
106+
code = Integer.parseInt(ent);
107+
entity = Character.toString((char) code);
108+
} else {
109+
// must be a non-numerical entity
110+
if (builtinEntities == null) {
111+
builtinEntities = buildBuiltinXMLEntityMap();
112+
}
113+
entity = builtinEntities.get(ent);
114+
if (entity == null) {
115+
// not a known entity - ignore it
116+
entity = "&" + ent + ';';
117+
}
118+
}
119+
m.appendReplacement(unescapedOutput, entity);
120+
}
121+
m.appendTail(unescapedOutput);
122+
123+
return unescapedOutput.toString();
124+
}
125+
126+
public static @Nullable String getWemoURL(URL descriptorURL, String actionService) {
127+
int portCheckStart = 49151;
128+
int portCheckStop = 49157;
129+
String port = null;
130+
String host = substringBetween(descriptorURL.toString(), "://", ":");
131+
for (int i = portCheckStart; i < portCheckStop; i++) {
132+
if (serviceAvailableFunction.apply(host, i)) {
133+
port = String.valueOf(i);
134+
break;
135+
}
136+
}
137+
return port == null ? null : "http://" + host + ":" + port + "/upnp/control/" + actionService + "1";
138+
}
139+
140+
private static boolean servicePing(String host, int port) {
141+
try {
142+
HttpUtil.executeUrl("GET", "http://" + host + ":" + port, 250);
143+
return true;
144+
} catch (IOException e) {
145+
return false;
146+
}
147+
}
148+
149+
private static Map<String, String> buildBuiltinXMLEntityMap() {
150+
Map<String, String> entities = new HashMap<String, String>(10);
151+
entities.put("lt", "<");
152+
entities.put("gt", ">");
153+
entities.put("amp", "&");
154+
entities.put("apos", "'");
155+
entities.put("quot", "\"");
156+
return entities;
157+
}
158+
}

0 commit comments

Comments
 (0)