/** * Copyright (c) 2016-present, RxJava Contributors. * * 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 io.reactivex.flowable; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.*; import org.junit.*; import org.reactivestreams.*; import io.reactivex.*; import io.reactivex.functions.*; import io.reactivex.internal.operators.flowable.*; import io.reactivex.internal.util.ExceptionHelper; import io.reactivex.observers.*; import io.reactivex.schedulers.Schedulers; import io.reactivex.subscribers.DefaultSubscriber; public class FlowableConversionTest { public static class Cylon { } public static class Jail { Object cylon; Jail(Object cylon) { this.cylon = cylon; } } public static class CylonDetectorObservable<T> { protected Publisher<T> onSubscribe; public static <T> CylonDetectorObservable<T> create(Publisher<T> onSubscribe) { return new CylonDetectorObservable<T>(onSubscribe); } protected CylonDetectorObservable(Publisher<T> onSubscribe) { this.onSubscribe = onSubscribe; } public void subscribe(Subscriber<T> subscriber) { onSubscribe.subscribe(subscriber); } public <R> CylonDetectorObservable<R> lift(FlowableOperator<? extends R, ? super T> operator) { return x(new RobotConversionFunc<T, R>(operator)); } public <R, O> O x(Function<Publisher<T>, O> operator) { try { return operator.apply(onSubscribe); } catch (Throwable ex) { throw ExceptionHelper.wrapOrThrow(ex); } } public <R> CylonDetectorObservable<? extends R> compose(Function<CylonDetectorObservable<? super T>, CylonDetectorObservable<? extends R>> transformer) { try { return transformer.apply(this); } catch (Throwable ex) { throw ExceptionHelper.wrapOrThrow(ex); } } public final CylonDetectorObservable<T> beep(Predicate<? super T> predicate) { return new CylonDetectorObservable<T>(new FlowableFilter<T>(Flowable.fromPublisher(onSubscribe), predicate)); } public final <R> CylonDetectorObservable<R> boop(Function<? super T, ? extends R> func) { return new CylonDetectorObservable<R>(new FlowableMap<T, R>(Flowable.fromPublisher(onSubscribe), func)); } public CylonDetectorObservable<String> DESTROY() { return boop(new Function<T, String>() { @Override public String apply(T t) { Object cylon = ((Jail) t).cylon; throwOutTheAirlock(cylon); if (t instanceof Jail) { String name = cylon.toString(); return "Cylon '" + name + "' has been destroyed"; } else { return "Cylon 'anonymous' has been destroyed"; } }}); } private static void throwOutTheAirlock(Object cylon) { // ... } } public static class RobotConversionFunc<T, R> implements Function<Publisher<T>, CylonDetectorObservable<R>> { private FlowableOperator<? extends R, ? super T> operator; public RobotConversionFunc(FlowableOperator<? extends R, ? super T> operator) { this.operator = operator; } @Override public CylonDetectorObservable<R> apply(final Publisher<T> onSubscribe) { return CylonDetectorObservable.create(new Publisher<R>() { @Override public void subscribe(Subscriber<? super R> o) { try { Subscriber<? super T> st = operator.apply(o); try { onSubscribe.subscribe(st); } catch (Throwable e) { st.onError(e); } } catch (Throwable e) { o.onError(e); } }}); } } public static class ConvertToCylonDetector<T> implements Function<Publisher<T>, CylonDetectorObservable<T>> { @Override public CylonDetectorObservable<T> apply(final Publisher<T> onSubscribe) { return CylonDetectorObservable.create(onSubscribe); } } public static class ConvertToObservable<T> implements Function<Publisher<T>, Flowable<T>> { @Override public Flowable<T> apply(final Publisher<T> onSubscribe) { return Flowable.fromPublisher(onSubscribe); } } @Test public void testConversionBetweenObservableClasses() { final TestObserver<String> subscriber = new TestObserver<String>(new DefaultObserver<String>() { @Override public void onComplete() { System.out.println("Complete"); } @Override public void onError(Throwable e) { System.out.println("error: " + e.getMessage()); e.printStackTrace(); } @Override public void onNext(String t) { System.out.println(t); } }); List<Object> crewOfBattlestarGalactica = Arrays.asList(new Object[] {"William Adama", "Laura Roslin", "Lee Adama", new Cylon()}); Flowable.fromIterable(crewOfBattlestarGalactica) .doOnNext(new Consumer<Object>() { @Override public void accept(Object pv) { System.out.println(pv); } }) .to(new ConvertToCylonDetector<Object>()) .beep(new Predicate<Object>() { @Override public boolean test(Object t) { return t instanceof Cylon; } }) .boop(new Function<Object, Object>() { @Override public Object apply(Object cylon) { return new Jail(cylon); } }) .DESTROY() .x(new ConvertToObservable<String>()) .reduce("Cylon Detector finished. Report:\n", new BiFunction<String, String, String>() { @Override public String apply(String a, String n) { return a + n + "\n"; } }) .subscribe(subscriber); subscriber.assertNoErrors(); subscriber.assertComplete(); } @Test public void testConvertToConcurrentQueue() { final AtomicReference<Throwable> thrown = new AtomicReference<Throwable>(null); final AtomicBoolean isFinished = new AtomicBoolean(false); ConcurrentLinkedQueue<? extends Integer> queue = Flowable.range(0,5) .flatMap(new Function<Integer, Publisher<Integer>>() { @Override public Publisher<Integer> apply(final Integer i) { return Flowable.range(0, 5) .observeOn(Schedulers.io()) .map(new Function<Integer, Integer>() { @Override public Integer apply(Integer k) { try { Thread.sleep(System.currentTimeMillis() % 100); } catch (InterruptedException e) { e.printStackTrace(); } return i + k; } }); } }) .to(new Function<Flowable<Integer>, ConcurrentLinkedQueue<Integer>>() { @Override public ConcurrentLinkedQueue<Integer> apply(Flowable<Integer> onSubscribe) { final ConcurrentLinkedQueue<Integer> q = new ConcurrentLinkedQueue<Integer>(); onSubscribe.subscribe(new DefaultSubscriber<Integer>() { @Override public void onComplete() { isFinished.set(true); } @Override public void onError(Throwable e) { thrown.set(e); } @Override public void onNext(Integer t) { q.add(t); }}); return q; } }); int x = 0; while (!isFinished.get()) { Integer i = queue.poll(); if (i != null) { x++; System.out.println(x + " item: " + i); } } Assert.assertNull(thrown.get()); } }