All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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