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

rx.util.async.operators.LatchedObserver Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2014 Netflix, Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package rx.util.async.operators;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import rx.Observer;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Action2;

/**
 * An observer implementation that calls a CountDownLatch in case
 * a terminal state has been reached.
 * @param  the observed value type
 */
abstract class LatchedObserver implements Observer {
    /** The CountDownLatch to count-down on a terminal state. */
    protected final CountDownLatch latch;
    /** Contains the error. */
    protected volatile Throwable error;
    /**
     * Indicates the completion status.
     */
    protected final AtomicBoolean done;
    /**
     * Consturcts a LatchedObserver instance.
     * @param latch the CountDownLatch to use
     */
    public LatchedObserver(CountDownLatch latch) {
        this.latch = latch;
        this.done = new AtomicBoolean();
    }
    
    /**
     * Override this method to handle an onNext event.
     * @param value 
     */
    protected abstract void onNextCore(T value);
    /**
     * Override this method to handle an onError event.
     * @param e 
     */
    protected abstract void onErrorCore(Throwable e);
    /**
     * Override this to handle th onCompleted event.
     */
    protected abstract void onCompletedCore();
    /**
     * Try to move into an error state.
     * @param e
     * @return true if succeded, false if this observable has already terminated
     */
    protected boolean fail(Throwable e) {
        if (done.compareAndSet(false, true)) {
            onErrorCore(e);
            return true;
        }
        return false;
    }

    @Override
    public final void onNext(T args) {
        if (!done.get()) {
            onNextCore(args);
        }
    }

    @Override
    public final void onError(Throwable e) {
        fail(e);
    }

    @Override
    public final void onCompleted() {
        if (done.compareAndSet(false, true)) {
            onCompletedCore();
        }
    }
    
    /**
     * Block and await the latch.
     * @throws InterruptedException if the wait is interrupted
     */
    public void await() throws InterruptedException {
        latch.await();
    }
    /**
     * Block and await the latch for a given amount of time.
     * @see CountDownLatch#await(long, java.util.concurrent.TimeUnit) 
     */
    public boolean await(long time, TimeUnit unit) throws InterruptedException {
        return latch.await(time, unit);
    }
    /**
     * Returns the observed error or null if there was none.
     * 

* Should be generally called after the await() returns. * @return the observed error */ public Throwable getThrowable() { return error; } /** * Create a LatchedObserver with the given callback function(s). */ public static LatchedObserver create(Action1 onNext) { return create(onNext, new CountDownLatch(1)); } /** * Create a LatchedObserver with the given callback function(s). */ public static LatchedObserver create(Action1 onNext, Action1 onError) { return create(onNext, onError, new CountDownLatch(1)); } /** * Create a LatchedObserver with the given callback function(s). */ public static LatchedObserver create(Action1 onNext, Action1 onError, Action0 onCompleted) { return create(onNext, onError, onCompleted, new CountDownLatch(1)); } /** * Create a LatchedObserver with the given callback function(s) and a shared latch. */ public static LatchedObserver create(Action1 onNext, CountDownLatch latch) { return new LatchedObserverImpl(onNext, Functionals.emptyThrowable(), Functionals.empty(), latch); } /** * Create a LatchedObserver with the given callback function(s) and a shared latch. */ public static LatchedObserver create(Action1 onNext, Action1 onError, CountDownLatch latch) { return new LatchedObserverImpl(onNext, onError, Functionals.empty(), latch); } /** * Create a LatchedObserver with the given callback function(s) and a shared latch. */ public static LatchedObserver create(Action1 onNext, Action1 onError, Action0 onCompleted, CountDownLatch latch) { return new LatchedObserverImpl(onNext, onError, onCompleted, latch); } /** * Create a LatchedObserver with the given indexed callback function(s). */ public static LatchedObserver createIndexed(Action2 onNext) { return createIndexed(onNext, new CountDownLatch(1)); } /** * Create a LatchedObserver with the given indexed callback function(s). */ public static LatchedObserver createIndexed(Action2 onNext, Action1 onError) { return createIndexed(onNext, onError, new CountDownLatch(1)); } /** * Create a LatchedObserver with the given indexed callback function(s). */ public static LatchedObserver createIndexed(Action2 onNext, Action1 onError, Action0 onCompleted) { return createIndexed(onNext, onError, onCompleted, new CountDownLatch(1)); } /** * Create a LatchedObserver with the given indexed callback function(s) and a shared latch. */ public static LatchedObserver createIndexed(Action2 onNext, CountDownLatch latch) { return new LatchedObserverIndexedImpl(onNext, Functionals.emptyThrowable(), Functionals.empty(), latch); } /** * Create a LatchedObserver with the given indexed callback function(s) and a shared latch. */ public static LatchedObserver createIndexed(Action2 onNext, Action1 onError, CountDownLatch latch) { return new LatchedObserverIndexedImpl(onNext, onError, Functionals.empty(), latch); } /** * Create a LatchedObserver with the given indexed callback function(s) and a shared latch. */ public static LatchedObserver createIndexed(Action2 onNext, Action1 onError, Action0 onCompleted, CountDownLatch latch) { return new LatchedObserverIndexedImpl(onNext, onError, onCompleted, latch); } /** * A latched observer which calls an action for each observed value * and checks if a cancellation token is not unsubscribed. * @param the observed value type */ private static final class LatchedObserverImpl extends LatchedObserver { final Action1 onNext; final Action1 onError; final Action0 onCompleted; public LatchedObserverImpl(Action1 onNext, Action1 onError, Action0 onCompleted, CountDownLatch latch) { super(latch); this.onNext = onNext; this.onError = onError; this.onCompleted = onCompleted; } @Override protected void onNextCore(T args) { try { onNext.call(args); } catch (Throwable t) { fail(t); } } @Override protected void onErrorCore(Throwable e) { try { error = e; onError.call(e); } finally { latch.countDown(); } } @Override protected void onCompletedCore() { try { onCompleted.call(); } finally { latch.countDown(); } } } /** * A latched observer which calls an action for each observed value * and checks if a cancellation token is not unsubscribed. * @param the observed value type */ private static final class LatchedObserverIndexedImpl extends LatchedObserver { final Action2 onNext; final Action1 onError; final Action0 onCompleted; int index; public LatchedObserverIndexedImpl(Action2 onNext, Action1 onError, Action0 onCompleted, CountDownLatch latch) { super(latch); this.onNext = onNext; this.onError = onError; this.onCompleted = onCompleted; } @Override protected void onNextCore(T args) { if (index == Integer.MAX_VALUE) { fail(new ArithmeticException("index overflow")); return; } try { onNext.call(args, index++); } catch (Throwable t) { fail(t); } } @Override protected void onErrorCore(Throwable e) { try { error = e; onError.call(e); } finally { latch.countDown(); } } @Override protected void onCompletedCore() { try { onCompleted.call(); } finally { latch.countDown(); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy