From 8a67d0ad94a2b400f09b4a1ec55d789b0807b396 Mon Sep 17 00:00:00 2001 From: Karel Goderis Date: Fri, 23 Jun 2023 20:53:03 +0200 Subject: [PATCH] Fix error handling + migrate to the injected JAX-RS ClientBuilder (#15096) Signed-off-by: Karel Goderis --- .../helios/internal/HeliosHandlerFactory.java | 18 ++++- .../internal/handler/HeliosHandler221.java | 68 +++++++++++++------ 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/HeliosHandlerFactory.java b/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/HeliosHandlerFactory.java index 03b448856..586b550cf 100644 --- a/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/HeliosHandlerFactory.java +++ b/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/HeliosHandlerFactory.java @@ -15,6 +15,9 @@ package org.openhab.binding.helios.internal; import static org.openhab.binding.helios.internal.HeliosBindingConstants.HELIOS_VARIO_IP_2_21_TYPE; import java.util.Set; +import java.util.concurrent.TimeUnit; + +import javax.ws.rs.client.ClientBuilder; import org.openhab.binding.helios.internal.handler.HeliosHandler221; import org.openhab.core.thing.Thing; @@ -22,7 +25,9 @@ import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; /** * The {@link HeliosHandlerFactory} is responsible for creating things and thing @@ -33,8 +38,19 @@ import org.osgi.service.component.annotations.Component; @Component(service = ThingHandlerFactory.class, configurationPid = "binding.helios") public class HeliosHandlerFactory extends BaseThingHandlerFactory { + private static final int EVENT_STREAM_CONNECT_TIMEOUT = 3; + private static final int EVENT_STREAM_READ_TIMEOUT = 200; private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(HELIOS_VARIO_IP_2_21_TYPE); + private final ClientBuilder clientBuilder; + + @Activate + public HeliosHandlerFactory(@Reference ClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder // + .connectTimeout(EVENT_STREAM_CONNECT_TIMEOUT, TimeUnit.SECONDS) + .readTimeout(EVENT_STREAM_READ_TIMEOUT, TimeUnit.SECONDS); + } + @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); @@ -45,7 +61,7 @@ public class HeliosHandlerFactory extends BaseThingHandlerFactory { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (thingTypeUID.equals(HELIOS_VARIO_IP_2_21_TYPE)) { - return new HeliosHandler221(thing); + return new HeliosHandler221(thing, clientBuilder); } return null; diff --git a/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/handler/HeliosHandler221.java b/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/handler/HeliosHandler221.java index b7f8c1f3a..7a88f0c15 100644 --- a/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/handler/HeliosHandler221.java +++ b/bundles/org.openhab.binding.helios/src/main/java/org/openhab/binding/helios/internal/handler/HeliosHandler221.java @@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; +import javax.ws.rs.ProcessingException; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.ClientRequestContext; @@ -122,6 +123,7 @@ public class HeliosHandler221 extends BaseThingHandler { // REST Client API variables private Client heliosClient; + private final ClientBuilder heliosClientBuilder; private WebTarget baseTarget; private WebTarget systemTarget; private WebTarget logTarget; @@ -139,8 +141,9 @@ public class HeliosHandler221 extends BaseThingHandler { private long logSubscriptionID = 0; - public HeliosHandler221(Thing thing) { + public HeliosHandler221(Thing thing, ClientBuilder heliosClientBuilder) { super(thing); + this.heliosClientBuilder = heliosClientBuilder; } @Override @@ -169,7 +172,7 @@ public class HeliosHandler221 extends BaseThingHandler { logger.error("An exception occurred while initialising the SSL context : '{}'", e1.getMessage(), e1); } - heliosClient = ClientBuilder.newBuilder().sslContext(sslContext).hostnameVerifier(new HostnameVerifier() { + heliosClient = heliosClientBuilder.sslContext(sslContext).hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { return true; @@ -177,19 +180,18 @@ public class HeliosHandler221 extends BaseThingHandler { }).build(); heliosClient.register(new Authenticator(username, password)); - baseTarget = heliosClient.target(BASE_URI); + baseTarget = heliosClient.target(BASE_URI.replace("{ip}", ipAddress)); systemTarget = baseTarget.path(SYSTEM_PATH); logTarget = baseTarget.path(LOG_PATH); switchTarget = baseTarget.path(SWITCH_PATH); Response response = null; try { - response = systemTarget.resolveTemplate("ip", ipAddress).resolveTemplate("cmd", INFO) - .request(MediaType.APPLICATION_JSON_TYPE).get(); - } catch (NullPointerException e) { + response = systemTarget.resolveTemplate("cmd", INFO).request(MediaType.APPLICATION_JSON_TYPE).get(); + } catch (ProcessingException e) { logger.debug("An exception occurred while fetching system info of the Helios IP Vario '{}' : '{}'", getThing().getUID().toString(), e.getMessage(), e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS); return; } @@ -241,6 +243,11 @@ public class HeliosHandler221 extends BaseThingHandler { @Override public void dispose() { logger.debug("Disposing the Helios IP Vario handler for '{}'.", getThing().getUID().toString()); + tearDown(); + } + + private void tearDown() { + logger.debug("Tearing down the Helios IP Vario handler for '{}'.", getThing().getUID().toString()); if (logSubscriptionID != 0) { unsubscribe(); @@ -711,7 +718,7 @@ public class HeliosHandler221 extends BaseThingHandler { protected Runnable resetRunnable = () -> { logger.debug("Resetting the Helios IP Vario handler for '{}'", getThing().getUID()); - dispose(); + tearDown(); initialize(); }; @@ -766,15 +773,26 @@ public class HeliosHandler221 extends BaseThingHandler { ThingBuilder thingBuilder = editThing(); ChannelTypeUID enablerUID = new ChannelTypeUID(BINDING_ID, SWITCH_ENABLER); ChannelTypeUID triggerUID = new ChannelTypeUID(BINDING_ID, SWITCH_TRIGGER); + ChannelUID activeSwitchChannelUID = new ChannelUID(getThing().getUID(), + "switch" + aSwitch.id + "active"); + ChannelUID switchChannelUID = new ChannelUID(getThing().getUID(), "switch" + aSwitch.id); - Channel channel = ChannelBuilder - .create(new ChannelUID(getThing().getUID(), "switch" + aSwitch.id + "active"), "Switch") - .withType(enablerUID).build(); - thingBuilder.withChannel(channel); - channel = ChannelBuilder - .create(new ChannelUID(getThing().getUID(), "switch" + aSwitch.id), "Switch") - .withType(triggerUID).build(); - thingBuilder.withChannel(channel); + if (this.getThing().getChannel(activeSwitchChannelUID) == null) { + logger.trace( + "Adding a channel with id '{}' to the Helios IP Vario '{}' for the switch with id '{}'", + activeSwitchChannelUID, getThing().getUID().toString(), aSwitch.id); + Channel channel = ChannelBuilder.create(activeSwitchChannelUID, "Switch").withType(enablerUID) + .build(); + thingBuilder.withChannel(channel); + } + if (this.getThing().getChannel(switchChannelUID) == null) { + logger.trace( + "Adding a channel with id '{}' to the Helios IP Vario '{}' for the switch with id '{}'", + switchChannelUID, getThing().getUID().toString(), aSwitch.id); + Channel channel = ChannelBuilder.create(switchChannelUID, "Switch").withType(triggerUID) + .build(); + thingBuilder.withChannel(channel); + } updateThing(thingBuilder.build()); } } @@ -788,14 +806,19 @@ public class HeliosHandler221 extends BaseThingHandler { getThing().getUID().toString(), aPort.port); ThingBuilder thingBuilder = editThing(); ChannelTypeUID triggerUID = new ChannelTypeUID(BINDING_ID, IO_TRIGGER); + ChannelUID ioChannelUID = new ChannelUID(getThing().getUID(), "io" + aPort.port); Map channelProperties = new HashMap<>(); channelProperties.put("type", aPort.type); - Channel channel = ChannelBuilder - .create(new ChannelUID(getThing().getUID(), "io" + aPort.port), "Switch").withType(triggerUID) - .withProperties(channelProperties).build(); - thingBuilder.withChannel(channel); + if (this.getThing().getChannel(ioChannelUID) == null) { + logger.trace( + "Adding a channel with id '{}' to the Helios IP Vario '{}' for the switch with id '{}'", + ioChannelUID.getId(), getThing().getUID().toString(), aPort.port); + Channel channel = ChannelBuilder.create(ioChannelUID, "Switch").withType(triggerUID) + .withProperties(channelProperties).build(); + thingBuilder.withChannel(channel); + } updateThing(thingBuilder.build()); } } @@ -979,6 +1002,11 @@ public class HeliosHandler221 extends BaseThingHandler { logger.trace("No events were retrieved"); } } + } catch (ProcessingException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + logger.trace("An underlying exception forced the Helios IP Vario to go offline : '{}'", + e.getMessage(), e); + scheduler.schedule(resetRunnable, RESET_INTERVAL, TimeUnit.SECONDS); } catch (Exception e) { logger.error("An exception occurred while processing an event : '{}'", e.getMessage(), e); }