2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.tradfri.internal;
16 import java.util.LinkedList;
17 import java.util.concurrent.CompletableFuture;
18 import java.util.concurrent.Future;
19 import java.util.concurrent.ScheduledExecutorService;
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;
30 * The {@link TradfriCoapClient} provides some convenience features over the
31 * plain {@link CoapClient} from californium.
33 * @author Kai Kreuzer - Initial contribution
36 public class TradfriCoapClient extends CoapClient {
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;
44 public TradfriCoapClient(URI uri) {
49 private void executeCommands() {
52 synchronized (commandsQueue) {
53 if (commandsQueue.isEmpty()) {
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);
61 Thread.sleep(DEFAULT_DELAY_MILLIS);
62 } catch (InterruptedException e) {
63 logger.debug("commandExecutorThread was interrupted", e);
69 * Starts observation of the resource and uses the given callback to provide updates.
71 * @param callback the callback to use for updates
73 public CoapObserveRelation startObserve(CoapCallback callback) {
74 return observe(new TradfriCoapHandler(callback));
78 * Asynchronously executes a GET on the resource and provides the result through a {@link CompletableFuture}.
80 * @return the future that will hold the result
82 public CompletableFuture<String> asyncGet() {
83 logger.debug("CoAP GET request\nuri: {}", getURI());
84 CompletableFuture<String> future = new CompletableFuture<>();
85 get(new TradfriCoapHandler(future));
90 * Asynchronously executes a GET on the resource and provides the result to a given callback.
92 * @param callback the callback to use for the response
94 public void asyncGet(CoapCallback callback) {
95 logger.debug("CoAP GET request\nuri: {}", getURI());
96 get(new TradfriCoapHandler(callback));
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.
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
107 public void asyncPut(String payload, CoapCallback callback, ScheduledExecutorService scheduler) {
108 asyncPut(new PayloadCallbackPair(payload, callback), scheduler);
112 * Asynchronously executes a PUT on the resource with a payload and provides the result to a given callback.
114 * @param payloadCallbackPair object which holds the payload and callback process the PUT request
115 * @param scheduler scheduler to be used for sending commands
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());
126 this.commandsQueue.offer(payloadCallbackPair);
132 public void shutdown() {
140 public final class PayloadCallbackPair {
141 public final String payload;
142 public final CoapCallback callback;
144 public PayloadCallbackPair(String payload, CoapCallback callback) {
145 this.payload = payload;
146 this.callback = callback;