org.javabits.yar.guice.BlockingSupplierImpl Maven / Gradle / Ivy
package org.javabits.yar.guice;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Futures.addCallback;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import java.lang.InterruptedException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
import org.javabits.yar.*;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
class BlockingSupplierImpl implements BlockingSupplier, SupplierListener {
private final AtomicReference>> supplierRef;
private final Id id;
// preserve a reference to the registration to avoid garbage collection.
@SuppressWarnings({"unused", "FieldCanBeLocal"})
private Registration selfRegistration;
BlockingSupplierImpl(Id id, Supplier supplier) {
this.id = checkNotNull(id, "id");
SettableFuture> settableFuture = SettableFuture.create();
if (supplier != null) {
settableFuture.set(supplier);
}
this.supplierRef = new AtomicReference<>(settableFuture);
}
@Override
public Id id() {
return id;
}
@Nullable
@Override
public T get() {
Future> future = supplierRef.get();
// Do not block on Future.get() here. Just check if the future is done.
if (future.isDone())
return future.isCancelled() ? null : getUnchecked(future).get();
return null;
}
@Override
public T getSync() throws InterruptedException {
try {
return getAsync().get();
} catch (ExecutionException e) {
// getAsync() future can't fail (by design). If it did then there is something
// horribly wrong with this code.
throw new AssertionError(e);
}
}
@Nullable
@Override
public T getSync(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
try {
return getAsync().get(timeout, unit);
} catch (ExecutionException e) {
// getAsync() future can't fail (by design). If it did then there is something
// horribly wrong with this code.
throw new AssertionError(e);
}
}
@Override
public ListenableFuture getAsync() {
final SettableFuture future = SettableFuture.create();
// The future callback will be executed either on the current thread (if the future is
// already completed) or on the registry's action handler thread.
addCallback(supplierRef.get(), new FutureCallback>() {
@Override
public void onSuccess(Supplier supplier) {
future.set(supplier.get());
}
@Override
public void onFailure(Throwable t) {
}
});
return future;
}
@SuppressWarnings("unchecked")
@Override
public void supplierChanged(SupplierEvent supplierEvent) {
SupplierEvent.Type type = supplierEvent.type();
Supplier supplier = (Supplier) supplierEvent.supplier();
switch (type) {
case ADD:
supplierRef.get().set(supplier);
break;
case REMOVE:
supplierRef.set(SettableFuture.> create());
break;
default:
throw new IllegalStateException("Unknown supplier event: " + supplierEvent);
}
}
//preserve a strong reference on the registration listener registration
void setSelfRegistration(Registration selfRegistration) {
this.selfRegistration = selfRegistration;
}
@Override
public String toString() {
SettableFuture> delegateSupplier = supplierRef.get();
return "BlockingSupplierImpl{" +
"id=" + id +
", delegate=" + (delegateSupplier != null? delegateSupplier.getClass().getName():"null") +
'}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy