From f717f8d6150dacddac0131bf304e1887140adddf Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Sun, 5 Dec 2021 05:20:20 -0500 Subject: [PATCH] [sleepiq] Use constructor injection for ClientBuilder (#11700) Fixes #11696 Signed-off-by: Mark Hilbush Signed-off-by: Andras Uhrin --- .../openhab/binding/sleepiq/api/SleepIQ.java | 10 +- .../binding/sleepiq/api/impl/SleepIQImpl.java | 152 ++++++------------ .../binding/sleepiq/api/model/TimeSince.java | 76 +++------ .../internal/SleepIQHandlerFactory.java | 13 +- .../internal/handler/SleepIQCloudHandler.java | 11 +- 5 files changed, 101 insertions(+), 161 deletions(-) diff --git a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java index dcb01b80f7040..5785b24f791e9 100644 --- a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java +++ b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java @@ -17,6 +17,8 @@ import java.util.List; +import javax.ws.rs.client.ClientBuilder; + import org.openhab.binding.sleepiq.api.impl.SleepIQImpl; import org.openhab.binding.sleepiq.api.model.Bed; import org.openhab.binding.sleepiq.api.model.FamilyStatus; @@ -29,8 +31,7 @@ * * @author Gregory Moyer */ -public interface SleepIQ -{ +public interface SleepIQ { /** * Login to the {@link Configuration configured} account. This method is not * required to be called before other methods because all methods must @@ -94,8 +95,7 @@ public interface SleepIQ * the configuration to use for the new instance * @return a concrete implementation of this interface */ - public static SleepIQ create(Configuration config) - { - return new SleepIQImpl(config); + public static SleepIQ create(Configuration config, ClientBuilder clientBuilder) { + return new SleepIQImpl(config, clientBuilder); } } diff --git a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java index 666eb93388d92..df1b85a387bd7 100644 --- a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java +++ b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java @@ -49,8 +49,7 @@ import org.openhab.binding.sleepiq.api.model.SleepersResponse; import org.openhab.binding.sleepiq.internal.GsonProvider; -public class SleepIQImpl extends AbstractClient implements SleepIQ -{ +public class SleepIQImpl extends AbstractClient implements SleepIQ { protected static final String PARAM_KEY = "_k"; protected static final String DATA_BED_ID = "bedId"; @@ -59,47 +58,36 @@ public class SleepIQImpl extends AbstractClient implements SleepIQ private volatile LoginInfo loginInfo; - public SleepIQImpl(Configuration config) - { + private final ClientBuilder clientBuilder; + + public SleepIQImpl(Configuration config, ClientBuilder clientBuilder) { this.config = config; + this.clientBuilder = clientBuilder; } @Override - public LoginInfo login() throws LoginException - { - if (loginInfo == null) - { - synchronized (this) - { - if (loginInfo == null) - { - Response response = getClient().target(config.getBaseUri()) - .path(Endpoints.login()) - .request(MediaType.APPLICATION_JSON_TYPE) - .put(Entity.json(new LoginRequest().withLogin(config.getUsername()) - .withPassword(config.getPassword()))); - - if (isUnauthorized(response)) - { + public LoginInfo login() throws LoginException { + if (loginInfo == null) { + synchronized (this) { + if (loginInfo == null) { + Response response = getClient().target(config.getBaseUri()).path(Endpoints.login()) + .request(MediaType.APPLICATION_JSON_TYPE).put(Entity.json(new LoginRequest() + .withLogin(config.getUsername()).withPassword(config.getPassword()))); + + if (isUnauthorized(response)) { throw new UnauthorizedException(response.readEntity(Failure.class)); } - if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) - { + if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) { throw new LoginException(response.readEntity(Failure.class)); } // add the received cookies to all future requests - getClient().register(new ClientRequestFilter() - { + getClient().register(new ClientRequestFilter() { @Override - public void filter(ClientRequestContext requestContext) throws IOException - { - List cookies = response.getCookies() - .values() - .stream() - .map(newCookie -> newCookie.toCookie()) - .collect(Collectors.toList()); + public void filter(ClientRequestContext requestContext) throws IOException { + List cookies = response.getCookies().values().stream() + .map(newCookie -> newCookie.toCookie()).collect(Collectors.toList()); requestContext.getHeaders().put("Cookie", cookies); } }); @@ -113,106 +101,76 @@ public void filter(ClientRequestContext requestContext) throws IOException } @Override - public List getBeds() - { + public List getBeds() { return getSessionResponse(this::getBedsResponse).readEntity(BedsResponse.class).getBeds(); } - protected Response getBedsResponse(Map data) throws LoginException - { + protected Response getBedsResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.bed()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.bed()).queryParam(PARAM_KEY, login.getKey()) + .request(MediaType.APPLICATION_JSON_TYPE).get(); } @Override - public List getSleepers() - { - return getSessionResponse(this::getSleepersResponse).readEntity(SleepersResponse.class) - .getSleepers(); + public List getSleepers() { + return getSessionResponse(this::getSleepersResponse).readEntity(SleepersResponse.class).getSleepers(); } - protected Response getSleepersResponse(Map data) throws LoginException - { + protected Response getSleepersResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.sleeper()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.sleeper()).queryParam(PARAM_KEY, login.getKey()) + .request(MediaType.APPLICATION_JSON_TYPE).get(); } @Override - public FamilyStatus getFamilyStatus() - { + public FamilyStatus getFamilyStatus() { return getSessionResponse(this::getFamilyStatusResponse).readEntity(FamilyStatus.class); } - protected Response getFamilyStatusResponse(Map data) throws LoginException - { + protected Response getFamilyStatusResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.bed()) - .path(Endpoints.familyStatus()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.bed()).path(Endpoints.familyStatus()) + .queryParam(PARAM_KEY, login.getKey()).request(MediaType.APPLICATION_JSON_TYPE).get(); } @Override - public PauseMode getPauseMode(String bedId) throws BedNotFoundException - { + public PauseMode getPauseMode(String bedId) throws BedNotFoundException { Map data = new HashMap<>(); data.put(DATA_BED_ID, bedId); Response response = getSessionResponse(this::getPauseModeResponse, data); - if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) - { + if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) { throw new BedNotFoundException(response.readEntity(Failure.class)); } return response.readEntity(PauseMode.class); } - protected Response getPauseModeResponse(Map data) throws LoginException - { + protected Response getPauseModeResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.bed()) - .path(data.get(DATA_BED_ID).toString()) - .path(Endpoints.pauseMode()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.bed()).path(data.get(DATA_BED_ID).toString()) + .path(Endpoints.pauseMode()).queryParam(PARAM_KEY, login.getKey()) + .request(MediaType.APPLICATION_JSON_TYPE).get(); } - protected boolean isUnauthorized(Response response) - { + protected boolean isUnauthorized(Response response) { return Status.UNAUTHORIZED.getStatusCode() == response.getStatusInfo().getStatusCode(); } - protected synchronized void resetLogin() - { + protected synchronized void resetLogin() { loginInfo = null; } - protected Response getSessionResponse(Request request) - { + protected Response getSessionResponse(Request request) { return getSessionResponse(request, Collections.emptyMap()); } - protected Response getSessionResponse(Request request, Map data) - { - try - { + protected Response getSessionResponse(Request request, Map data) { + try { Response response = request.execute(data); - if (isUnauthorized(response)) - { + if (isUnauthorized(response)) { // session timed out response.close(); resetLogin(); @@ -220,35 +178,27 @@ protected Response getSessionResponse(Request request, Map data) } return response; - } - catch (LoginException e) - { + } catch (LoginException e) { throw new RuntimeException(e.getMessage(), e); } } @Override - protected Client createClient() - { - ClientBuilder builder = ClientBuilder.newBuilder(); - + protected Client createClient() { // setup Gson (de)serialization GsonProvider gsonProvider = new GsonProvider<>(getGson()); - builder.register(gsonProvider); + clientBuilder.register(gsonProvider); // turn on logging if requested - if (config.isLogging()) - { - builder.register(new LoggingFilter(Logger.getLogger(SleepIQImpl.class.getName()), - true)); + if (config.isLogging()) { + clientBuilder.register(new LoggingFilter(Logger.getLogger(SleepIQImpl.class.getName()), true)); } - return builder.build(); + return clientBuilder.build(); } @FunctionalInterface - public static interface Request - { + public static interface Request { public Response execute(Map data) throws LoginException; } } diff --git a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java index 674e2ef7449d9..c6c8704861863 100644 --- a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java +++ b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java @@ -16,46 +16,37 @@ package org.openhab.binding.sleepiq.api.model; import java.time.Duration; -import java.time.format.DateTimeParseException; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class TimeSince -{ +public class TimeSince { private static final Pattern PATTERN = Pattern.compile("(([0-9]+) d )?([0-9]{2}):([0-9]{2}):([0-9]{2})", - Pattern.CASE_INSENSITIVE); + Pattern.CASE_INSENSITIVE); private Duration duration; - public Duration getDuration() - { + public Duration getDuration() { return duration; } - public void setDuration(Duration duration) - { + public void setDuration(Duration duration) { this.duration = duration == null ? null : duration.abs(); } - public TimeSince withDuration(long days, long hours, long minutes, long seconds) - { - return withDuration(Duration.ofSeconds(TimeUnit.DAYS.toSeconds(days) - + TimeUnit.HOURS.toSeconds(hours) - + TimeUnit.MINUTES.toSeconds(minutes) - + seconds)); + public TimeSince withDuration(long days, long hours, long minutes, long seconds) { + return withDuration(Duration.ofSeconds(TimeUnit.DAYS.toSeconds(days) + TimeUnit.HOURS.toSeconds(hours) + + TimeUnit.MINUTES.toSeconds(minutes) + seconds)); } - public TimeSince withDuration(Duration duration) - { + public TimeSince withDuration(Duration duration) { setDuration(duration); return this; } @Override - public int hashCode() - { + public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((duration == null) ? 0 : duration.hashCode()); @@ -63,38 +54,29 @@ public int hashCode() } @Override - public boolean equals(Object obj) - { - if (this == obj) - { + public boolean equals(Object obj) { + if (this == obj) { return true; } - if (obj == null) - { + if (obj == null) { return false; } - if (!(obj instanceof TimeSince)) - { + if (!(obj instanceof TimeSince)) { return false; } - TimeSince other = (TimeSince)obj; - if (duration == null) - { - if (other.duration != null) - { + TimeSince other = (TimeSince) obj; + if (duration == null) { + if (other.duration != null) { return false; } - } - else if (!duration.equals(other.duration)) - { + } else if (!duration.equals(other.duration)) { return false; } return true; } @Override - public String toString() - { + public String toString() { long totalDays = duration.toDays(); long totalHours = duration.toHours(); long totalMinutes = duration.toMinutes(); @@ -104,22 +86,19 @@ public String toString() long minutes = totalMinutes - TimeUnit.HOURS.toMinutes(totalHours); long seconds = totalSeconds - TimeUnit.MINUTES.toSeconds(totalMinutes); - if (totalDays > 0) - { + if (totalDays > 0) { return String.format("%d d %02d:%02d:%02d", totalDays, hours, minutes, seconds); } return String.format("%02d:%02d:%02d", hours, minutes, seconds); } - public static TimeSince parse(CharSequence text) - { + public static TimeSince parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); - if (!matcher.matches()) - { - throw new DateTimeParseException("Text cannot be parsed", text, 0); + if (!matcher.matches()) { + return new TimeSince().withDuration(Duration.ZERO); } String dayMatch = matcher.group(2); @@ -128,17 +107,10 @@ public static TimeSince parse(CharSequence text) String secondMatch = matcher.group(5); StringBuilder sb = new StringBuilder("P"); - if (dayMatch != null) - { + if (dayMatch != null) { sb.append(dayMatch).append('D'); } - sb.append('T') - .append(hourMatch) - .append('H') - .append(minuteMatch) - .append('M') - .append(secondMatch) - .append('S'); + sb.append('T').append(hourMatch).append('H').append(minuteMatch).append('M').append(secondMatch).append('S'); return new TimeSince().withDuration(Duration.parse(sb.toString())); } diff --git a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java index 67ff44666fa7c..6717c178e63ca 100644 --- a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java +++ b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java @@ -20,6 +20,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.ws.rs.client.ClientBuilder; + import org.openhab.binding.sleepiq.internal.discovery.SleepIQBedDiscoveryService; import org.openhab.binding.sleepiq.internal.handler.SleepIQCloudHandler; import org.openhab.binding.sleepiq.internal.handler.SleepIQDualBedHandler; @@ -32,7 +34,9 @@ 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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,8 +53,15 @@ public class SleepIQHandlerFactory extends BaseThingHandlerFactory { private final Logger logger = LoggerFactory.getLogger(SleepIQHandlerFactory.class); + private final ClientBuilder clientBuilder; + private final Map> discoveryServiceReg = new HashMap<>(); + @Activate + public SleepIQHandlerFactory(@Reference ClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder; + } + @Override public boolean supportsThingType(final ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID); @@ -62,7 +73,7 @@ protected ThingHandler createHandler(final Thing thing) { if (SleepIQCloudHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) { logger.debug("Creating SleepIQ cloud thing handler"); - SleepIQCloudHandler cloudHandler = new SleepIQCloudHandler((Bridge) thing); + SleepIQCloudHandler cloudHandler = new SleepIQCloudHandler((Bridge) thing, clientBuilder); registerBedDiscoveryService(cloudHandler); return cloudHandler; } else if (SleepIQDualBedHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) { diff --git a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java index 1b8a4bf558098..1fcc2fb3650ab 100644 --- a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java +++ b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java @@ -25,6 +25,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import javax.ws.rs.client.ClientBuilder; + import org.openhab.binding.sleepiq.api.Configuration; import org.openhab.binding.sleepiq.api.LoginException; import org.openhab.binding.sleepiq.api.SleepIQ; @@ -67,8 +69,11 @@ public class SleepIQCloudHandler extends ConfigStatusBridgeHandler { private SleepIQ cloud; - public SleepIQCloudHandler(final Bridge bridge) { + private ClientBuilder clientBuilder; + + public SleepIQCloudHandler(final Bridge bridge, ClientBuilder clientBuilder) { super(bridge); + this.clientBuilder = clientBuilder; } @Override @@ -100,6 +105,8 @@ public void initialize() { /** * Create a new SleepIQ cloud service connection. If a connection already exists, it will be lost. * + * @param clientBuilder2 + * * @throws LoginException if there is an error while authenticating to the service */ private void createCloudConnection() throws LoginException { @@ -109,7 +116,7 @@ private void createCloudConnection() throws LoginException { logger.debug("Creating SleepIQ client"); Configuration cloudConfig = new Configuration().withUsername(bindingConfig.username) .withPassword(bindingConfig.password).withLogging(logger.isDebugEnabled()); - cloud = SleepIQ.create(cloudConfig); + cloud = SleepIQ.create(cloudConfig, clientBuilder); logger.debug("Authenticating at the SleepIQ cloud service"); cloud.login();