From 028e0733f04fc4a5cdb376c49e6698c96ef5dcd8 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sun, 31 Dec 2023 12:56:18 +0100 Subject: [PATCH 1/7] New ThingHandlerService documentation --- developers/bindings/index.md | 44 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/developers/bindings/index.md b/developers/bindings/index.md index 29d1beeb67..b18fb3fe88 100644 --- a/developers/bindings/index.md +++ b/developers/bindings/index.md @@ -571,9 +571,11 @@ If you implement the `ThingActions` interface, you can tell the framework about Please note that for actions not related to Things you will instead implement an `ActionHandler` as described in the developing [Module Types](../module-types/) chapter. -You start things off by implementing `ThingActions` and annotate your class with `@ThingActionsScope`: +You start things off by implementing `ThingActions` and annotate your class with `@ThingActionsScope`. +Since a new service is required for each thing, the component needs to be a `PROTOTYPE`: ```java +@Component(scope = ServiceScope.PROTOTYPE, service = MQTTActions.class) @ThingActionsScope(name = "mqtt") // Your bindings id is usually the scope @NonNullByDefault public class MQTTActions implements ThingActions { @@ -976,41 +978,45 @@ Here the developer only needs to implement four simple methods: When the discovery process is dependent on a configured bridge the discovery service must be bound to the bridge handler. Binding additional services to a handler can be achieved by implementing the service as a `ThingHandlerService`. -Instead of using the Component annotation your discovery service implements the `ThingHandlerService`. -It should extend the `AbstractDiscoveryService` (which implements `DiscoveryService`) just like a normal service: +It should extend the `AbstractThingHandlerDiscoveryService` (which implements `ThingHandlerService`and `DiscoveryService`) just like a normal service. +Since a new service is created for each thing, it has to be a `PROTOTYPE` component: + ```java -public class extends AbstractDiscoveryService - implements ThingHandlerService { +@Component(scope = ServiceScope.PROTOTYPE, service = YourBindingDiscoveryService.class) +public class extends AbstractThingHandlerDiscoveryService { ``` -The interface `ThingHandlerService` has 2 methods to pass the handler of the bridge. -A typical implementation is: +In the class there is a field `protected YourBridgeHandler thingHandler;` which is automatically assigned. +This field is guaranteed to be non-null after the service has been activated. + +During service creation, first `activate()` is called, then the `thingHandler` is injected and finally ìnitialize() is called. +The opposite order is used when the service is destroyed, first `dispose()` is called (when the thing handler is still available in the service), then `deactivate`. +`initialize()` and `dispose()` take care of background discovery. + +If you need additional code for initializing / disposing the discovery service, you can place them in the `initialize()` / `dispose()` methods. +To ensure everything is working correctly, you should call `super.initialize()` AFTER your own code and `super.dispose()` BEFORE your own code. + +The `thingHandler` can be used to get the bridge UID or to get access to the configured device connected to the bridge handler. +Fields set in `activate()` or `initialize()` can be regarded as "injected" and therefore be annotated with `@NonNullByDefault({})`. ```java - @Override - public void setThingHandler(@Nullable ThingHandler handler) { - if (handler instanceof ) { - bridgeHandler = () handler; - } - } + private @NonNullByDefault({}) ThingUID bridgeUid; @Override - public @Nullable ThingHandler getThingHandler() { - return bridgeHandler; + public void initialize() { + bridgeUid = thingHandler.getThing().getUID(); + super.initialize(); } ``` -The `setThingHandler` is called by the openHAB framework and give you access to the binding bridge handler. -The handler can be used to get the bridge UID or to get access to the configured device connected to the bridge handler. - In the bridge handler you need to activate the thing handler service. This is done by implementing the `getServices` method in your bridge handler: ```java @Override public Collection> getServices() { - return Collections.singleton(.class); + return Collections.singleton(YourBindingDiscoveryService.class); } ``` From 7e5aa44f2570d1d002671a099ed8863ed74be36d Mon Sep 17 00:00:00 2001 From: J-N-K Date: Tue, 2 Jan 2024 12:39:36 +0100 Subject: [PATCH 2/7] Update developers/bindings/index.md Co-authored-by: Wouter Born Signed-off-by: J-N-K --- developers/bindings/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developers/bindings/index.md b/developers/bindings/index.md index b18fb3fe88..557493dc78 100644 --- a/developers/bindings/index.md +++ b/developers/bindings/index.md @@ -1016,7 +1016,7 @@ This is done by implementing the `getServices` method in your bridge handler: ```java @Override public Collection> getServices() { - return Collections.singleton(YourBindingDiscoveryService.class); + return List.of(YourBindingDiscoveryService.class); } ``` From 4793e1e38c916a92ae0d24b4a785478f24907e4e Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Tue, 2 Jan 2024 12:42:39 +0100 Subject: [PATCH 3/7] improvement --- developers/bindings/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/developers/bindings/index.md b/developers/bindings/index.md index 557493dc78..003b1f21fb 100644 --- a/developers/bindings/index.md +++ b/developers/bindings/index.md @@ -596,7 +596,7 @@ public class MyThingHandler extends BaseThingHandler { ... @Override public Collection> getServices() { - return Collections.singleton(MQTTActions.class); + return List.of(MQTTActions.class); } } ``` @@ -981,7 +981,6 @@ Binding additional services to a handler can be achieved by implementing the ser It should extend the `AbstractThingHandlerDiscoveryService` (which implements `ThingHandlerService`and `DiscoveryService`) just like a normal service. Since a new service is created for each thing, it has to be a `PROTOTYPE` component: - ```java @Component(scope = ServiceScope.PROTOTYPE, service = YourBindingDiscoveryService.class) public class extends AbstractThingHandlerDiscoveryService { From 93b0384cd5e7b6b1f296200e1ab7c3304e103624 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Tue, 2 Jan 2024 12:53:11 +0100 Subject: [PATCH 4/7] improvement Signed-off-by: Jan N. Klug --- developers/bindings/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developers/bindings/index.md b/developers/bindings/index.md index 003b1f21fb..fcf347d52e 100644 --- a/developers/bindings/index.md +++ b/developers/bindings/index.md @@ -875,7 +875,7 @@ public class HueBridgeDiscoveryParticipant implements UpnpDiscoveryParticipant { @Override public Set getSupportedThingTypeUIDs() { - return Collections.singleton(THING_TYPE_BRIDGE); + return Set.of(THING_TYPE_BRIDGE); } @Override From 52566d584c84ad4dda85de28b1065100fc0b16c4 Mon Sep 17 00:00:00 2001 From: J-N-K Date: Wed, 3 Jan 2024 14:40:43 +0100 Subject: [PATCH 5/7] Update developers/bindings/index.md Co-authored-by: Wouter Born Signed-off-by: J-N-K --- developers/bindings/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developers/bindings/index.md b/developers/bindings/index.md index fcf347d52e..fc48fcbd60 100644 --- a/developers/bindings/index.md +++ b/developers/bindings/index.md @@ -989,7 +989,7 @@ public class extends AbstractThingHandlerDiscovery In the class there is a field `protected YourBridgeHandler thingHandler;` which is automatically assigned. This field is guaranteed to be non-null after the service has been activated. -During service creation, first `activate()` is called, then the `thingHandler` is injected and finally ìnitialize() is called. +During service creation, first `activate()` is called, then the `thingHandler` is injected and finally `ìnitialize()` is called. The opposite order is used when the service is destroyed, first `dispose()` is called (when the thing handler is still available in the service), then `deactivate`. `initialize()` and `dispose()` take care of background discovery. From aa5ec5fd5ac1678ebbc31b094ea411ca55c44c42 Mon Sep 17 00:00:00 2001 From: J-N-K Date: Wed, 3 Jan 2024 14:40:57 +0100 Subject: [PATCH 6/7] Update developers/bindings/index.md Co-authored-by: Wouter Born Signed-off-by: J-N-K --- developers/bindings/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developers/bindings/index.md b/developers/bindings/index.md index fc48fcbd60..b1e9b1b97a 100644 --- a/developers/bindings/index.md +++ b/developers/bindings/index.md @@ -978,7 +978,7 @@ Here the developer only needs to implement four simple methods: When the discovery process is dependent on a configured bridge the discovery service must be bound to the bridge handler. Binding additional services to a handler can be achieved by implementing the service as a `ThingHandlerService`. -It should extend the `AbstractThingHandlerDiscoveryService` (which implements `ThingHandlerService`and `DiscoveryService`) just like a normal service. +It should extend the `AbstractThingHandlerDiscoveryService` (which implements `ThingHandlerService` and `DiscoveryService`) just like a normal service. Since a new service is created for each thing, it has to be a `PROTOTYPE` component: ```java From ea671db39eb6763ea44fd1d1f08100b0518ce8ff Mon Sep 17 00:00:00 2001 From: J-N-K Date: Wed, 3 Jan 2024 14:41:10 +0100 Subject: [PATCH 7/7] Update developers/bindings/index.md Co-authored-by: Wouter Born Signed-off-by: J-N-K --- developers/bindings/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developers/bindings/index.md b/developers/bindings/index.md index b1e9b1b97a..2c94704da7 100644 --- a/developers/bindings/index.md +++ b/developers/bindings/index.md @@ -990,7 +990,7 @@ In the class there is a field `protected YourBridgeHandler thingHandler;` which This field is guaranteed to be non-null after the service has been activated. During service creation, first `activate()` is called, then the `thingHandler` is injected and finally `ìnitialize()` is called. -The opposite order is used when the service is destroyed, first `dispose()` is called (when the thing handler is still available in the service), then `deactivate`. +The opposite order is used when the service is destroyed, first `dispose()` is called (when the thing handler is still available in the service), then `deactivate()`. `initialize()` and `dispose()` take care of background discovery. If you need additional code for initializing / disposing the discovery service, you can place them in the `initialize()` / `dispose()` methods.