From 92a7c6f8b58759d4d55508a76629967a4871b369 Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Tue, 26 May 2020 12:34:54 +0200 Subject: [PATCH] [tesla] Use CXF JAX-RS client builder, if available. (#7789) Signed-off-by: Kai Kreuzer --- .../tesla/internal/TeslaHandlerFactory.java | 44 ++++++++++++++++++- .../internal/handler/TeslaAccountHandler.java | 25 ++++++----- .../internal/handler/TeslaVehicleHandler.java | 20 ++++----- 3 files changed, 65 insertions(+), 24 deletions(-) diff --git a/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/TeslaHandlerFactory.java b/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/TeslaHandlerFactory.java index f1d3a2b2097ce..acdef688a93db 100644 --- a/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/TeslaHandlerFactory.java +++ b/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/TeslaHandlerFactory.java @@ -18,6 +18,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.ws.rs.client.ClientBuilder; + import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingTypeUID; @@ -27,6 +29,8 @@ import org.openhab.binding.tesla.internal.handler.TeslaAccountHandler; import org.openhab.binding.tesla.internal.handler.TeslaVehicleHandler; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; /** * The {@link TeslaHandlerFactory} is responsible for creating things and thing @@ -39,10 +43,26 @@ @Component(service = ThingHandlerFactory.class, configurationPid = "binding.tesla") public class TeslaHandlerFactory extends BaseThingHandlerFactory { + // TODO: Those constants are Jersey specific - once we move away from Jersey, + // this can be removed and the client builder creation simplified. + public static final String READ_TIMEOUT_JERSEY = "jersey.config.client.readTimeout"; + public static final String CONNECT_TIMEOUT_JERSEY = "jersey.config.client.connectTimeout"; + + public static final String READ_TIMEOUT = "http.receive.timeout"; + public static final String CONNECT_TIMEOUT = "http.connection.timeout"; + + private static final int EVENT_STREAM_CONNECT_TIMEOUT = 3000; + private static final int EVENT_STREAM_READ_TIMEOUT = 200000; + public static final Set SUPPORTED_THING_TYPES_UIDS = Stream .of(THING_TYPE_ACCOUNT, THING_TYPE_MODELS, THING_TYPE_MODEL3, THING_TYPE_MODELX, THING_TYPE_MODELY) .collect(Collectors.toSet()); + @Reference(cardinality = ReferenceCardinality.OPTIONAL) + private ClientBuilder injectedClientBuilder; + + private ClientBuilder clientBuilder; + @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); @@ -53,9 +73,29 @@ protected ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (thingTypeUID.equals(THING_TYPE_ACCOUNT)) { - return new TeslaAccountHandler((Bridge) thing); + return new TeslaAccountHandler((Bridge) thing, getClientBuilder().build()); } else { - return new TeslaVehicleHandler(thing); + return new TeslaVehicleHandler(thing, getClientBuilder()); + } + } + + private synchronized ClientBuilder getClientBuilder() { + if (clientBuilder == null) { + try { + clientBuilder = ClientBuilder.newBuilder(); + clientBuilder.property(CONNECT_TIMEOUT_JERSEY, EVENT_STREAM_CONNECT_TIMEOUT); + clientBuilder.property(READ_TIMEOUT_JERSEY, EVENT_STREAM_READ_TIMEOUT); + } catch (Exception e) { + // we seem to have no Jersey, so let's hope for an injected builder by CXF + if (this.injectedClientBuilder != null) { + clientBuilder = injectedClientBuilder; + clientBuilder.property(CONNECT_TIMEOUT, EVENT_STREAM_CONNECT_TIMEOUT); + clientBuilder.property(READ_TIMEOUT, EVENT_STREAM_READ_TIMEOUT); + } else { + throw new IllegalStateException("No JAX RS Client Builder available."); + } + } } + return clientBuilder; } } diff --git a/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaAccountHandler.java b/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaAccountHandler.java index 410dcf76f5b30..a094c9b420310 100644 --- a/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaAccountHandler.java +++ b/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaAccountHandler.java @@ -32,7 +32,6 @@ import javax.ws.rs.ProcessingException; import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.client.Entity; @@ -86,14 +85,13 @@ public class TeslaAccountHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(TeslaAccountHandler.class); // REST Client API variables - private final Client teslaClient = ClientBuilder.newClient(); - private final WebTarget teslaTarget = teslaClient.target(URI_OWNERS); - private final WebTarget tokenTarget = teslaTarget.path(URI_ACCESS_TOKEN); - final WebTarget vehiclesTarget = teslaTarget.path(API_VERSION).path(VEHICLES); - final WebTarget vehicleTarget = vehiclesTarget.path(PATH_VEHICLE_ID); - final WebTarget dataRequestTarget = vehicleTarget.path(PATH_DATA_REQUEST); - final WebTarget commandTarget = vehicleTarget.path(PATH_COMMAND); - final WebTarget wakeUpTarget = vehicleTarget.path(PATH_WAKE_UP); + private final WebTarget teslaTarget; + private final WebTarget tokenTarget; + WebTarget vehiclesTarget; // this cannot be marked final as it is used in the runnable + final WebTarget vehicleTarget; + final WebTarget dataRequestTarget; + final WebTarget commandTarget; + final WebTarget wakeUpTarget; // Threading and Job related variables protected ScheduledFuture connectJob; @@ -111,8 +109,15 @@ public class TeslaAccountHandler extends BaseBridgeHandler { private TokenResponse logonToken; private final Set vehicleListeners = new HashSet<>(); - public TeslaAccountHandler(Bridge bridge) { + public TeslaAccountHandler(Bridge bridge, Client teslaClient) { super(bridge); + this.teslaTarget = teslaClient.target(URI_OWNERS); + this.tokenTarget = teslaTarget.path(URI_ACCESS_TOKEN); + this.vehiclesTarget = teslaTarget.path(API_VERSION).path(VEHICLES); + this.vehicleTarget = vehiclesTarget.path(PATH_VEHICLE_ID); + this.dataRequestTarget = vehicleTarget.path(PATH_DATA_REQUEST); + this.commandTarget = vehicleTarget.path(PATH_COMMAND); + this.wakeUpTarget = vehicleTarget.path(PATH_WAKE_UP); } @Override diff --git a/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaVehicleHandler.java b/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaVehicleHandler.java index 8248103354159..2c450b06b93dc 100644 --- a/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaVehicleHandler.java +++ b/bundles/org.openhab.binding.tesla/src/main/java/org/openhab/binding/tesla/internal/handler/TeslaVehicleHandler.java @@ -86,13 +86,6 @@ */ public class TeslaVehicleHandler extends BaseThingHandler { - // TODO: Those constants are Jersey specific - once we move away from Jersey, - // this must be changed to https://stackoverflow.com/a/49736022 (assuming we have a JAX-RS 2.1 implementation). - public static final String READ_TIMEOUT = "jersey.config.client.readTimeout"; - public static final String CONNECT_TIMEOUT = "jersey.config.client.connectTimeout"; - - private static final int EVENT_STREAM_CONNECT_TIMEOUT = 3000; - private static final int EVENT_STREAM_READ_TIMEOUT = 200000; private static final int EVENT_STREAM_PAUSE = 5000; private static final int EVENT_TIMESTAMP_AGE_LIMIT = 3000; private static final int EVENT_TIMESTAMP_MAX_DELTA = 10000; @@ -136,7 +129,8 @@ public class TeslaVehicleHandler extends BaseThingHandler { protected TeslaAccountHandler account; protected QueueChannelThrottler stateThrottler; - protected Client eventClient = ClientBuilder.newClient(); + protected ClientBuilder clientBuilder; + protected Client eventClient; protected TeslaChannelSelectorProxy teslaChannelSelectorProxy = new TeslaChannelSelectorProxy(); protected Thread eventThread; protected ScheduledFuture fastStateJob; @@ -145,8 +139,9 @@ public class TeslaVehicleHandler extends BaseThingHandler { private final Gson gson = new Gson(); private final JsonParser parser = new JsonParser(); - public TeslaVehicleHandler(Thing thing) { + public TeslaVehicleHandler(Thing thing, ClientBuilder clientBuilder) { super(thing); + this.clientBuilder = clientBuilder; } @SuppressWarnings("null") @@ -218,7 +213,9 @@ public void dispose() { lock.unlock(); } - eventClient.close(); + if (eventClient != null) { + eventClient.close(); + } } /** @@ -991,8 +988,7 @@ protected boolean establishEventStream() { if (!isEstablished) { eventBufferedReader = null; - eventClient = ClientBuilder.newClient().property(CONNECT_TIMEOUT, EVENT_STREAM_CONNECT_TIMEOUT) - .property(READ_TIMEOUT, EVENT_STREAM_READ_TIMEOUT) + eventClient = clientBuilder.build() .register(new Authenticator((String) getConfig().get(CONFIG_USERNAME), vehicle.tokens[0])); eventTarget = eventClient.target(URI_EVENT).path(vehicle.vehicle_id + "/").queryParam("values", StringUtils.join(EventKeys.values(), ',', 1, EventKeys.values().length));