]> git.basschouten.com Git - openhab-addons.git/blob
faef13874e44d2c7432f0373026cba80361fa8e2
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.tradfri.internal;
14
15 import java.net.URI;
16 import java.util.LinkedList;
17 import java.util.concurrent.CompletableFuture;
18 import java.util.concurrent.Future;
19 import java.util.concurrent.ScheduledExecutorService;
20
21 import org.eclipse.californium.core.CoapClient;
22 import org.eclipse.californium.core.CoapObserveRelation;
23 import org.eclipse.californium.core.coap.MediaTypeRegistry;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * The {@link TradfriCoapClient} provides some convenience features over the
31  * plain {@link CoapClient} from californium.
32  *
33  * @author Kai Kreuzer - Initial contribution
34  */
35 @NonNullByDefault
36 public class TradfriCoapClient extends CoapClient {
37
38     private static final long TIMEOUT = 2000;
39     private static final int DEFAULT_DELAY_MILLIS = 600;
40     private final Logger logger = LoggerFactory.getLogger(TradfriCoapClient.class);
41     private final LinkedList<PayloadCallbackPair> commandsQueue = new LinkedList<>();
42     private @Nullable Future<?> job;
43
44     public TradfriCoapClient(URI uri) {
45         super(uri);
46         setTimeout(TIMEOUT);
47     }
48
49     private void executeCommands() {
50         while (true) {
51             try {
52                 synchronized (commandsQueue) {
53                     if (commandsQueue.isEmpty()) {
54                         return;
55                     }
56                     PayloadCallbackPair payloadCallbackPair = commandsQueue.poll();
57                     logger.debug("CoAP PUT request\nuri: {}\npayload: {}", getURI(), payloadCallbackPair.payload);
58                     put(new TradfriCoapHandler(payloadCallbackPair.callback), payloadCallbackPair.payload,
59                             MediaTypeRegistry.TEXT_PLAIN);
60                 }
61                 Thread.sleep(DEFAULT_DELAY_MILLIS);
62             } catch (InterruptedException e) {
63                 logger.debug("commandExecutorThread was interrupted", e);
64             }
65         }
66     }
67
68     /**
69      * Starts observation of the resource and uses the given callback to provide updates.
70      *
71      * @param callback the callback to use for updates
72      */
73     public CoapObserveRelation startObserve(CoapCallback callback) {
74         return observe(new TradfriCoapHandler(callback));
75     }
76
77     /**
78      * Asynchronously executes a GET on the resource and provides the result through a {@link CompletableFuture}.
79      *
80      * @return the future that will hold the result
81      */
82     public CompletableFuture<String> asyncGet() {
83         logger.debug("CoAP GET request\nuri: {}", getURI());
84         CompletableFuture<String> future = new CompletableFuture<>();
85         get(new TradfriCoapHandler(future));
86         return future;
87     }
88
89     /**
90      * Asynchronously executes a GET on the resource and provides the result to a given callback.
91      *
92      * @param callback the callback to use for the response
93      */
94     public void asyncGet(CoapCallback callback) {
95         logger.debug("CoAP GET request\nuri: {}", getURI());
96         get(new TradfriCoapHandler(callback));
97     }
98
99     /**
100      * Asynchronously executes a PUT on the resource with a payload, provides the result to a given callback
101      * and blocks sending new requests to the resource for specified amount of milliseconds.
102      *
103      * @param payload the payload to send with the PUT request
104      * @param callback the callback to use for the response
105      * @param scheduler scheduler to be used for sending commands
106      */
107     public void asyncPut(String payload, CoapCallback callback, ScheduledExecutorService scheduler) {
108         asyncPut(new PayloadCallbackPair(payload, callback), scheduler);
109     }
110
111     /**
112      * Asynchronously executes a PUT on the resource with a payload and provides the result to a given callback.
113      *
114      * @param payloadCallbackPair object which holds the payload and callback process the PUT request
115      * @param scheduler scheduler to be used for sending commands
116      */
117     public void asyncPut(PayloadCallbackPair payloadCallbackPair, ScheduledExecutorService scheduler) {
118         synchronized (this.commandsQueue) {
119             if (this.commandsQueue.isEmpty()) {
120                 this.commandsQueue.offer(payloadCallbackPair);
121                 final Future<?> job = this.job;
122                 if (job == null || job.isDone()) {
123                     this.job = scheduler.submit(() -> executeCommands());
124                 }
125             } else {
126                 this.commandsQueue.offer(payloadCallbackPair);
127             }
128         }
129     }
130
131     @Override
132     public void shutdown() {
133         if (job != null) {
134             job.cancel(true);
135         }
136
137         super.shutdown();
138     }
139
140     public final class PayloadCallbackPair {
141         public final String payload;
142         public final CoapCallback callback;
143
144         public PayloadCallbackPair(String payload, CoapCallback callback) {
145             this.payload = payload;
146             this.callback = callback;
147         }
148     }
149 }