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

com.github.davidmoten.rx.RxUtil Maven / Gradle / Ivy

There is a newer version: 0.7.19
Show newest version
package com.github.davidmoten.rx;

import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Observable.Operator;
import rx.Observer;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func1;

/**
 * Utility methods for RxJava.
 */
public final class RxUtil {

    /**
     * slf4j logger.
     */
    private static final Logger log = LoggerFactory.getLogger(RxUtil.class);

    private RxUtil() {
        // prevent instantiation
    }

    /**
     * Returns the concatenation of two {@link Observable}s but the first
     * sequence will be emitted in its entirety and ignored before o2 starts
     * emitting.
     * 
     * @param 
     *            the generic type of the second observable
     * @param o1
     *            the sequence to ignore
     * @param o2
     *            the sequence to emit after o1 ignored
     * @return observable result of concatenating two observables, ignoring the
     *         first
     */
    @SuppressWarnings("unchecked")
    public static  Observable concatButIgnoreFirstSequence(Observable o1, Observable o2) {
        return Observable.concat((Observable) o1.ignoreElements(), o2);
    }

    /**
     * Logs errors and onNext at info level using slf4j {@link Logger}.
     * 
     * @param 
     *            the return generic type
     * @return a logging {@link Observer}
     */
    public static  Observer log() {
        return new Observer() {

            @Override
            public void onCompleted() {
                // do nothing
            }

            @Override
            public void onError(Throwable e) {
                log.error(e.getMessage(), e);
            }

            @Override
            public void onNext(T t) {
                log.info(t + "");
            }
        };
    }

    /**
     * Returns a constant value.
     * 
     * @param 
     *            from type
     * @param 
     *            to type
     * @param s
     * @return a constant function with value s
     */
    public static  Func1 constant(final S s) {
        return new Func1() {
            @Override
            public S call(R t1) {
                return s;
            }
        };
    }

    /**
     * Converts a transformation of an Observable into another Observable into
     * an {@link Operator} suitable for use with
     * {@link Observable#lift(Operator)} for instance.
     * 
     * @param 
     *            from generic type
     * @param 
     *            to generic type
     * @param operation
     * @return an operator form of the given function
     */
    public static  Operator toOperator(Func1, Observable> operation) {
        return OperationToOperator.toOperator(operation);
    }

    /**
     * Returns a detector of unsubscribe events. Insert this operator using lift
     * just after the {@link Observable} you want to monitor unsubscribe on.
     *
     * @param 
     *            generic type of stream being monitored for unsubscription
     * @return a detector of unsubscription
     */
    public static  UnsubscribeDetector detectUnsubscribe() {
        return UnsubscribeDetector.detect();
    }

    /**
     * Returns an {@link Action1} that increments a counter when the call method
     * is called.
     * 
     * @param 
     *            generic type of item being counted
     * @return {@link Action1} to count calls.
     */
    public static  CountingAction counter() {
        return new CountingAction();
    }

    public static class CountingAction implements Action1 {
        private final AtomicLong count = new AtomicLong(0);

        public Observable count() {
            return Observable.create(new OnSubscribe() {

                @Override
                public void call(Subscriber subscriber) {
                    subscriber.onNext(count.get());
                    subscriber.onCompleted();
                }
            });
        }

        @Override
        public void call(T t) {
            count.incrementAndGet();
        }
    }

    public static  Func1 greaterThanZero() {
        return new Func1() {

            @Override
            public Boolean call(T t) {
                return t.doubleValue() > 0;
            }
        };
    }

    /**
     * Returns a {@link Func1} that returns an empty {@link Observable}.
     * 
     * @return
     */
    public static  Func1> toEmpty() {
        return constant(Observable. empty());
    }

    /**
     * Returns an {@link Operator} that flattens a sequence of
     * {@link Observable} into a flat sequence of the items from the
     * Observables. This operator may interleave the items asynchronously. For
     * synchronous behaviour use {@link RxUtil#concat()}.
     * 
     * @return
     */
    public static  Operator> flatten() {
        return toOperator(new Func1>, Observable>() {

            @Override
            public Observable call(Observable> source) {
                return source.flatMap(RxUtil.> identity());
            }
        });
    }

    public static  Func1 identity() {
        return new Func1() {
            @Override
            public T call(T t) {
                return t;
            }
        };
    }

    public static  Operator> concat() {
        return toOperator(new Func1>, Observable>() {

            @Override
            public Observable call(Observable> source) {
                return Observable.concat(source);
            }
        });
    }

}