1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2015 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.producers.internal; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 20*f585d8a3SJacky Wang 21*f585d8a3SJacky Wang import com.google.common.util.concurrent.AbstractFuture; 22*f585d8a3SJacky Wang import com.google.common.util.concurrent.ListenableFuture; 23*f585d8a3SJacky Wang import dagger.producers.Producer; 24*f585d8a3SJacky Wang import java.util.concurrent.atomic.AtomicBoolean; 25*f585d8a3SJacky Wang 26*f585d8a3SJacky Wang /** An abstract {@link Producer} implementation that memoizes the result of its compute method. */ 27*f585d8a3SJacky Wang public abstract class AbstractProducer<T> implements CancellableProducer<T> { 28*f585d8a3SJacky Wang private final AtomicBoolean requested = new AtomicBoolean(); 29*f585d8a3SJacky Wang private final NonExternallyCancellableFuture<T> future = new NonExternallyCancellableFuture<T>(); 30*f585d8a3SJacky Wang AbstractProducer()31*f585d8a3SJacky Wang protected AbstractProducer() {} 32*f585d8a3SJacky Wang 33*f585d8a3SJacky Wang /** Computes this producer's future, which is then cached in {@link #get}. */ compute()34*f585d8a3SJacky Wang protected abstract ListenableFuture<T> compute(); 35*f585d8a3SJacky Wang 36*f585d8a3SJacky Wang @Override get()37*f585d8a3SJacky Wang public final ListenableFuture<T> get() { 38*f585d8a3SJacky Wang if (requested.compareAndSet(false, true)) { 39*f585d8a3SJacky Wang future.setFuture(compute()); 40*f585d8a3SJacky Wang } 41*f585d8a3SJacky Wang return future; 42*f585d8a3SJacky Wang } 43*f585d8a3SJacky Wang 44*f585d8a3SJacky Wang @Override cancel(boolean mayInterruptIfRunning)45*f585d8a3SJacky Wang public final void cancel(boolean mayInterruptIfRunning) { 46*f585d8a3SJacky Wang requested.set(true); // Avoid potentially starting the task later only to cancel it immediately. 47*f585d8a3SJacky Wang future.doCancel(mayInterruptIfRunning); 48*f585d8a3SJacky Wang } 49*f585d8a3SJacky Wang 50*f585d8a3SJacky Wang @Override newDependencyView()51*f585d8a3SJacky Wang public Producer<T> newDependencyView() { 52*f585d8a3SJacky Wang return new NonCancellationPropagatingView(); 53*f585d8a3SJacky Wang } 54*f585d8a3SJacky Wang 55*f585d8a3SJacky Wang @Override newEntryPointView(CancellationListener cancellationListener)56*f585d8a3SJacky Wang public Producer<T> newEntryPointView(CancellationListener cancellationListener) { 57*f585d8a3SJacky Wang NonCancellationPropagatingView result = new NonCancellationPropagatingView(); 58*f585d8a3SJacky Wang result.addCancellationListener(cancellationListener); 59*f585d8a3SJacky Wang return result; 60*f585d8a3SJacky Wang } 61*f585d8a3SJacky Wang 62*f585d8a3SJacky Wang /** 63*f585d8a3SJacky Wang * A view of this producer that returns a future that can be cancelled without cancelling the 64*f585d8a3SJacky Wang * producer itself. 65*f585d8a3SJacky Wang */ 66*f585d8a3SJacky Wang private final class NonCancellationPropagatingView implements Producer<T> { 67*f585d8a3SJacky Wang /** 68*f585d8a3SJacky Wang * An independently cancellable view of this node. Needs to be cancellable by normal future 69*f585d8a3SJacky Wang * cancellation so that the view at an entry point can listen for its cancellation. 70*f585d8a3SJacky Wang */ 71*f585d8a3SJacky Wang private final ListenableFuture<T> viewFuture = nonCancellationPropagating(future); 72*f585d8a3SJacky Wang 73*f585d8a3SJacky Wang @SuppressWarnings("FutureReturnValueIgnored") 74*f585d8a3SJacky Wang @Override get()75*f585d8a3SJacky Wang public ListenableFuture<T> get() { 76*f585d8a3SJacky Wang AbstractProducer.this.get(); // force compute() 77*f585d8a3SJacky Wang return viewFuture; 78*f585d8a3SJacky Wang } 79*f585d8a3SJacky Wang addCancellationListener(final CancellationListener cancellationListener)80*f585d8a3SJacky Wang void addCancellationListener(final CancellationListener cancellationListener) { 81*f585d8a3SJacky Wang viewFuture.addListener( 82*f585d8a3SJacky Wang new Runnable() { 83*f585d8a3SJacky Wang @Override 84*f585d8a3SJacky Wang public void run() { 85*f585d8a3SJacky Wang if (viewFuture.isCancelled()) { 86*f585d8a3SJacky Wang boolean mayInterruptIfRunning = 87*f585d8a3SJacky Wang viewFuture instanceof NonCancellationPropagatingFuture 88*f585d8a3SJacky Wang && ((NonCancellationPropagatingFuture) viewFuture).interrupted(); 89*f585d8a3SJacky Wang cancellationListener.onProducerFutureCancelled(mayInterruptIfRunning); 90*f585d8a3SJacky Wang } 91*f585d8a3SJacky Wang } 92*f585d8a3SJacky Wang }, 93*f585d8a3SJacky Wang directExecutor()); 94*f585d8a3SJacky Wang } 95*f585d8a3SJacky Wang } 96*f585d8a3SJacky Wang 97*f585d8a3SJacky Wang /** A settable future that can't be cancelled via normal future cancellation. */ 98*f585d8a3SJacky Wang private static final class NonExternallyCancellableFuture<T> extends AbstractFuture<T> { 99*f585d8a3SJacky Wang 100*f585d8a3SJacky Wang @Override setFuture(ListenableFuture<? extends T> future)101*f585d8a3SJacky Wang public boolean setFuture(ListenableFuture<? extends T> future) { 102*f585d8a3SJacky Wang return super.setFuture(future); 103*f585d8a3SJacky Wang } 104*f585d8a3SJacky Wang 105*f585d8a3SJacky Wang @Override cancel(boolean mayInterruptIfRunning)106*f585d8a3SJacky Wang public boolean cancel(boolean mayInterruptIfRunning) { 107*f585d8a3SJacky Wang return false; 108*f585d8a3SJacky Wang } 109*f585d8a3SJacky Wang 110*f585d8a3SJacky Wang /** Actually cancels this future. */ doCancel(boolean mayInterruptIfRunning)111*f585d8a3SJacky Wang void doCancel(boolean mayInterruptIfRunning) { 112*f585d8a3SJacky Wang super.cancel(mayInterruptIfRunning); 113*f585d8a3SJacky Wang } 114*f585d8a3SJacky Wang } 115*f585d8a3SJacky Wang nonCancellationPropagating(ListenableFuture<T> future)116*f585d8a3SJacky Wang private static <T> ListenableFuture<T> nonCancellationPropagating(ListenableFuture<T> future) { 117*f585d8a3SJacky Wang if (future.isDone()) { 118*f585d8a3SJacky Wang return future; 119*f585d8a3SJacky Wang } 120*f585d8a3SJacky Wang NonCancellationPropagatingFuture<T> output = new NonCancellationPropagatingFuture<T>(future); 121*f585d8a3SJacky Wang future.addListener(output, directExecutor()); 122*f585d8a3SJacky Wang return output; 123*f585d8a3SJacky Wang } 124*f585d8a3SJacky Wang 125*f585d8a3SJacky Wang /** 126*f585d8a3SJacky Wang * Equivalent to {@code Futures.nonCancellationPropagating}, but allowing us to check whether or 127*f585d8a3SJacky Wang * not {@code mayInterruptIfRunning} was set when cancelling it. 128*f585d8a3SJacky Wang */ 129*f585d8a3SJacky Wang private static final class NonCancellationPropagatingFuture<T> extends AbstractFuture<T> 130*f585d8a3SJacky Wang implements Runnable { 131*f585d8a3SJacky Wang // TODO(cgdecker): This is copied directly from Producers.nonCancellationPropagating, but try 132*f585d8a3SJacky Wang // to find out why this doesn't need to be volatile. 133*f585d8a3SJacky Wang private ListenableFuture<T> delegate; 134*f585d8a3SJacky Wang NonCancellationPropagatingFuture(final ListenableFuture<T> delegate)135*f585d8a3SJacky Wang NonCancellationPropagatingFuture(final ListenableFuture<T> delegate) { 136*f585d8a3SJacky Wang this.delegate = delegate; 137*f585d8a3SJacky Wang } 138*f585d8a3SJacky Wang 139*f585d8a3SJacky Wang @Override run()140*f585d8a3SJacky Wang public void run() { 141*f585d8a3SJacky Wang // This prevents cancellation from propagating because we don't call setFuture(delegate) until 142*f585d8a3SJacky Wang // delegate is already done, so calling cancel() on this future won't affect it. 143*f585d8a3SJacky Wang ListenableFuture<T> localDelegate = delegate; 144*f585d8a3SJacky Wang if (localDelegate != null) { 145*f585d8a3SJacky Wang setFuture(localDelegate); 146*f585d8a3SJacky Wang } 147*f585d8a3SJacky Wang } 148*f585d8a3SJacky Wang 149*f585d8a3SJacky Wang @Override pendingToString()150*f585d8a3SJacky Wang protected String pendingToString() { 151*f585d8a3SJacky Wang ListenableFuture<T> localDelegate = delegate; 152*f585d8a3SJacky Wang if (localDelegate != null) { 153*f585d8a3SJacky Wang return "delegate=[" + localDelegate + "]"; 154*f585d8a3SJacky Wang } 155*f585d8a3SJacky Wang return null; 156*f585d8a3SJacky Wang } 157*f585d8a3SJacky Wang 158*f585d8a3SJacky Wang @Override afterDone()159*f585d8a3SJacky Wang protected void afterDone() { 160*f585d8a3SJacky Wang delegate = null; 161*f585d8a3SJacky Wang } 162*f585d8a3SJacky Wang interrupted()163*f585d8a3SJacky Wang public boolean interrupted() { 164*f585d8a3SJacky Wang return super.wasInterrupted(); 165*f585d8a3SJacky Wang } 166*f585d8a3SJacky Wang } 167*f585d8a3SJacky Wang } 168