[bluetooth] Add some utility classes (#9064)
* Add some utility classes that will be used by other bluetooth bindings. * Add handle field to BluetoothDescriptor Signed-off-by: Connor Petty <mistercpp2000+gitsignoff@gmail.com>
This commit is contained in:
@@ -396,7 +396,7 @@ public class BlueZBluetoothDevice extends BaseBluetoothDevice implements BlueZEv
|
||||
|
||||
for (BluetoothGattDescriptor dBusBlueZDescriptor : dBusBlueZCharacteristic.getGattDescriptors()) {
|
||||
BluetoothDescriptor descriptor = new BluetoothDescriptor(characteristic,
|
||||
UUID.fromString(dBusBlueZDescriptor.getUuid()));
|
||||
UUID.fromString(dBusBlueZDescriptor.getUuid()), 0);
|
||||
characteristic.addDescriptor(descriptor);
|
||||
}
|
||||
service.addCharacteristic(characteristic);
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.bluetooth.bluez.internal;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -22,6 +20,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
import org.openhab.binding.bluetooth.util.RetryException;
|
||||
import org.openhab.binding.bluetooth.util.RetryFuture;
|
||||
import org.openhab.core.common.ThreadPoolManager;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
@@ -71,7 +71,7 @@ public class DeviceManagerFactory {
|
||||
public void initialize() {
|
||||
logger.debug("initializing DeviceManagerFactory");
|
||||
|
||||
var stage1 = this.deviceManagerFuture = callAsync(() -> {
|
||||
var stage1 = this.deviceManagerFuture = RetryFuture.callWithRetry(() -> {
|
||||
try {
|
||||
// if this is the first call to the library, this call
|
||||
// should throw an exception (that we are catching)
|
||||
@@ -83,12 +83,10 @@ public class DeviceManagerFactory {
|
||||
}
|
||||
}, scheduler);
|
||||
|
||||
stage1.thenCompose(devManager -> {
|
||||
this.deviceManagerWrapperFuture = stage1.thenCompose(devManager -> {
|
||||
// lambdas can't modify outside variables due to scoping, so instead we use an AtomicInteger.
|
||||
AtomicInteger tryCount = new AtomicInteger();
|
||||
// We need to set deviceManagerWrapperFuture here since we want to be able to cancel the underlying
|
||||
// AsyncCompletableFuture instance
|
||||
return this.deviceManagerWrapperFuture = callAsync(() -> {
|
||||
return RetryFuture.callWithRetry(() -> {
|
||||
int count = tryCount.incrementAndGet();
|
||||
try {
|
||||
logger.debug("Registering property handler attempt: {}", count);
|
||||
@@ -127,60 +125,4 @@ public class DeviceManagerFactory {
|
||||
}
|
||||
this.deviceManagerWrapperFuture = null;
|
||||
}
|
||||
|
||||
private static <T> CompletableFuture<T> callAsync(Callable<T> callable, ScheduledExecutorService scheduler) {
|
||||
return new AsyncCompletableFuture<>(callable, scheduler);
|
||||
}
|
||||
|
||||
// this is a utility class that allows use of Callable with CompletableFutures in a way such that the
|
||||
// async future is cancellable thru this CompletableFuture instance.
|
||||
private static class AsyncCompletableFuture<T> extends CompletableFuture<T> implements Runnable {
|
||||
|
||||
private final Callable<T> callable;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final Object futureLock = new Object();
|
||||
private Future<?> future;
|
||||
|
||||
public AsyncCompletableFuture(Callable<T> callable, ScheduledExecutorService scheduler) {
|
||||
this.callable = callable;
|
||||
this.scheduler = scheduler;
|
||||
future = scheduler.submit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
synchronized (futureLock) {
|
||||
future.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
return super.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
complete(callable.call());
|
||||
} catch (RetryException e) {
|
||||
synchronized (futureLock) {
|
||||
if (!future.isCancelled()) {
|
||||
future = scheduler.schedule(this, e.delay, e.unit);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
completeExceptionally(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is a special exception to indicate to a AsyncCompletableFuture that the task needs to be retried.
|
||||
private static class RetryException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 8512275408512109328L;
|
||||
private long delay;
|
||||
private TimeUnit unit;
|
||||
|
||||
public RetryException(long delay, TimeUnit unit) {
|
||||
this.delay = delay;
|
||||
this.unit = unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user