From 63850510fd51df5de398f47322852b0946ec30c2 Mon Sep 17 00:00:00 2001 From: akarnokd Date: Thu, 3 Nov 2016 10:04:55 +0100 Subject: [PATCH 01/74] Release 1.2.2 --- CHANGES.md | 42 +++++++++++++++++++ src/main/java/rx/Completable.java | 1 - .../operators/CompletableFromEmitterTest.java | 1 - src/test/java/rx/plugins/RxJavaHooksTest.java | 6 +-- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 17ba6a9a89..1741085701 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,47 @@ # RxJava Releases # +### Version 1.2.2 - November 3, 2016 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.2%7C)) + +Note that the interface `Cancellable` has been moved to `rx.functions` affecting `CompletableEmitter` and the experimental `Observable.fromEmitter(Action1> emitter, AsyncEmitter.BackpressureMode backpressure)` has been removed. + +Another important clarification was added to the javadoc about using `SingleSubscriber`: due to the internal enhancements of `Single`, a `SingleSubscriber` is no longer wrapped into a `Subscriber`+`SafeSubscriber` which setup used to call `unsubscribe` on the `SingleSubscriber` yielding `isUnsubscribed() == true` when the source terminated. Therefore, when one extends the class `SingleSubscriber`, the `unsubscribe()` should be called manually to yield the given expecation mentioned before: + +``` java +Subscritpion s = Single.just(1).subscribe(new SingleSubscriber() { + @Override public void onSuccess(Integer t) { + System.out.println("Success"); + unsubscribe(); + } + + @Override public void onError(Throwable e) { + e.printStackTrace(); + unsubscribe(); + } +}); + +assertTrue(s.isUnsubscribed()); +``` +#### Documentation enhancements + +- [Pull 4693](https://github.com/ReactiveX/RxJava/pull/4693): improve `timer` javadoc +- [Pull 4769](https://github.com/ReactiveX/RxJava/pull/4769): Add note to `SingleSubscriber` doc about unsubscribe invocation in `onSuccess` and `onError`. + +#### API enhancements + +- [Pull 4725](https://github.com/ReactiveX/RxJava/pull/4725): remove `AsyncEmitter` deprecations +- [Pull 4757](https://github.com/ReactiveX/RxJava/pull/4757): Add `cache()` to `Single` + +#### Performance enhancements + +- [Pull 4676](https://github.com/ReactiveX/RxJava/pull/4676): Make identity function a singleton. +- [Pull 4764](https://github.com/ReactiveX/RxJava/pull/4764): `zip` - check local boolean before volatile in boolean and + +#### Bugfixes + +- [Pull 4716](https://github.com/ReactiveX/RxJava/pull/4716): fix`subscribe(Action1 [, Action1])` to report `isUnsubscribed` true after the callbacks were invoked +- [Pull 4740](https://github.com/ReactiveX/RxJava/pull/4740): Error when tracking exception with unknown cause +- [Pull 4791](https://github.com/ReactiveX/RxJava/pull/4791): Add null check to `Observable.switchIfEmpty` + ### Version 1.2.1 - October 5, 2016 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.1%7C)) #### API enhancements diff --git a/src/main/java/rx/Completable.java b/src/main/java/rx/Completable.java index e9ae55239a..e604fdaf71 100644 --- a/src/main/java/rx/Completable.java +++ b/src/main/java/rx/Completable.java @@ -540,7 +540,6 @@ public void call(rx.CompletableSubscriber s) { * @return the new Completable instance * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) */ - @SuppressWarnings("deprecation") @Experimental public static Completable fromEmitter(Action1 producer) { return create(new CompletableFromEmitter(producer)); diff --git a/src/test/java/rx/internal/operators/CompletableFromEmitterTest.java b/src/test/java/rx/internal/operators/CompletableFromEmitterTest.java index a719f186b1..32107591fc 100644 --- a/src/test/java/rx/internal/operators/CompletableFromEmitterTest.java +++ b/src/test/java/rx/internal/operators/CompletableFromEmitterTest.java @@ -29,7 +29,6 @@ import rx.observers.TestSubscriber; import rx.subscriptions.BooleanSubscription; -@SuppressWarnings("deprecation") public class CompletableFromEmitterTest { @Test diff --git a/src/test/java/rx/plugins/RxJavaHooksTest.java b/src/test/java/rx/plugins/RxJavaHooksTest.java index 89a118482d..a4b3999f73 100644 --- a/src/test/java/rx/plugins/RxJavaHooksTest.java +++ b/src/test/java/rx/plugins/RxJavaHooksTest.java @@ -21,12 +21,10 @@ import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.*; -import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; -import org.mockito.Mockito; import rx.*; import rx.Observable; import rx.Scheduler.Worker; @@ -42,6 +40,8 @@ public class RxJavaHooksTest { public static class TestExceptionWithUnknownCause extends RuntimeException { + private static final long serialVersionUID = 6771158999860253299L; + TestExceptionWithUnknownCause() { super((Throwable) null); } From d6bc9237338f26853a99149751342f54e5ba9b18 Mon Sep 17 00:00:00 2001 From: Dave Moten Date: Wed, 9 Nov 2016 20:33:53 +1100 Subject: [PATCH 02/74] add TestSubscriber2 to provide method chained version of TestSubscriber and support Observable.test() (#4777) --- src/main/java/rx/Completable.java | 23 ++ src/main/java/rx/Observable.java | 43 +++ src/main/java/rx/Single.java | 23 ++ .../AssertableSubscriberObservable.java | 310 ++++++++++++++++++ .../rx/observers/AssertableSubscriber.java | 87 +++++ .../observers/AssertableSubscriberTest.java | 162 +++++++++ 6 files changed, 648 insertions(+) create mode 100644 src/main/java/rx/internal/observers/AssertableSubscriberObservable.java create mode 100644 src/main/java/rx/observers/AssertableSubscriber.java create mode 100644 src/test/java/rx/observers/AssertableSubscriberTest.java diff --git a/src/main/java/rx/Completable.java b/src/main/java/rx/Completable.java index e604fdaf71..12d088c35d 100644 --- a/src/main/java/rx/Completable.java +++ b/src/main/java/rx/Completable.java @@ -23,6 +23,7 @@ import rx.annotations.*; import rx.exceptions.*; import rx.functions.*; +import rx.internal.observers.AssertableSubscriberObservable; import rx.internal.operators.*; import rx.internal.util.*; import rx.observers.*; @@ -2364,4 +2365,26 @@ public void call() { } }); } + + // ------------------------------------------------------------------------- + // Fluent test support, super handy and reduces test preparation boilerplate + // ------------------------------------------------------------------------- + /** + * Creates an AssertableSubscriber that requests {@code Long.MAX_VALUE} and subscribes + * it to this Observable. + *
+ *
Backpressure:
+ *
The returned AssertableSubscriber consumes this Observable in an unbounded fashion.
+ *
Scheduler:
+ *
{@code test} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @return the new AssertableSubscriber instance + * @since 1.2.3 + */ + @Experimental + public final AssertableSubscriber test() { + AssertableSubscriberObservable ts = AssertableSubscriberObservable.create(Long.MAX_VALUE); + subscribe(ts); + return ts; + } } \ No newline at end of file diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index dd67541c2f..904ccec45c 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -18,10 +18,12 @@ import rx.annotations.*; import rx.exceptions.*; import rx.functions.*; +import rx.internal.observers.AssertableSubscriberObservable; import rx.internal.operators.*; import rx.internal.util.*; import rx.observables.*; import rx.observers.SafeSubscriber; +import rx.observers.AssertableSubscriber; import rx.plugins.*; import rx.schedulers.*; import rx.subscriptions.Subscriptions; @@ -12640,4 +12642,45 @@ public final Observable zipWith(Iterable other, Func2 Observable zipWith(Observable other, Func2 zipFunction) { return (Observable)zip(this, other, zipFunction); } + + // ------------------------------------------------------------------------- + // Fluent test support, super handy and reduces test preparation boilerplate + // ------------------------------------------------------------------------- + /** + * Creates a AssertableSubscriber that requests {@code Long.MAX_VALUE} and subscribes + * it to this Observable. + *
+ *
Backpressure:
+ *
The returned AssertableSubscriber consumes this Observable in an unbounded fashion.
+ *
Scheduler:
+ *
{@code test} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @return the new AssertableSubscriber instance + * @since 1.2.3 + */ + @Experimental + public final AssertableSubscriber test() { + AssertableSubscriber ts = AssertableSubscriberObservable.create(Long.MAX_VALUE); + subscribe(ts); + return ts; + } + + /** + * Creates an AssertableSubscriber with the initial request amount and subscribes + * it to this Observable. + *
+ *
Backpressure:
+ *
The returned AssertableSubscriber requests the given {@code initialRequest} amount upfront.
+ *
Scheduler:
+ *
{@code test} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @return the new AssertableSubscriber instance + * @since 1.2.3 + */ + @Experimental + public final AssertableSubscriber test(long initialRequestAmount) { + AssertableSubscriber ts = AssertableSubscriberObservable.create(initialRequestAmount); + subscribe(ts); + return ts; + } } diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index b0ac837610..7b85c4d3a5 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -19,6 +19,7 @@ import rx.annotations.*; import rx.exceptions.*; import rx.functions.*; +import rx.internal.observers.AssertableSubscriberObservable; import rx.internal.operators.*; import rx.internal.util.*; import rx.observables.ConnectableObservable; @@ -2675,4 +2676,26 @@ public final Single delaySubscription(Observable other) { } return create(new SingleOnSubscribeDelaySubscriptionOther(this, other)); } + + // ------------------------------------------------------------------------- + // Fluent test support, super handy and reduces test preparation boilerplate + // ------------------------------------------------------------------------- + /** + * Creates an AssertableSubscriber that requests {@code Long.MAX_VALUE} and subscribes + * it to this Observable. + *
+ *
Backpressure:
+ *
The returned AssertableSubscriber consumes this Observable in an unbounded fashion.
+ *
Scheduler:
+ *
{@code test} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @return the new AssertableSubscriber instance + * @since 1.2.3 + */ + @Experimental + public final AssertableSubscriber test() { + AssertableSubscriberObservable ts = AssertableSubscriberObservable.create(Long.MAX_VALUE); + subscribe(ts); + return ts; + } } diff --git a/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java b/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java new file mode 100644 index 0000000000..db1c4f0532 --- /dev/null +++ b/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java @@ -0,0 +1,310 @@ +/** + * Copyright 2016 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.internal.observers; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import rx.Producer; +import rx.Subscriber; +import rx.annotations.Experimental; +import rx.functions.Action0; +import rx.observers.TestSubscriber; +import rx.observers.AssertableSubscriber; + +/** + * A {@code AssertableSubscriber} is a variety of {@link Subscriber} that you can use + * for unit testing, to perform assertions or inspect received events. + * AssertableSubscriber is a duplicate of TestSubscriber but supports method chaining + * where possible. + * + * @param + * the value type + */ +@Experimental +public class AssertableSubscriberObservable extends Subscriber implements AssertableSubscriber { + + private final TestSubscriber ts; + + public AssertableSubscriberObservable(TestSubscriber ts) { + this.ts = ts; + } + + public static AssertableSubscriberObservable create(long initialRequest) { + TestSubscriber t1 = new TestSubscriber(initialRequest); + AssertableSubscriberObservable t2 = new AssertableSubscriberObservable(t1); + t2.add(t1); + return t2; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#onStart() + */ + @Override + public void onStart() { + ts.onStart(); + } + + @Override + public void onCompleted() { + ts.onCompleted(); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#setProducer(rx.Producer) + */ + @Override + public void setProducer(Producer p) { + ts.setProducer(p); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#getCompletions() + */ + @Override + public final int getCompletions() { + return ts.getCompletions(); + } + + @Override + public void onError(Throwable e) { + ts.onError(e); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#getOnErrorEvents() + */ + @Override + public List getOnErrorEvents() { + return ts.getOnErrorEvents(); + } + + @Override + public void onNext(T t) { + ts.onNext(t); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#getValueCount() + */ + @Override + public final int getValueCount() { + return ts.getValueCount(); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#requestMore(long) + */ + @Override + public AssertableSubscriber requestMore(long n) { + ts.requestMore(n); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#getOnNextEvents() + */ + @Override + public List getOnNextEvents() { + return ts.getOnNextEvents(); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertReceivedOnNext(java.util.List) + */ + @Override + public AssertableSubscriber assertReceivedOnNext(List items) { + ts.assertReceivedOnNext(items); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#awaitValueCount(int, long, java.util.concurrent.TimeUnit) + */ + @Override + public final boolean awaitValueCount(int expected, long timeout, TimeUnit unit) { + return ts.awaitValueCount(expected, timeout, unit); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertTerminalEvent() + */ + @Override + public AssertableSubscriber assertTerminalEvent() { + ts.assertTerminalEvent(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertUnsubscribed() + */ + @Override + public AssertableSubscriber assertUnsubscribed() { + ts.assertUnsubscribed(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertNoErrors() + */ + @Override + public AssertableSubscriber assertNoErrors() { + ts.assertNoErrors(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#awaitTerminalEvent() + */ + @Override + public AssertableSubscriber awaitTerminalEvent() { + ts.awaitTerminalEvent(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#awaitTerminalEvent(long, java.util.concurrent.TimeUnit) + */ + @Override + public AssertableSubscriber awaitTerminalEvent(long timeout, TimeUnit unit) { + ts.awaitTerminalEvent(timeout, unit); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#awaitTerminalEventAndUnsubscribeOnTimeout(long, java.util.concurrent.TimeUnit) + */ + @Override + public AssertableSubscriber awaitTerminalEventAndUnsubscribeOnTimeout(long timeout, + TimeUnit unit) { + ts.awaitTerminalEventAndUnsubscribeOnTimeout(timeout, unit); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#getLastSeenThread() + */ + @Override + public Thread getLastSeenThread() { + return ts.getLastSeenThread(); + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertCompleted() + */ + @Override + public AssertableSubscriber assertCompleted() { + ts.assertCompleted(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertNotCompleted() + */ + @Override + public AssertableSubscriber assertNotCompleted() { + ts.assertNotCompleted(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertError(java.lang.Class) + */ + @Override + public AssertableSubscriber assertError(Class clazz) { + ts.assertError(clazz); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertError(java.lang.Throwable) + */ + @Override + public AssertableSubscriber assertError(Throwable throwable) { + ts.assertError(throwable); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertNoTerminalEvent() + */ + @Override + public AssertableSubscriber assertNoTerminalEvent() { + ts.assertNoTerminalEvent(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertNoValues() + */ + @Override + public AssertableSubscriber assertNoValues() { + ts.assertNoValues(); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertValueCount(int) + */ + @Override + public AssertableSubscriber assertValueCount(int count) { + ts.assertValueCount(count); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertValues(T) + */ + @Override + public AssertableSubscriber assertValues(T... values) { + ts.assertValues(values); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertValue(T) + */ + @Override + public AssertableSubscriber assertValue(T value) { + ts.assertValue(value); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#assertValuesAndClear(T, T) + */ + @Override + public final AssertableSubscriber assertValuesAndClear(T expectedFirstValue, + T... expectedRestValues) { + ts.assertValuesAndClear(expectedFirstValue, expectedRestValues); + return this; + } + + /* (non-Javadoc) + * @see rx.observers.AssertableSubscriber#perform(rx.functions.Action0) + */ + @Override + public final AssertableSubscriber perform(Action0 action) { + action.call(); + return this; + } + + @Override + public String toString() { + return ts.toString(); + } + +} diff --git a/src/main/java/rx/observers/AssertableSubscriber.java b/src/main/java/rx/observers/AssertableSubscriber.java new file mode 100644 index 0000000000..c4199088cb --- /dev/null +++ b/src/main/java/rx/observers/AssertableSubscriber.java @@ -0,0 +1,87 @@ +/** + * Copyright 2016 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.observers; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import rx.Observer; +import rx.Producer; +import rx.functions.Action0; + +public interface AssertableSubscriber extends Observer { + + void onStart(); + + void setProducer(Producer p); + + int getCompletions(); + + List getOnErrorEvents(); + + int getValueCount(); + + AssertableSubscriber requestMore(long n); + + List getOnNextEvents(); + + AssertableSubscriber assertReceivedOnNext(List items); + + boolean awaitValueCount(int expected, long timeout, TimeUnit unit); + + AssertableSubscriber assertTerminalEvent(); + + AssertableSubscriber assertUnsubscribed(); + + AssertableSubscriber assertNoErrors(); + + AssertableSubscriber awaitTerminalEvent(); + + AssertableSubscriber awaitTerminalEvent(long timeout, TimeUnit unit); + + AssertableSubscriber awaitTerminalEventAndUnsubscribeOnTimeout(long timeout, + TimeUnit unit); + + Thread getLastSeenThread(); + + AssertableSubscriber assertCompleted(); + + AssertableSubscriber assertNotCompleted(); + + AssertableSubscriber assertError(Class clazz); + + AssertableSubscriber assertError(Throwable throwable); + + AssertableSubscriber assertNoTerminalEvent(); + + AssertableSubscriber assertNoValues(); + + AssertableSubscriber assertValueCount(int count); + + AssertableSubscriber assertValues(T... values); + + AssertableSubscriber assertValue(T value); + + AssertableSubscriber assertValuesAndClear(T expectedFirstValue, + T... expectedRestValues); + + AssertableSubscriber perform(Action0 action); + + void unsubscribe(); + + boolean isUnsubscribed(); + +} \ No newline at end of file diff --git a/src/test/java/rx/observers/AssertableSubscriberTest.java b/src/test/java/rx/observers/AssertableSubscriberTest.java new file mode 100644 index 0000000000..84128feada --- /dev/null +++ b/src/test/java/rx/observers/AssertableSubscriberTest.java @@ -0,0 +1,162 @@ +/** + * Copyright 2016 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.observers; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.Test; + +import rx.Completable; +import rx.Observable; +import rx.Single; +import rx.functions.Action0; +import rx.functions.Actions; + +public class AssertableSubscriberTest { + + @Test + public void testManyMaxValue() { + AssertableSubscriber ts = Observable.just(1, 2, 3) + .test() + .assertValues(1, 2, 3) + .awaitTerminalEvent() + .awaitTerminalEvent(5, TimeUnit.SECONDS) + .awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS) + .assertCompleted() + .assertTerminalEvent() + .assertNoErrors() + .assertUnsubscribed() + .assertReceivedOnNext(Arrays.asList(1, 2, 3)) + .assertValueCount(3); + assertEquals(3, ts.getValueCount()); + assertEquals(1, ts.getCompletions()); + assertEquals(Thread.currentThread().getName(), ts.getLastSeenThread().getName()); + assertEquals(Arrays.asList(1,2,3), ts.getOnNextEvents()); + assertTrue(ts.awaitValueCount(3, 5, TimeUnit.SECONDS)); + } + + @Test + public void testManyWithInitialRequest() { + AssertableSubscriber ts = Observable.just(1, 2, 3) + .test(1) + .assertValue(1) + .assertValues(1) + .assertValuesAndClear(1) + .assertNotCompleted() + .assertNoErrors() + .assertNoTerminalEvent() + .requestMore(1) + .assertValuesAndClear(2); + ts.unsubscribe(); + ts.assertUnsubscribed(); + assertTrue(ts.isUnsubscribed()); + } + + @Test + public void testEmpty() { + Observable.empty() + .test() + .assertNoValues(); + } + + @Test + public void testError() { + IOException e = new IOException(); + AssertableSubscriber ts = Observable.error(e) + .test() + .assertError(e) + .assertError(IOException.class); + assertEquals(Arrays.asList(e), ts.getOnErrorEvents()); + } + + @Test + public void toStringIsNotNull() { + AssertableSubscriber ts = Observable.empty().test(); + assertNotNull(ts.toString()); + } + + @Test + public void testPerform() { + final AtomicBoolean performed = new AtomicBoolean(false); + Observable.empty() + .test() + .perform(new Action0() { + @Override + public void call() { + performed.set(true); + } + }); + assertTrue(performed.get()); + } + + @Test + public void testCompletable() { + AssertableSubscriber ts = Completable + .fromAction(Actions.empty()) + .test() + .assertNoValues() + .assertNoErrors() + .assertValueCount(0) + .assertValues() + .assertTerminalEvent() + .assertReceivedOnNext(Collections.emptyList()) + .awaitTerminalEvent() + .awaitTerminalEvent(5, TimeUnit.SECONDS) + .awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS) + .assertCompleted() + .assertUnsubscribed(); + assertEquals(1, ts.getCompletions()); + assertEquals(Thread.currentThread().getName(), ts.getLastSeenThread().getName()); + assertTrue(ts.getOnErrorEvents().isEmpty()); + assertTrue(ts.getOnNextEvents().isEmpty()); + assertEquals(0, ts.getValueCount()); + } + + @Test + public void testSingle() { + AssertableSubscriber ts = Single + .just(10) + .test() + .assertValue(10) + .assertValues(10) + .assertValueCount(1) + .assertReceivedOnNext(Arrays.asList(10)) + .assertValuesAndClear(10) + .assertNoValues() + .assertTerminalEvent() + .assertNoErrors() + .assertCompleted() + .assertUnsubscribed() + .awaitTerminalEvent() + .awaitTerminalEvent(5, TimeUnit.SECONDS) + .awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS); + assertEquals(1, ts.getCompletions()); + assertEquals(Thread.currentThread().getName(), ts.getLastSeenThread().getName()); + assertTrue(ts.getOnErrorEvents().isEmpty()); + assertTrue(ts.getOnNextEvents().isEmpty()); + assertEquals(1, ts.getValueCount()); + } + +} + From 1f6c68c469359ec08842d3b540387682357325f1 Mon Sep 17 00:00:00 2001 From: George Campbell Date: Wed, 9 Nov 2016 14:55:03 -0800 Subject: [PATCH 03/74] Schedule when bug fix (#4826) * change tabs to spaces. * Fixing a bug in the subscription logic of the actions that caused work to get unsubscribed too early. Changed the code to delay the calling of onCompleted of the CompletableSubscriber until the actualAction is truly done. --- .../rx/internal/schedulers/SchedulerWhen.java | 400 +++++++++--------- .../java/rx/schedulers/SchedulerWhenTest.java | 15 + 2 files changed, 224 insertions(+), 191 deletions(-) diff --git a/src/main/java/rx/internal/schedulers/SchedulerWhen.java b/src/main/java/rx/internal/schedulers/SchedulerWhen.java index db1006f885..c45ee5853c 100644 --- a/src/main/java/rx/internal/schedulers/SchedulerWhen.java +++ b/src/main/java/rx/internal/schedulers/SchedulerWhen.java @@ -104,195 +104,213 @@ */ @Experimental public class SchedulerWhen extends Scheduler implements Subscription { - private final Scheduler actualScheduler; - private final Observer> workerObserver; - private final Subscription subscription; - - public SchedulerWhen(Func1>, Completable> combine, Scheduler actualScheduler) { - this.actualScheduler = actualScheduler; - // workers are converted into completables and put in this queue. - PublishSubject> workerSubject = PublishSubject.create(); - this.workerObserver = new SerializedObserver>(workerSubject); - // send it to a custom combinator to pick the order and rate at which - // workers are processed. - this.subscription = combine.call(workerSubject.onBackpressureBuffer()).subscribe(); - } - - @Override - public void unsubscribe() { - subscription.unsubscribe(); - } - - @Override - public boolean isUnsubscribed() { - return subscription.isUnsubscribed(); - } - - @Override - public Worker createWorker() { - final Worker actualWorker = actualScheduler.createWorker(); - // a queue for the actions submitted while worker is waiting to get to - // the subscribe to off the workerQueue. - BufferUntilSubscriber actionSubject = BufferUntilSubscriber.create(); - final Observer actionObserver = new SerializedObserver(actionSubject); - // convert the work of scheduling all the actions into a completable - Observable actions = actionSubject.map(new Func1() { - @Override - public Completable call(final ScheduledAction action) { - return Completable.create(new OnSubscribe() { - @Override - public void call(CompletableSubscriber actionCompletable) { - actionCompletable.onSubscribe(action); - action.call(actualWorker); - actionCompletable.onCompleted(); - } - }); - } - }); - - // a worker that queues the action to the actionQueue subject. - Worker worker = new Worker() { - private final AtomicBoolean unsubscribed = new AtomicBoolean(); - - @Override - public void unsubscribe() { - // complete the actionQueue when worker is unsubscribed to make - // room for the next worker in the workerQueue. - if (unsubscribed.compareAndSet(false, true)) { - actualWorker.unsubscribe(); - actionObserver.onCompleted(); - } - } - - @Override - public boolean isUnsubscribed() { - return unsubscribed.get(); - } - - @Override - public Subscription schedule(final Action0 action, final long delayTime, final TimeUnit unit) { - // send a scheduled action to the actionQueue - DelayedAction delayedAction = new DelayedAction(action, delayTime, unit); - actionObserver.onNext(delayedAction); - return delayedAction; - } - - @Override - public Subscription schedule(final Action0 action) { - // send a scheduled action to the actionQueue - ImmediateAction immediateAction = new ImmediateAction(action); - actionObserver.onNext(immediateAction); - return immediateAction; - } - }; - - // enqueue the completable that process actions put in reply subject - workerObserver.onNext(actions); - - // return the worker that adds actions to the reply subject - return worker; - } - - static final Subscription SUBSCRIBED = new Subscription() { - @Override - public void unsubscribe() { - } - - @Override - public boolean isUnsubscribed() { - return false; - } - }; - - static final Subscription UNSUBSCRIBED = Subscriptions.unsubscribed(); - - @SuppressWarnings("serial") - private static abstract class ScheduledAction extends AtomicReference implements Subscription { - public ScheduledAction() { - super(SUBSCRIBED); - } - - private void call(Worker actualWorker) { - Subscription oldState = get(); - // either SUBSCRIBED or UNSUBSCRIBED - if (oldState == UNSUBSCRIBED) { - // no need to schedule return - return; - } - if (oldState != SUBSCRIBED) { - // has already been scheduled return - // should not be able to get here but handle it anyway by not - // rescheduling. - return; - } - - Subscription newState = callActual(actualWorker); - - if (!compareAndSet(SUBSCRIBED, newState)) { - // set would only fail if the new current state is some other - // subscription from a concurrent call to this method. - // Unsubscribe from the action just scheduled because it lost - // the race. - newState.unsubscribe(); - } - } - - protected abstract Subscription callActual(Worker actualWorker); - - @Override - public boolean isUnsubscribed() { - return get().isUnsubscribed(); - } - - @Override - public void unsubscribe() { - Subscription oldState; - // no matter what the current state is the new state is going to be - Subscription newState = UNSUBSCRIBED; - do { - oldState = get(); - if (oldState == UNSUBSCRIBED) { - // the action has already been unsubscribed - return; - } - } while (!compareAndSet(oldState, newState)); - - if (oldState != SUBSCRIBED) { - // the action was scheduled. stop it. - oldState.unsubscribe(); - } - } - } - - @SuppressWarnings("serial") - private static class ImmediateAction extends ScheduledAction { - private final Action0 action; - - public ImmediateAction(Action0 action) { - this.action = action; - } - - @Override - protected Subscription callActual(Worker actualWorker) { - return actualWorker.schedule(action); - } - } - - @SuppressWarnings("serial") - private static class DelayedAction extends ScheduledAction { - private final Action0 action; - private final long delayTime; - private final TimeUnit unit; - - public DelayedAction(Action0 action, long delayTime, TimeUnit unit) { - this.action = action; - this.delayTime = delayTime; - this.unit = unit; - } - - @Override - protected Subscription callActual(Worker actualWorker) { - return actualWorker.schedule(action, delayTime, unit); - } - } + private final Scheduler actualScheduler; + private final Observer> workerObserver; + private final Subscription subscription; + + public SchedulerWhen(Func1>, Completable> combine, Scheduler actualScheduler) { + this.actualScheduler = actualScheduler; + // workers are converted into completables and put in this queue. + PublishSubject> workerSubject = PublishSubject.create(); + this.workerObserver = new SerializedObserver>(workerSubject); + // send it to a custom combinator to pick the order and rate at which + // workers are processed. + this.subscription = combine.call(workerSubject.onBackpressureBuffer()).subscribe(); + } + + @Override + public void unsubscribe() { + subscription.unsubscribe(); + } + + @Override + public boolean isUnsubscribed() { + return subscription.isUnsubscribed(); + } + + @Override + public Worker createWorker() { + final Worker actualWorker = actualScheduler.createWorker(); + // a queue for the actions submitted while worker is waiting to get to + // the subscribe to off the workerQueue. + BufferUntilSubscriber actionSubject = BufferUntilSubscriber. create(); + final Observer actionObserver = new SerializedObserver(actionSubject); + // convert the work of scheduling all the actions into a completable + Observable actions = actionSubject.map(new Func1() { + @Override + public Completable call(final ScheduledAction action) { + return Completable.create(new OnSubscribe() { + @Override + public void call(CompletableSubscriber actionCompletable) { + actionCompletable.onSubscribe(action); + action.call(actualWorker, actionCompletable); + } + }); + } + }); + + // a worker that queues the action to the actionQueue subject. + Worker worker = new Worker() { + private final AtomicBoolean unsubscribed = new AtomicBoolean(); + + @Override + public void unsubscribe() { + // complete the actionQueue when worker is unsubscribed to make + // room for the next worker in the workerQueue. + if (unsubscribed.compareAndSet(false, true)) { + actualWorker.unsubscribe(); + actionObserver.onCompleted(); + } + } + + @Override + public boolean isUnsubscribed() { + return unsubscribed.get(); + } + + @Override + public Subscription schedule(final Action0 action, final long delayTime, final TimeUnit unit) { + // send a scheduled action to the actionQueue + DelayedAction delayedAction = new DelayedAction(action, delayTime, unit); + actionObserver.onNext(delayedAction); + return delayedAction; + } + + @Override + public Subscription schedule(final Action0 action) { + // send a scheduled action to the actionQueue + ImmediateAction immediateAction = new ImmediateAction(action); + actionObserver.onNext(immediateAction); + return immediateAction; + } + }; + + // enqueue the completable that process actions put in reply subject + workerObserver.onNext(actions); + + // return the worker that adds actions to the reply subject + return worker; + } + + static final Subscription SUBSCRIBED = new Subscription() { + @Override + public void unsubscribe() { + } + + @Override + public boolean isUnsubscribed() { + return false; + } + }; + + static final Subscription UNSUBSCRIBED = Subscriptions.unsubscribed(); + + @SuppressWarnings("serial") + private static abstract class ScheduledAction extends AtomicReferenceimplements Subscription { + public ScheduledAction() { + super(SUBSCRIBED); + } + + private void call(Worker actualWorker, CompletableSubscriber actionCompletable) { + Subscription oldState = get(); + // either SUBSCRIBED or UNSUBSCRIBED + if (oldState == UNSUBSCRIBED) { + // no need to schedule return + return; + } + if (oldState != SUBSCRIBED) { + // has already been scheduled return + // should not be able to get here but handle it anyway by not + // rescheduling. + return; + } + + Subscription newState = callActual(actualWorker, actionCompletable); + + if (!compareAndSet(SUBSCRIBED, newState)) { + // set would only fail if the new current state is some other + // subscription from a concurrent call to this method. + // Unsubscribe from the action just scheduled because it lost + // the race. + newState.unsubscribe(); + } + } + + protected abstract Subscription callActual(Worker actualWorker, CompletableSubscriber actionCompletable); + + @Override + public boolean isUnsubscribed() { + return get().isUnsubscribed(); + } + + @Override + public void unsubscribe() { + Subscription oldState; + // no matter what the current state is the new state is going to be + Subscription newState = UNSUBSCRIBED; + do { + oldState = get(); + if (oldState == UNSUBSCRIBED) { + // the action has already been unsubscribed + return; + } + } while (!compareAndSet(oldState, newState)); + + if (oldState != SUBSCRIBED) { + // the action was scheduled. stop it. + oldState.unsubscribe(); + } + } + } + + @SuppressWarnings("serial") + private static class ImmediateAction extends ScheduledAction { + private final Action0 action; + + public ImmediateAction(Action0 action) { + this.action = action; + } + + @Override + protected Subscription callActual(Worker actualWorker, CompletableSubscriber actionCompletable) { + return actualWorker.schedule(new OnCompletedAction(action, actionCompletable)); + } + } + + @SuppressWarnings("serial") + private static class DelayedAction extends ScheduledAction { + private final Action0 action; + private final long delayTime; + private final TimeUnit unit; + + public DelayedAction(Action0 action, long delayTime, TimeUnit unit) { + this.action = action; + this.delayTime = delayTime; + this.unit = unit; + } + + @Override + protected Subscription callActual(Worker actualWorker, CompletableSubscriber actionCompletable) { + return actualWorker.schedule(new OnCompletedAction(action, actionCompletable), delayTime, unit); + } + } + + private static class OnCompletedAction implements Action0 { + private CompletableSubscriber actionCompletable; + private Action0 action; + + public OnCompletedAction(Action0 action, CompletableSubscriber actionCompletable) { + this.action = action; + this.actionCompletable = actionCompletable; + } + + @Override + public void call() { + try { + action.call(); + } finally { + actionCompletable.onCompleted(); + } + } + } } diff --git a/src/test/java/rx/schedulers/SchedulerWhenTest.java b/src/test/java/rx/schedulers/SchedulerWhenTest.java index 49ff840e65..ed0e2f3792 100644 --- a/src/test/java/rx/schedulers/SchedulerWhenTest.java +++ b/src/test/java/rx/schedulers/SchedulerWhenTest.java @@ -16,6 +16,8 @@ package rx.schedulers; import static java.util.concurrent.TimeUnit.SECONDS; +import static rx.Observable.just; +import static rx.Observable.merge; import org.junit.Test; @@ -204,4 +206,17 @@ public Completable call(Completable worker) { }, tSched); return sched; } + + @Test(timeout=1000) + public void testRaceConditions() { + Scheduler comp = Schedulers.computation(); + Scheduler limited = comp.when(new Func1>, Completable>() { + @Override + public Completable call(Observable> t) { + return Completable.merge(Observable.merge(t, 10)); + } + }); + + merge(just(just(1).subscribeOn(limited).observeOn(comp)).repeat(1000)).toBlocking().subscribe(); + } } From eb58e5c849b04f7f46f0984ac95c31cb102de0d5 Mon Sep 17 00:00:00 2001 From: George Campbell Date: Thu, 10 Nov 2016 00:01:36 -0800 Subject: [PATCH 04/74] changing inner classes to package-private. (#4828) --- src/main/java/rx/internal/schedulers/SchedulerWhen.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/rx/internal/schedulers/SchedulerWhen.java b/src/main/java/rx/internal/schedulers/SchedulerWhen.java index c45ee5853c..1310a96e08 100644 --- a/src/main/java/rx/internal/schedulers/SchedulerWhen.java +++ b/src/main/java/rx/internal/schedulers/SchedulerWhen.java @@ -206,7 +206,7 @@ public boolean isUnsubscribed() { static final Subscription UNSUBSCRIBED = Subscriptions.unsubscribed(); @SuppressWarnings("serial") - private static abstract class ScheduledAction extends AtomicReferenceimplements Subscription { + static abstract class ScheduledAction extends AtomicReferenceimplements Subscription { public ScheduledAction() { super(SUBSCRIBED); } @@ -264,7 +264,7 @@ public void unsubscribe() { } @SuppressWarnings("serial") - private static class ImmediateAction extends ScheduledAction { + static class ImmediateAction extends ScheduledAction { private final Action0 action; public ImmediateAction(Action0 action) { @@ -278,7 +278,7 @@ protected Subscription callActual(Worker actualWorker, CompletableSubscriber act } @SuppressWarnings("serial") - private static class DelayedAction extends ScheduledAction { + static class DelayedAction extends ScheduledAction { private final Action0 action; private final long delayTime; private final TimeUnit unit; @@ -295,7 +295,7 @@ protected Subscription callActual(Worker actualWorker, CompletableSubscriber act } } - private static class OnCompletedAction implements Action0 { + static class OnCompletedAction implements Action0 { private CompletableSubscriber actionCompletable; private Action0 action; From bebdec6a52955ea478a992cebbd527364cb5b6a4 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 10 Nov 2016 09:13:06 +0100 Subject: [PATCH 05/74] 1.x: update AssertableSubscriber API and add Javadoc (#4824) --- src/main/java/rx/Completable.java | 2 +- src/main/java/rx/Observable.java | 5 +- .../AssertableSubscriberObservable.java | 39 ++- .../rx/observers/AssertableSubscriber.java | 202 +++++++++++++++- .../observers/AssertableSubscriberTest.java | 228 ++++++++++++++++-- 5 files changed, 438 insertions(+), 38 deletions(-) diff --git a/src/main/java/rx/Completable.java b/src/main/java/rx/Completable.java index 12d088c35d..37191e3b12 100644 --- a/src/main/java/rx/Completable.java +++ b/src/main/java/rx/Completable.java @@ -2365,7 +2365,7 @@ public void call() { } }); } - + // ------------------------------------------------------------------------- // Fluent test support, super handy and reduces test preparation boilerplate // ------------------------------------------------------------------------- diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 904ccec45c..0d25f8f3f2 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -12642,7 +12642,7 @@ public final Observable zipWith(Iterable other, Func2 Observable zipWith(Observable other, Func2 zipFunction) { return (Observable)zip(this, other, zipFunction); } - + // ------------------------------------------------------------------------- // Fluent test support, super handy and reduces test preparation boilerplate // ------------------------------------------------------------------------- @@ -12664,7 +12664,7 @@ public final AssertableSubscriber test() { subscribe(ts); return ts; } - + /** * Creates an AssertableSubscriber with the initial request amount and subscribes * it to this Observable. @@ -12675,6 +12675,7 @@ public final AssertableSubscriber test() { *
{@code test} does not operate by default on a particular {@link Scheduler}.
* * @return the new AssertableSubscriber instance + * @param initialRequestAmount the amount to request from upstream upfront, non-negative (not verified) * @since 1.2.3 */ @Experimental diff --git a/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java b/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java index db1c4f0532..b9068b04ff 100644 --- a/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java +++ b/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java @@ -135,8 +135,11 @@ public AssertableSubscriber assertReceivedOnNext(List items) { * @see rx.observers.AssertableSubscriber#awaitValueCount(int, long, java.util.concurrent.TimeUnit) */ @Override - public final boolean awaitValueCount(int expected, long timeout, TimeUnit unit) { - return ts.awaitValueCount(expected, timeout, unit); + public final AssertableSubscriber awaitValueCount(int expected, long timeout, TimeUnit unit) { + if (!ts.awaitValueCount(expected, timeout, unit)) { + throw new AssertionError("Did not receive enough values in time. Expected: " + expected + ", Actual: " + ts.getValueCount()); + } + return this; } /* (non-Javadoc) @@ -282,7 +285,7 @@ public AssertableSubscriber assertValue(T value) { ts.assertValue(value); return this; } - + /* (non-Javadoc) * @see rx.observers.AssertableSubscriber#assertValuesAndClear(T, T) */ @@ -307,4 +310,34 @@ public String toString() { return ts.toString(); } + @Override + public final AssertableSubscriber assertResult(T... values) { + ts.assertValues(values); + ts.assertNoErrors(); + ts.assertCompleted(); + return this; + } + + @Override + public final AssertableSubscriber assertFailure(Class errorClass, T... values) { + ts.assertValues(values); + ts.assertError(errorClass); + ts.assertNotCompleted(); + return this; + } + + @Override + public final AssertableSubscriber assertFailureAndMessage(Class errorClass, String message, + T... values) { + ts.assertValues(values); + ts.assertError(errorClass); + ts.assertNotCompleted(); + + String actualMessage = ts.getOnErrorEvents().get(0).getMessage(); + if (!(actualMessage == message || (message != null && message.equals(actualMessage)))) { + throw new AssertionError("Error message differs. Expected: \'" + message + "\', Received: \'" + actualMessage + "\'"); + } + + return this; + } } diff --git a/src/main/java/rx/observers/AssertableSubscriber.java b/src/main/java/rx/observers/AssertableSubscriber.java index c4199088cb..756d3049d0 100644 --- a/src/main/java/rx/observers/AssertableSubscriber.java +++ b/src/main/java/rx/observers/AssertableSubscriber.java @@ -18,70 +18,260 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import rx.Observer; -import rx.Producer; +import rx.*; +import rx.annotations.Experimental; import rx.functions.Action0; -public interface AssertableSubscriber extends Observer { +/** + * Interface for asserting the state of a sequence under testing with a {@code test()} + * method of a reactive base class. + *

+ * This interface is not intended to be implemented outside of RxJava. + *

+ * This interface extends {@link Observer} and allows injecting onXXX signals into + * the testing process. + * @param the value type consumed by this Observer + * @since 1.2.3 + */ +@Experimental +public interface AssertableSubscriber extends Observer, Subscription { + /** + * Allows manually calling the {@code onStart} method of the underlying Subscriber. + */ void onStart(); + /** + * Allows manually calling the {@code setProducer} method of the underlying Subscriber. + * @param p the producer to use, not null + */ void setProducer(Producer p); + /** + * Returns the number of {@code onCompleted} signals received by this Observer. + * @return the number of {@code onCompleted} signals received + */ int getCompletions(); + /** + * Returns a list of received {@code onError} signals. + * @return this + */ List getOnErrorEvents(); + /** + * Returns the number of {@code onNext} signals received by this Observer in + * a thread-safe manner; one can read up to this number of elements from + * the {@code List} returned by {@link #getOnNextEvents()}. + * @return the number of {@code onNext} signals received. + */ int getValueCount(); + /** + * Requests the specified amount of items from upstream. + * @param n the amount requested, non-negative + * @return this + */ AssertableSubscriber requestMore(long n); + /** + * Returns the list of received {@code onNext} events. + *

If the sequence hasn't completed yet and is asynchronous, use the + * {@link #getValueCount()} method to determine how many elements are safe + * to be read from the list returned by this method. + * @return the List of received {@code onNext} events. + */ List getOnNextEvents(); + /** + * Assert that this Observer received the given list of items as {@code onNext} signals + * in the same order and with the default null-safe object equals comparison. + * @param items the List of items expected + * @return this + */ AssertableSubscriber assertReceivedOnNext(List items); - boolean awaitValueCount(int expected, long timeout, TimeUnit unit); + /** + * Assert that this Observer receives at least the given number of {@code onNext} + * signals within the specified timeout period. + *

+ * Note that it is possible the AssertionError thrown by this method will + * contain an actual value >= to the expected one in case there is an emission + * race or unexpected delay on the emitter side. In this case, increase the timeout + * amount to avoid false positives. + * + * @param expected the expected (at least) number of {@code onNext} signals + * @param timeout the timeout to wait to receive the given number of {@code onNext} events + * @param unit the time unit + * @return this + */ + AssertableSubscriber awaitValueCount(int expected, long timeout, TimeUnit unit); + /** + * Assert that this Observer received either an {@code onError} or {@code onCompleted} signal. + * @return this + */ AssertableSubscriber assertTerminalEvent(); + /** + * Assert that this Observer has been unsubscribed via {@code unsubscribe()} or by a wrapping + * {@code SafeSubscriber}. + * @return this + */ AssertableSubscriber assertUnsubscribed(); + /** + * Assert that this Observer has not received any {@code onError} signal. + * @return this + */ AssertableSubscriber assertNoErrors(); + /** + * Waits for an {@code onError} or {code onCompleted} terminal event indefinitely. + * @return this + */ AssertableSubscriber awaitTerminalEvent(); + + /** + * Waits for an {@code onError} or {code onCompleted} terminal event for the given + * amount of timeout. + * @param timeout the time to wait for the terminal event + * @param unit the time unit of the wait time + * @return this + */ AssertableSubscriber awaitTerminalEvent(long timeout, TimeUnit unit); + /** + * Waits for an {@code onError} or {code onCompleted} terminal event for the given + * amount of timeout and unsubscribes the sequence if the timeout passed or the + * wait itself is interrupted. + * @param timeout the time to wait for the terminal event + * @param unit the time unit of the wait time + * @return this + */ AssertableSubscriber awaitTerminalEventAndUnsubscribeOnTimeout(long timeout, TimeUnit unit); + /** + * Returns the Thread that has called the last {@code onNext}, {@code onError} or + * {@code onCompleted} methods of this Observer. + * @return this + */ Thread getLastSeenThread(); + /** + * Assert that this Observer received exaclty one {@code onCompleted} signal. + * @return this + */ AssertableSubscriber assertCompleted(); + /** + * Assert that this Observer received no {@code onCompleted} signal. + * @return this + */ AssertableSubscriber assertNotCompleted(); + /** + * Assert that this Observer received one {@code onError} signal with + * the given subclass of a Throwable as type. + * @param clazz the expected type of the {@code onError} signal received + * @return this + */ AssertableSubscriber assertError(Class clazz); + /** + * Assert that this Observer received one {@code onError} signal with the + * object-equals of the given Throwable instance + * @param throwable the Throwable instance expected + * @return this + */ AssertableSubscriber assertError(Throwable throwable); + /** + * Assert that no {@code onError} or {@code onCompleted} signals were received so far. + * @return this + */ AssertableSubscriber assertNoTerminalEvent(); + /** + * Assert that no {@code onNext} signals were received so far. + * @return this + */ AssertableSubscriber assertNoValues(); + /** + * Assert that this Observer received exactly the given count of + * {@code onNext} signals. + * @param count the expected number of {@code onNext} signals + * @return this + */ AssertableSubscriber assertValueCount(int count); + /** + * Assert that this Observer received exactly the given expected values + * (compared via null-safe object equals) in the given order. + * @param values the expected values + * @return this + */ AssertableSubscriber assertValues(T... values); + /** + * Assert that this Observer received exactly the given single expected value + * (compared via null-safe object equals). + * @param value the single value expected + * @return this + */ AssertableSubscriber assertValue(T value); + /** + * Assert that this Observer received exactly the given values (compared via + * null-safe object equals) and if so, clears the internal buffer of the + * underlying Subscriber of these values. + * @param expectedFirstValue the first value expected + * @param expectedRestValues the rest of the values expected + * @return this + */ AssertableSubscriber assertValuesAndClear(T expectedFirstValue, T... expectedRestValues); + /** + * Performs an action given by the Action0 callback in a fluent manner. + * @param action the action to perform, not null + * @return this + */ AssertableSubscriber perform(Action0 action); - + + @Override void unsubscribe(); - + + @Override boolean isUnsubscribed(); + /** + * Assert that this Observer received the specified items in the given order followed + * by a completion signal and no errors. + * @param values the values expected + * @return this + */ + AssertableSubscriber assertResult(T... values); + + /** + * Assert that this Observer received the specified items in the given order followed + * by an error signal of the given type (but no completion signal). + * @param errorClass the expected Throwable subclass type + * @param values the expected values + * @return this + */ + AssertableSubscriber assertFailure(Class errorClass, T... values); + + /** + * Assert that this Observer received the specified items in the given order followed + * by an error signal of the given type and with the exact error message (but no completion signal). + * @param errorClass the expected Throwable subclass type + * @param message the expected error message returned by {@link Throwable#getMessage()} + * @param values the expected values + * @return this + */ + AssertableSubscriber assertFailureAndMessage(Class errorClass, String message, T... values); } \ No newline at end of file diff --git a/src/test/java/rx/observers/AssertableSubscriberTest.java b/src/test/java/rx/observers/AssertableSubscriberTest.java index 84128feada..838f57d6ec 100644 --- a/src/test/java/rx/observers/AssertableSubscriberTest.java +++ b/src/test/java/rx/observers/AssertableSubscriberTest.java @@ -15,51 +15,47 @@ */ package rx.observers; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; -import rx.Completable; +import rx.*; import rx.Observable; -import rx.Single; -import rx.functions.Action0; -import rx.functions.Actions; +import rx.exceptions.TestException; +import rx.functions.*; public class AssertableSubscriberTest { @Test public void testManyMaxValue() { - AssertableSubscriber ts = Observable.just(1, 2, 3) - .test() - .assertValues(1, 2, 3) + AssertableSubscriber ts = Observable.just(1, 2, 3) + .test() + .assertValues(1, 2, 3) .awaitTerminalEvent() .awaitTerminalEvent(5, TimeUnit.SECONDS) .awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS) - .assertCompleted() + .assertCompleted() .assertTerminalEvent() - .assertNoErrors() - .assertUnsubscribed() - .assertReceivedOnNext(Arrays.asList(1, 2, 3)) + .assertNoErrors() + .assertUnsubscribed() + .assertReceivedOnNext(Arrays.asList(1, 2, 3)) .assertValueCount(3); assertEquals(3, ts.getValueCount()); assertEquals(1, ts.getCompletions()); assertEquals(Thread.currentThread().getName(), ts.getLastSeenThread().getName()); assertEquals(Arrays.asList(1,2,3), ts.getOnNextEvents()); - assertTrue(ts.awaitValueCount(3, 5, TimeUnit.SECONDS)); + ts.awaitValueCount(3, 5, TimeUnit.SECONDS); } - + @Test public void testManyWithInitialRequest() { - AssertableSubscriber ts = Observable.just(1, 2, 3) - .test(1) + AssertableSubscriber ts = Observable.just(1, 2, 3) + .test(1) .assertValue(1) .assertValues(1) .assertValuesAndClear(1) @@ -72,7 +68,7 @@ public void testManyWithInitialRequest() { ts.assertUnsubscribed(); assertTrue(ts.isUnsubscribed()); } - + @Test public void testEmpty() { Observable.empty() @@ -89,13 +85,13 @@ public void testError() { .assertError(IOException.class); assertEquals(Arrays.asList(e), ts.getOnErrorEvents()); } - + @Test public void toStringIsNotNull() { AssertableSubscriber ts = Observable.empty().test(); assertNotNull(ts.toString()); } - + @Test public void testPerform() { final AtomicBoolean performed = new AtomicBoolean(false); @@ -109,7 +105,7 @@ public void call() { }); assertTrue(performed.get()); } - + @Test public void testCompletable() { AssertableSubscriber ts = Completable @@ -132,7 +128,7 @@ public void testCompletable() { assertTrue(ts.getOnNextEvents().isEmpty()); assertEquals(0, ts.getValueCount()); } - + @Test public void testSingle() { AssertableSubscriber ts = Single @@ -157,6 +153,186 @@ public void testSingle() { assertTrue(ts.getOnNextEvents().isEmpty()); assertEquals(1, ts.getValueCount()); } - + + @Test + public void assertResult() { + Observable.just(1) + .test() + .assertResult(1); + } + + @Test + public void assertResultFail() { + try { + Observable.just(1) + .test() + .assertResult(2); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.just(1) + .test() + .assertResult(); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.never() + .test() + .assertResult(1); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.error(new TestException()) + .test() + .assertResult(2); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + } + + @Test + public void assertFailure() { + Observable.error(new TestException()) + .test() + .assertFailure(TestException.class); + + Observable.just(1).concatWith(Observable.error(new TestException())) + .test() + .assertFailure(TestException.class, 1); + } + + @Test + public void assertFailureFail() { + try { + Observable.error(new TestException()) + .test() + .assertFailure(IOException.class); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.just(1) + .test() + .assertFailure(IOException.class); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.just(1) + .test() + .assertFailure(IOException.class, 1); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.empty() + .test() + .assertFailure(IOException.class, 1); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + } + + @Test + public void assertFailureAndMessage() { + Observable.error(new TestException("forced failure")) + .test() + .assertFailureAndMessage(TestException.class, "forced failure"); + + Observable.just(1).concatWith(Observable.error(new TestException("forced failure 2"))) + .test() + .assertFailureAndMessage(TestException.class, "forced failure 2", 1); + } + + @Test + public void assertFailureAndMessageFail() { + try { + Observable.error(new TestException()) + .test() + .assertFailureAndMessage(IOException.class, "forced failure"); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + try { + Observable.error(new TestException("forced failure")) + .test() + .assertFailureAndMessage(IOException.class, "forced failure"); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.just(1) + .test() + .assertFailureAndMessage(IOException.class, "forced failure"); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.just(1) + .test() + .assertFailureAndMessage(IOException.class, "forced failure", 1); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.empty() + .test() + .assertFailureAndMessage(IOException.class, "forced failure", 1); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.error(new TestException("failure forced")) + .test() + .assertFailureAndMessage(TestException.class, "forced failure"); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.just(1).concatWith(Observable.error(new TestException("failure forced"))) + .test() + .assertFailureAndMessage(TestException.class, "forced failure", 1); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + + try { + Observable.just(1).concatWith(Observable.error(new TestException())) + .test() + .assertFailureAndMessage(TestException.class, "forced failure", 1); + throw new RuntimeException("Should have thrown!"); // fail() doesn't work here because it also throws AssertionError and may look like the test passed + } catch (AssertionError ex) { + // expected + } + } } From 2cdf1c071cb7a69295fefa381f37504af76d2e83 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 10 Nov 2016 15:22:25 +0100 Subject: [PATCH 06/74] 1.x: Completable.doAfterTerminate to run after onError as well (#4830) --- src/main/java/rx/Completable.java | 20 +++++++++++++------- src/test/java/rx/CompletableTest.java | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/rx/Completable.java b/src/main/java/rx/Completable.java index 37191e3b12..e9b78c569f 100644 --- a/src/main/java/rx/Completable.java +++ b/src/main/java/rx/Completable.java @@ -1347,7 +1347,7 @@ public final Completable doOnError(Action1 onError) { * @param onSubscribe the consumer called when a CompletableSubscriber subscribes. * @param onError the consumer called when this emits an onError event * @param onComplete the runnable called just before when this Completable completes normally - * @param onAfterComplete the runnable called after this Completable completes normally + * @param onAfterTerminate the runnable called after this Completable terminates * @param onUnsubscribe the runnable called when the child cancels the subscription * @return the new Completable instance */ @@ -1355,12 +1355,12 @@ protected final Completable doOnLifecycle( final Action1 onSubscribe, final Action1 onError, final Action0 onComplete, - final Action0 onAfterComplete, + final Action0 onAfterTerminate, final Action0 onUnsubscribe) { requireNonNull(onSubscribe); requireNonNull(onError); requireNonNull(onComplete); - requireNonNull(onAfterComplete); + requireNonNull(onAfterTerminate); requireNonNull(onUnsubscribe); return create(new OnSubscribe() { @Override @@ -1379,7 +1379,7 @@ public void onCompleted() { s.onCompleted(); try { - onAfterComplete.call(); + onAfterTerminate.call(); } catch (Throwable e) { RxJavaHooks.onError(e); } @@ -1394,6 +1394,12 @@ public void onError(Throwable e) { } s.onError(e); + + try { + onAfterTerminate.call(); + } catch (Throwable ex) { + RxJavaHooks.onError(ex); + } } @Override @@ -1455,12 +1461,12 @@ public void call(Throwable e) { /** * Returns a Completable instance that calls the given onAfterComplete callback after this * Completable completes normally. - * @param onAfterComplete the callback to call after this Completable emits an onComplete event. + * @param onAfterTerminate the callback to call after this Completable emits an onCompleted or onError event. * @return the new Completable instance * @throws NullPointerException if onAfterComplete is null */ - public final Completable doAfterTerminate(Action0 onAfterComplete) { - return doOnLifecycle(Actions.empty(), Actions.empty(), Actions.empty(), onAfterComplete, Actions.empty()); + public final Completable doAfterTerminate(Action0 onAfterTerminate) { + return doOnLifecycle(Actions.empty(), Actions.empty(), Actions.empty(), onAfterTerminate, Actions.empty()); } /** diff --git a/src/test/java/rx/CompletableTest.java b/src/test/java/rx/CompletableTest.java index 72941a7300..98ee57b5b2 100644 --- a/src/test/java/rx/CompletableTest.java +++ b/src/test/java/rx/CompletableTest.java @@ -2058,7 +2058,7 @@ public void call() { // expected } - Assert.assertFalse("Closure called", doneAfter.get()); + Assert.assertTrue("Closure called", doneAfter.get()); } @Test(expected = NullPointerException.class) From aa1c4ed39ee91b65ec8abbfa64b91957fb9ad671 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sat, 12 Nov 2016 19:31:35 +0100 Subject: [PATCH 07/74] 1.x: replace non-serializable value of OnNextValue with its toString (#4841) --- .../java/rx/exceptions/OnErrorThrowable.java | 33 +++++++++++---- .../java/rx/exceptions/OnNextValueTest.java | 42 +++++++++++++++---- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/main/java/rx/exceptions/OnErrorThrowable.java b/src/main/java/rx/exceptions/OnErrorThrowable.java index 77c255a874..b8c0c3555f 100644 --- a/src/main/java/rx/exceptions/OnErrorThrowable.java +++ b/src/main/java/rx/exceptions/OnErrorThrowable.java @@ -15,11 +15,10 @@ */ package rx.exceptions; -import java.util.HashSet; -import java.util.Set; +import java.io.*; +import java.util.*; -import rx.plugins.RxJavaErrorHandler; -import rx.plugins.RxJavaPlugins; +import rx.plugins.*; /** * Represents a {@code Throwable} that an {@code Observable} might notify its subscribers of, but that then can @@ -43,7 +42,17 @@ private OnErrorThrowable(Throwable exception) { private OnErrorThrowable(Throwable exception, Object value) { super(exception); hasValue = true; - this.value = value; + Object v; + if (value instanceof Serializable) { + v = value; + } else { + try { + v = String.valueOf(value); + } catch (Throwable ex) { + v = ex.getMessage(); + } + } + this.value = v; } /** @@ -150,7 +159,17 @@ private static Set> create() { */ public OnNextValue(Object value) { super("OnError while emitting onNext value: " + renderValue(value)); - this.value = value; + Object v; + if (value instanceof Serializable) { + v = value; + } else { + try { + v = String.valueOf(value); + } catch (Throwable ex) { + v = ex.getMessage(); + } + } + this.value = v; } /** @@ -177,7 +196,7 @@ public Object getValue() { * @return a string version of the object if primitive or managed through error plugin, * otherwise the class name of the object */ - static String renderValue(Object value){ + static String renderValue(Object value) { if (value == null) { return "null"; } diff --git a/src/test/java/rx/exceptions/OnNextValueTest.java b/src/test/java/rx/exceptions/OnNextValueTest.java index 2e36c5bafd..31a37692f8 100644 --- a/src/test/java/rx/exceptions/OnNextValueTest.java +++ b/src/test/java/rx/exceptions/OnNextValueTest.java @@ -15,20 +15,16 @@ */ package rx.exceptions; +import static org.junit.Assert.*; + +import java.io.*; + import org.junit.Test; -import rx.Observable; -import rx.Observer; +import rx.*; import rx.exceptions.OnErrorThrowable.OnNextValue; import rx.functions.Func1; -import java.io.PrintWriter; -import java.io.StringWriter; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - /** * ```java * public OnNextValue(Object value) { @@ -166,4 +162,32 @@ public void testRenderDouble() { public void testRenderVoid() { assertEquals("null", OnNextValue.renderValue((Void) null)); } + + static class Value { + @Override + public String toString() { + return "Value"; + } + } + + @Test + public void nonSerializableValue() throws Exception { + Throwable e = OnErrorThrowable.addValueAsLastCause(new RuntimeException(), new Value()); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bout); + oos.writeObject(e); + oos.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bin); + + Throwable f = (Throwable)ois.readObject(); + + ois.close(); + + Object v = ((OnNextValue)f.getCause()).getValue(); + + assertEquals("Value", v); + } } From 077c4d0a4fd11612c6c60c1bfc92e339bc25962a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Karnok?= Date: Sun, 13 Nov 2016 23:24:34 +0100 Subject: [PATCH 08/74] 1.x: remove ObjectPool, code style cleanups --- src/main/java/rx/BackpressureOverflow.java | 16 +- src/main/java/rx/Observable.java | 4 +- src/main/java/rx/Scheduler.java | 20 +- .../rx/exceptions/CompositeException.java | 6 +- .../operators/BufferUntilSubscriber.java | 2 +- .../rx/internal/operators/OnSubscribeAmb.java | 8 +- .../operators/OnSubscribeAutoConnect.java | 2 +- .../internal/operators/OnSubscribeRedo.java | 6 +- .../operators/OnSubscribeToMultimap.java | 2 +- .../internal/operators/OperatorGroupBy.java | 2 +- .../internal/operators/OperatorMulticast.java | 2 +- .../operators/OperatorOnBackpressureDrop.java | 2 +- .../internal/operators/OperatorPublish.java | 5 +- .../rx/internal/operators/OperatorSwitch.java | 2 +- .../rx/internal/operators/OperatorTake.java | 2 +- .../schedulers/CachedThreadScheduler.java | 4 +- .../rx/internal/schedulers/SchedulerWhen.java | 22 +- .../rx/internal/util/IndexedRingBuffer.java | 13 +- .../java/rx/internal/util/ObjectPool.java | 163 --------- .../java/rx/internal/util/OpenHashSet.java | 2 +- .../java/rx/internal/util/RxRingBuffer.java | 42 +-- .../rx/internal/util/SynchronizedQueue.java | 163 --------- .../atomic/AtomicReferenceArrayQueue.java | 2 +- .../util/atomic/BaseLinkedAtomicQueue.java | 2 +- .../util/atomic/MpscLinkedAtomicQueue.java | 4 +- .../util/atomic/SpscAtomicArrayQueue.java | 4 +- .../atomic/SpscExactAtomicArrayQueue.java | 2 +- .../util/atomic/SpscLinkedArrayQueue.java | 4 +- .../atomic/SpscUnboundedAtomicArrayQueue.java | 4 +- .../internal/util/unsafe/BaseLinkedQueue.java | 2 +- .../unsafe/ConcurrentCircularArrayQueue.java | 2 +- .../internal/util/unsafe/MpscLinkedQueue.java | 6 +- .../java/rx/internal/util/unsafe/README.md | 2 +- .../internal/util/unsafe/SpmcArrayQueue.java | 4 +- .../internal/util/unsafe/SpscArrayQueue.java | 4 +- .../util/unsafe/SpscUnboundedArrayQueue.java | 8 +- .../java/rx/observables/SyncOnSubscribe.java | 4 +- src/main/java/rx/schedulers/Schedulers.java | 42 ++- src/perf/java/rx/ScalarJustPerf.java | 2 +- src/perf/java/rx/SingleSourcePerf.java | 2 +- .../rx/jmh/InputWithIncrementingInteger.java | 2 +- .../rx/jmh/PerfAsyncSingleSubscriber.java | 2 +- .../rx/observables/SyncOnSubscribePerf.java | 10 +- src/perf/java/rx/operators/ZipPerf.java | 8 +- src/test/java/rx/BackpressureTests.java | 4 +- .../rx/CapturingUncaughtExceptionHandler.java | 2 +- src/test/java/rx/CompletableTest.java | 14 +- src/test/java/rx/NotificationTest.java | 21 +- src/test/java/rx/ObservableTests.java | 4 +- src/test/java/rx/SingleTest.java | 2 +- src/test/java/rx/SubscriberTest.java | 2 +- src/test/java/rx/TestUtil.java | 4 +- .../rx/exceptions/CompositeExceptionTest.java | 18 +- .../BlockingOperatorToFutureTest.java | 8 +- .../DeferredScalarSubscriberTest.java | 10 +- .../OnSubscribeCombineLatestTest.java | 4 +- .../operators/OnSubscribeDoOnEachTest.java | 6 +- .../operators/OnSubscribeFromEmitterTest.java | 6 +- .../OnSubscribeFromIterableTest.java | 10 +- .../operators/OnSubscribeMapTest.java | 2 +- .../operators/OnSubscribeUsingTest.java | 4 +- .../internal/operators/OperatorAllTest.java | 4 +- .../internal/operators/OperatorAnyTest.java | 4 +- .../operators/OperatorBufferTest.java | 2 +- .../operators/OperatorConcatTest.java | 31 +- .../internal/operators/OperatorDelayTest.java | 8 +- .../operators/OperatorGroupByTest.java | 22 +- .../operators/OperatorMaterializeTest.java | 4 +- .../OperatorMergeMaxConcurrentTest.java | 2 +- .../internal/operators/OperatorMergeTest.java | 17 +- .../OperatorOnBackpressureBufferTest.java | 2 +- .../OperatorOnBackpressureDropTest.java | 4 +- .../OperatorOnBackpressureLatestTest.java | 2 +- ...ratorOnErrorResumeNextViaFunctionTest.java | 7 +- ...torOnErrorResumeNextViaObservableTest.java | 10 +- .../operators/OperatorOnErrorReturnTest.java | 7 +- ...nExceptionResumeNextViaObservableTest.java | 16 +- .../operators/OperatorPublishTest.java | 2 +- .../internal/operators/OperatorRetryTest.java | 18 +- .../OperatorRetryWithPredicateTest.java | 4 +- .../operators/OperatorSerializeTest.java | 11 +- .../internal/operators/OperatorSkipTest.java | 2 +- .../operators/OperatorSkipWhileTest.java | 5 +- .../operators/OperatorSwitchTest.java | 24 +- .../operators/OperatorTakeLastTest.java | 8 +- .../operators/OperatorTakeLastTimedTest.java | 2 +- .../internal/operators/OperatorTakeTest.java | 2 +- .../operators/OperatorTakeUntilTest.java | 2 +- .../operators/OperatorTakeWhileTest.java | 6 +- .../OperatorTimeoutWithSelectorTest.java | 6 +- .../OperatorToObservableSortedListTest.java | 4 +- .../operators/OperatorZipIterableTest.java | 4 +- .../internal/operators/OperatorZipTest.java | 2 +- .../operators/SafeSubscriberTest.java | 2 +- .../operators/SingleOnSubscribeUsingTest.java | 4 +- .../producers/SingleDelayedProducerTest.java | 4 +- .../schedulers/NewThreadWorkerTest.java | 2 +- .../internal/util/IndexedRingBufferTest.java | 2 +- .../rx/internal/util/JCToolsQueueTests.java | 8 +- .../internal/util/SynchronizedQueueTest.java | 155 --------- .../rx/observables/AsyncOnSubscribeTest.java | 79 ++--- .../observables/BlockingObservableTest.java | 2 +- .../rx/observables/SyncOnSubscribeTest.java | 29 +- .../java/rx/observers/SafeSubscriberTest.java | 6 +- .../rx/observers/SerializedObserverTest.java | 8 +- .../java/rx/plugins/RxJavaPluginsTest.java | 2 +- .../AbstractSchedulerConcurrencyTests.java | 8 +- .../rx/schedulers/AbstractSchedulerTests.java | 6 +- .../schedulers/ComputationSchedulerTests.java | 2 +- .../java/rx/schedulers/SchedulerTests.java | 20 +- .../java/rx/schedulers/SchedulerWhenTest.java | 320 +++++++++--------- .../schedulers/TrampolineSchedulerTest.java | 2 +- .../subjects/BufferUntilSubscriberTest.java | 11 +- src/test/java/rx/util/AssertObservable.java | 23 +- 114 files changed, 607 insertions(+), 1065 deletions(-) delete mode 100644 src/main/java/rx/internal/util/ObjectPool.java delete mode 100644 src/main/java/rx/internal/util/SynchronizedQueue.java delete mode 100644 src/test/java/rx/internal/util/SynchronizedQueueTest.java diff --git a/src/main/java/rx/BackpressureOverflow.java b/src/main/java/rx/BackpressureOverflow.java index b47e40f825..39948d8804 100644 --- a/src/main/java/rx/BackpressureOverflow.java +++ b/src/main/java/rx/BackpressureOverflow.java @@ -26,6 +26,10 @@ @Beta public final class BackpressureOverflow { + private BackpressureOverflow() { + throw new IllegalStateException("No instances!"); + } + /** * Signal a MissingBackressureException due to lack of requests. */ @@ -65,10 +69,10 @@ public interface Strategy { /** * Drop oldest items from the buffer making room for newer ones. */ - static class DropOldest implements BackpressureOverflow.Strategy { + static final class DropOldest implements BackpressureOverflow.Strategy { static final DropOldest INSTANCE = new DropOldest(); - private DropOldest() {} + private DropOldest() { } @Override public boolean mayAttemptDrop() { @@ -80,10 +84,10 @@ public boolean mayAttemptDrop() { * Drop most recent items, but not {@code onError} nor unsubscribe from source * (as {code OperatorOnBackpressureDrop}). */ - static class DropLatest implements BackpressureOverflow.Strategy { + static final class DropLatest implements BackpressureOverflow.Strategy { static final DropLatest INSTANCE = new DropLatest(); - private DropLatest() {} + private DropLatest() { } @Override public boolean mayAttemptDrop() { @@ -94,11 +98,11 @@ public boolean mayAttemptDrop() { /** * {@code onError} a MissingBackpressureException and unsubscribe from source. */ - static class Error implements BackpressureOverflow.Strategy { + static final class Error implements BackpressureOverflow.Strategy { static final Error INSTANCE = new Error(); - private Error() {} + private Error() { } @Override public boolean mayAttemptDrop() throws MissingBackpressureException { diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 0d25f8f3f2..434cbd22e8 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -3470,7 +3470,7 @@ public static Observable range(int start, int count) { if (start > Integer.MAX_VALUE - count + 1) { throw new IllegalArgumentException("start + count can not exceed Integer.MAX_VALUE"); } - if(count == 1) { + if (count == 1) { return Observable.just(start); } return Observable.create(new OnSubscribeRange(start, start + (count - 1))); @@ -11742,7 +11742,7 @@ public final Observable> toSortedList(Func2 sorted(){ + public final Observable sorted() { return toSortedList().flatMapIterable(UtilityFunctions.>identity()); } diff --git a/src/main/java/rx/Scheduler.java b/src/main/java/rx/Scheduler.java index 9dc789d463..bbcd19ae34 100644 --- a/src/main/java/rx/Scheduler.java +++ b/src/main/java/rx/Scheduler.java @@ -212,9 +212,9 @@ public long now() { * *
      * Scheduler limitScheduler = Schedulers.computation().when(workers -> {
-     * 	// use merge max concurrent to limit the number of concurrent
-     * 	// callbacks two at a time
-     * 	return Completable.merge(Observable.merge(workers), 2);
+     *     // use merge max concurrent to limit the number of concurrent
+     *     // callbacks two at a time
+     *     return Completable.merge(Observable.merge(workers), 2);
      * });
      * 
*

@@ -230,9 +230,9 @@ public long now() { * *

      * Scheduler limitScheduler = Schedulers.computation().when(workers -> {
-     * 	// use merge max concurrent to limit the number of concurrent
-     * 	// Observables two at a time
-     * 	return Completable.merge(Observable.merge(workers, 2));
+     *     // use merge max concurrent to limit the number of concurrent
+     *     // Observables two at a time
+     *     return Completable.merge(Observable.merge(workers, 2));
      * });
      * 
* @@ -243,10 +243,10 @@ public long now() { * *
      * Scheduler slowScheduler = Schedulers.computation().when(workers -> {
-     * 	// use concatenate to make each worker happen one at a time.
-     * 	return Completable.concat(workers.map(actions -> {
-     * 		// delay the starting of the next worker by 1 second.
-     * 		return Completable.merge(actions.delaySubscription(1, TimeUnit.SECONDS));
+     *     // use concatenate to make each worker happen one at a time.
+     *     return Completable.concat(workers.map(actions -> {
+     *         // delay the starting of the next worker by 1 second.
+     *         return Completable.merge(actions.delaySubscription(1, TimeUnit.SECONDS));
      *    }));
      * });
      * 
diff --git a/src/main/java/rx/exceptions/CompositeException.java b/src/main/java/rx/exceptions/CompositeException.java index 8c40d37bb7..cfbfdc2113 100644 --- a/src/main/java/rx/exceptions/CompositeException.java +++ b/src/main/java/rx/exceptions/CompositeException.java @@ -141,7 +141,7 @@ public synchronized Throwable getCause() { // NOPMD List listOfCauses = getListOfCauses(e); // check if any of them have been seen before - for(Throwable child : listOfCauses) { + for (Throwable child : listOfCauses) { if (seenCauses.contains(child)) { // already seen this outer Throwable so skip e = new RuntimeException("Duplicate found in causal chain so cropping to prevent loop ..."); @@ -288,7 +288,7 @@ private List getListOfCauses(Throwable ex) { if (root == null || root == ex) { return list; } else { - while(true) { + while (true) { list.add(root); Throwable cause = root.getCause(); if (cause == null || cause == root) { @@ -311,7 +311,7 @@ private Throwable getRootCause(Throwable e) { if (root == null || root == e) { return e; } else { - while(true) { + while (true) { Throwable cause = root.getCause(); if (cause == null || cause == root) { return root; diff --git a/src/main/java/rx/internal/operators/BufferUntilSubscriber.java b/src/main/java/rx/internal/operators/BufferUntilSubscriber.java index 2a4401c52c..7855bdc5d9 100644 --- a/src/main/java/rx/internal/operators/BufferUntilSubscriber.java +++ b/src/main/java/rx/internal/operators/BufferUntilSubscriber.java @@ -102,7 +102,7 @@ public void call() { } } if (win) { - while(true) { + while (true) { Object o; while ((o = state.buffer.poll()) != null) { NotificationLite.accept(state.get(), o); diff --git a/src/main/java/rx/internal/operators/OnSubscribeAmb.java b/src/main/java/rx/internal/operators/OnSubscribeAmb.java index d64567b340..bd0b0fe2b5 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeAmb.java +++ b/src/main/java/rx/internal/operators/OnSubscribeAmb.java @@ -29,7 +29,7 @@ * Given multiple {@link Observable}s, propagates the one that first emits an item. * @param the value type */ -public final class OnSubscribeAmb implements OnSubscribe{ +public final class OnSubscribeAmb implements OnSubscribe { //give default access instead of private as a micro-optimization //for access from anonymous classes below final Iterable> sources; @@ -336,12 +336,12 @@ private boolean isSelected() { } @SuppressWarnings("serial") - static final class Selection extends AtomicReference> { + static final class Selection extends AtomicReference> { final Collection> ambSubscribers = new ConcurrentLinkedQueue>(); public void unsubscribeLosers() { AmbSubscriber winner = get(); - if(winner != null) { + if (winner != null) { unsubscribeOthers(winner); } } @@ -437,7 +437,7 @@ public void request(long n) { } static void unsubscribeAmbSubscribers(Collection> ambSubscribers) { - if(!ambSubscribers.isEmpty()) { + if (!ambSubscribers.isEmpty()) { for (AmbSubscriber other : ambSubscribers) { other.unsubscribe(); } diff --git a/src/main/java/rx/internal/operators/OnSubscribeAutoConnect.java b/src/main/java/rx/internal/operators/OnSubscribeAutoConnect.java index 87a81ae7e8..cf6e7e7473 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeAutoConnect.java +++ b/src/main/java/rx/internal/operators/OnSubscribeAutoConnect.java @@ -33,7 +33,7 @@ public final class OnSubscribeAutoConnect extends AtomicInteger implements OnSubscribe { // AtomicInteger aspect of `this` represents the number of clients - final ConnectableObservable source; + final ConnectableObservable source; final int numberOfSubscribers; final Action1 connection; diff --git a/src/main/java/rx/internal/operators/OnSubscribeRedo.java b/src/main/java/rx/internal/operators/OnSubscribeRedo.java index 628c58f4ef..fc9fe9e4d2 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeRedo.java +++ b/src/main/java/rx/internal/operators/OnSubscribeRedo.java @@ -78,12 +78,12 @@ public Observable call(Observable> ts) { @Override public Notification call(Notification terminalNotification) { - if(count == 0) { + if (count == 0) { return terminalNotification; } num++; - if(num <= count) { + if (num <= count) { return Notification.createOnNext(num); } else { return terminalNotification; @@ -153,7 +153,7 @@ public static Observable repeat(Observable source, final long count) { } public static Observable repeat(Observable source, final long count, Scheduler scheduler) { - if(count == 0) { + if (count == 0) { return Observable.empty(); } if (count < 0) { diff --git a/src/main/java/rx/internal/operators/OnSubscribeToMultimap.java b/src/main/java/rx/internal/operators/OnSubscribeToMultimap.java index 6883e93d24..c412ea5af5 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeToMultimap.java +++ b/src/main/java/rx/internal/operators/OnSubscribeToMultimap.java @@ -155,7 +155,7 @@ public void onStart() { @Override public void onNext(T t) { - if (done){ + if (done) { return; } try { diff --git a/src/main/java/rx/internal/operators/OperatorGroupBy.java b/src/main/java/rx/internal/operators/OperatorGroupBy.java index abbe5cf3cf..af2fd4347a 100644 --- a/src/main/java/rx/internal/operators/OperatorGroupBy.java +++ b/src/main/java/rx/internal/operators/OperatorGroupBy.java @@ -43,7 +43,7 @@ * @param * the value type of the groups */ -public final class OperatorGroupBy implements Operator, T>{ +public final class OperatorGroupBy implements Operator, T> { final Func1 keySelector; final Func1 valueSelector; final int bufferSize; diff --git a/src/main/java/rx/internal/operators/OperatorMulticast.java b/src/main/java/rx/internal/operators/OperatorMulticast.java index d07f60bf93..3f0777ca91 100644 --- a/src/main/java/rx/internal/operators/OperatorMulticast.java +++ b/src/main/java/rx/internal/operators/OperatorMulticast.java @@ -112,7 +112,7 @@ public void call() { guardedSubscription = gs.get(); // register any subscribers that are waiting with this new subject - for(final Subscriber s : waitingForConnect) { + for (final Subscriber s : waitingForConnect) { subject.unsafeSubscribe(new Subscriber(s) { @Override public void onNext(R t) { diff --git a/src/main/java/rx/internal/operators/OperatorOnBackpressureDrop.java b/src/main/java/rx/internal/operators/OperatorOnBackpressureDrop.java index 6c8770dd04..5ed221746d 100644 --- a/src/main/java/rx/internal/operators/OperatorOnBackpressureDrop.java +++ b/src/main/java/rx/internal/operators/OperatorOnBackpressureDrop.java @@ -99,7 +99,7 @@ public void onNext(T t) { requested.decrementAndGet(); } else { // item dropped - if(onDrop != null) { + if (onDrop != null) { try { onDrop.call(t); } catch (Throwable e) { diff --git a/src/main/java/rx/internal/operators/OperatorPublish.java b/src/main/java/rx/internal/operators/OperatorPublish.java index f7879a7ee1..7d087efcb4 100644 --- a/src/main/java/rx/internal/operators/OperatorPublish.java +++ b/src/main/java/rx/internal/operators/OperatorPublish.java @@ -21,7 +21,8 @@ import rx.*; import rx.exceptions.*; import rx.functions.*; -import rx.internal.util.*; +import rx.internal.util.RxRingBuffer; +import rx.internal.util.atomic.SpscAtomicArrayQueue; import rx.internal.util.unsafe.*; import rx.observables.ConnectableObservable; import rx.subscriptions.Subscriptions; @@ -244,7 +245,7 @@ static final class PublishSubscriber extends Subscriber implements Subscri public PublishSubscriber(AtomicReference> current) { this.queue = UnsafeAccess.isUnsafeAvailable() ? new SpscArrayQueue(RxRingBuffer.SIZE) - : new SynchronizedQueue(RxRingBuffer.SIZE); + : new SpscAtomicArrayQueue(RxRingBuffer.SIZE); this.producers = new AtomicReference(EMPTY); this.current = current; diff --git a/src/main/java/rx/internal/operators/OperatorSwitch.java b/src/main/java/rx/internal/operators/OperatorSwitch.java index 1f2806ab53..e50e7cafc9 100644 --- a/src/main/java/rx/internal/operators/OperatorSwitch.java +++ b/src/main/java/rx/internal/operators/OperatorSwitch.java @@ -113,7 +113,7 @@ public void call() { clearProducer(); } })); - child.setProducer(new Producer(){ + child.setProducer(new Producer() { @Override public void request(long n) { diff --git a/src/main/java/rx/internal/operators/OperatorTake.java b/src/main/java/rx/internal/operators/OperatorTake.java index 7835327ec4..0be75b4f2c 100644 --- a/src/main/java/rx/internal/operators/OperatorTake.java +++ b/src/main/java/rx/internal/operators/OperatorTake.java @@ -97,7 +97,7 @@ public void setProducer(final Producer producer) { @Override public void request(long n) { - if (n >0 && !completed) { + if (n > 0 && !completed) { // because requests may happen concurrently use a CAS loop to // ensure we only request as much as needed, no more no less while (true) { diff --git a/src/main/java/rx/internal/schedulers/CachedThreadScheduler.java b/src/main/java/rx/internal/schedulers/CachedThreadScheduler.java index 940fe685f2..e5728540d5 100644 --- a/src/main/java/rx/internal/schedulers/CachedThreadScheduler.java +++ b/src/main/java/rx/internal/schedulers/CachedThreadScheduler.java @@ -24,7 +24,7 @@ import rx.subscriptions.*; public final class CachedThreadScheduler extends Scheduler implements SchedulerLifecycle { - private static final long KEEP_ALIVE_TIME = 60; + private static final long KEEP_ALIVE_TIME; private static final TimeUnit KEEP_ALIVE_UNIT = TimeUnit.SECONDS; static final ThreadWorker SHUTDOWN_THREADWORKER; @@ -41,6 +41,8 @@ public final class CachedThreadScheduler extends Scheduler implements SchedulerL NONE = new CachedWorkerPool(null, 0, null); NONE.shutdown(); + + KEEP_ALIVE_TIME = Integer.getInteger("rx.io-scheduler.keepalive", 60); } static final class CachedWorkerPool { diff --git a/src/main/java/rx/internal/schedulers/SchedulerWhen.java b/src/main/java/rx/internal/schedulers/SchedulerWhen.java index 1310a96e08..880992c9d5 100644 --- a/src/main/java/rx/internal/schedulers/SchedulerWhen.java +++ b/src/main/java/rx/internal/schedulers/SchedulerWhen.java @@ -63,9 +63,9 @@ * *
  * Scheduler limitScheduler = Schedulers.computation().when(workers -> {
- * 	// use merge max concurrent to limit the number of concurrent
- * 	// callbacks two at a time
- * 	return Completable.merge(Observable.merge(workers), 2);
+ *     // use merge max concurrent to limit the number of concurrent
+ *     // callbacks two at a time
+ *     return Completable.merge(Observable.merge(workers), 2);
  * });
  * 
*

@@ -81,9 +81,9 @@ * *

  * Scheduler limitScheduler = Schedulers.computation().when(workers -> {
- * 	// use merge max concurrent to limit the number of concurrent
- * 	// Observables two at a time
- * 	return Completable.merge(Observable.merge(workers, 2));
+ *     // use merge max concurrent to limit the number of concurrent
+ *     // Observables two at a time
+ *     return Completable.merge(Observable.merge(workers, 2));
  * });
  * 
* @@ -94,11 +94,11 @@ * *
  * Scheduler slowScheduler = Schedulers.computation().when(workers -> {
- * 	// use concatenate to make each worker happen one at a time.
- * 	return Completable.concat(workers.map(actions -> {
- * 		// delay the starting of the next worker by 1 second.
- * 		return Completable.merge(actions.delaySubscription(1, TimeUnit.SECONDS));
- * 	}));
+ *     // use concatenate to make each worker happen one at a time.
+ *     return Completable.concat(workers.map(actions -> {
+ *         // delay the starting of the next worker by 1 second.
+ *         return Completable.merge(actions.delaySubscription(1, TimeUnit.SECONDS));
+ *     }));
  * });
  * 
*/ diff --git a/src/main/java/rx/internal/util/IndexedRingBuffer.java b/src/main/java/rx/internal/util/IndexedRingBuffer.java index 3699fa1d8e..30ba900b7e 100644 --- a/src/main/java/rx/internal/util/IndexedRingBuffer.java +++ b/src/main/java/rx/internal/util/IndexedRingBuffer.java @@ -52,15 +52,6 @@ public final class IndexedRingBuffer implements Subscription { /* package for unit testing */final AtomicInteger index = new AtomicInteger(); /* package for unit testing */final AtomicInteger removedIndex = new AtomicInteger(); - private static final ObjectPool> POOL = new ObjectPool>() { - - @Override - protected IndexedRingBuffer createObject() { - return new IndexedRingBuffer(); - } - - }; - /* package for unit testing */static final int SIZE; // default size of ring buffer @@ -255,9 +246,8 @@ protected IndexedRingBuffer createObject() { SIZE = defaultSize; } - @SuppressWarnings("unchecked") public static IndexedRingBuffer getInstance() { - return (IndexedRingBuffer) POOL.borrowObject(); + return new IndexedRingBuffer(); } /** @@ -283,7 +273,6 @@ public void releaseToPool() { index.set(0); removedIndex.set(0); - POOL.returnObject(this); } @Override diff --git a/src/main/java/rx/internal/util/ObjectPool.java b/src/main/java/rx/internal/util/ObjectPool.java deleted file mode 100644 index 032e1338c3..0000000000 --- a/src/main/java/rx/internal/util/ObjectPool.java +++ /dev/null @@ -1,163 +0,0 @@ -/** - * 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. - * - * Modified from http://www.javacodegeeks.com/2013/08/simple-and-lightweight-pool-implementation.html - */ -package rx.internal.util; - -import java.util.Queue; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicReference; - -import rx.internal.schedulers.*; -import rx.internal.util.unsafe.*; -import rx.plugins.RxJavaHooks; - -public abstract class ObjectPool implements SchedulerLifecycle { - Queue pool; - final int minSize; - final int maxSize; - private final long validationInterval; - - private final AtomicReference> periodicTask; - - public ObjectPool() { - this(0, 0, 67); // NOPMD - } - - /** - * Creates the pool. - * - * @param min - * minimum number of objects residing in the pool - * @param max - * maximum number of objects residing in the pool - * @param validationInterval - * time in seconds for periodical checking of minIdle / maxIdle conditions in a separate thread. - * When the number of objects is less than minIdle, missing instances will be created. - * When the number of objects is greater than maxIdle, too many instances will be removed. - */ - private ObjectPool(final int min, final int max, final long validationInterval) { - this.minSize = min; - this.maxSize = max; - this.validationInterval = validationInterval; - this.periodicTask = new AtomicReference>(); - // initialize pool - initialize(min); - - start(); - } - - /** - * Gets the next free object from the pool. If the pool doesn't contain any objects, - * a new object will be created and given to the caller of this method back. - * - * @return T borrowed object - */ - public T borrowObject() { - T object; - if ((object = pool.poll()) == null) { - object = createObject(); - } - - return object; - } - - /** - * Returns object back to the pool. - * - * @param object - * object to be returned - */ - public void returnObject(T object) { - if (object == null) { - return; - } - - this.pool.offer(object); - } - - /** - * Shutdown this pool. - */ - @Override - public void shutdown() { - Future f = periodicTask.getAndSet(null); - if (f != null) { - f.cancel(false); - } - } - - @Override - public void start() { - for (;;) { - if (periodicTask.get() != null) { - return; - } - ScheduledExecutorService w = GenericScheduledExecutorService.getInstance(); - - Future f; - try { - f = w.scheduleAtFixedRate(new Runnable() { - - @Override - public void run() { - int size = pool.size(); - if (size < minSize) { - int sizeToBeAdded = maxSize - size; - for (int i = 0; i < sizeToBeAdded; i++) { - pool.add(createObject()); - } - } else if (size > maxSize) { - int sizeToBeRemoved = size - maxSize; - for (int i = 0; i < sizeToBeRemoved; i++) { - // pool.pollLast(); - pool.poll(); - } - } - } - - }, validationInterval, validationInterval, TimeUnit.SECONDS); - } catch (RejectedExecutionException ex) { - RxJavaHooks.onError(ex); - break; - } - if (!periodicTask.compareAndSet(null, f)) { - f.cancel(false); - } else { - break; - } - } - } - - /** - * Creates a new object. - * - * @return T new object - */ - protected abstract T createObject(); - - private void initialize(final int min) { - if (UnsafeAccess.isUnsafeAvailable()) { - pool = new MpmcArrayQueue(Math.max(maxSize, 1024)); - } else { - pool = new ConcurrentLinkedQueue(); - } - - for (int i = 0; i < min; i++) { - pool.add(createObject()); - } - } -} \ No newline at end of file diff --git a/src/main/java/rx/internal/util/OpenHashSet.java b/src/main/java/rx/internal/util/OpenHashSet.java index c5045ace70..238411656f 100644 --- a/src/main/java/rx/internal/util/OpenHashSet.java +++ b/src/main/java/rx/internal/util/OpenHashSet.java @@ -173,7 +173,7 @@ void rehash() { for (int j = size; j-- != 0; ) { - while (a[--i] == null); // NOPMD + while (a[--i] == null) { } // NOPMD int pos = mix(a[i].hashCode()) & m; if (b[pos] != null) { for (;;) { diff --git a/src/main/java/rx/internal/util/RxRingBuffer.java b/src/main/java/rx/internal/util/RxRingBuffer.java index dfbb6cbd6f..366fffd4c2 100644 --- a/src/main/java/rx/internal/util/RxRingBuffer.java +++ b/src/main/java/rx/internal/util/RxRingBuffer.java @@ -21,6 +21,7 @@ import rx.Subscription; import rx.exceptions.MissingBackpressureException; import rx.internal.operators.NotificationLite; +import rx.internal.util.atomic.SpscAtomicArrayQueue; import rx.internal.util.unsafe.SpmcArrayQueue; import rx.internal.util.unsafe.SpscArrayQueue; import rx.internal.util.unsafe.UnsafeAccess; @@ -128,7 +129,6 @@ public class RxRingBuffer implements Subscription { private Queue queue; private final int size; - private final ObjectPool> pool; /** * We store the terminal state separately so it doesn't count against the size. @@ -261,29 +261,9 @@ public class RxRingBuffer implements Subscription { } public static final int SIZE; - /* Public so Schedulers can manage the lifecycle of the inner worker. */ - public static final ObjectPool> SPSC_POOL = new ObjectPool>() { - - @Override - protected SpscArrayQueue createObject() { - return new SpscArrayQueue(SIZE); - } - - }; - - /* Public so Schedulers can manage the lifecycle of the inner worker. */ - public static final ObjectPool> SPMC_POOL = new ObjectPool>() { - - @Override - protected SpmcArrayQueue createObject() { - return new SpmcArrayQueue(SIZE); - } - - }; - public static RxRingBuffer getSpscInstance() { if (UnsafeAccess.isUnsafeAvailable()) { - return new RxRingBuffer(SPSC_POOL, SIZE); + return new RxRingBuffer(false, SIZE); } else { return new RxRingBuffer(); } @@ -291,7 +271,7 @@ public static RxRingBuffer getSpscInstance() { public static RxRingBuffer getSpmcInstance() { if (UnsafeAccess.isUnsafeAvailable()) { - return new RxRingBuffer(SPMC_POOL, SIZE); + return new RxRingBuffer(true, SIZE); } else { return new RxRingBuffer(); } @@ -299,24 +279,16 @@ public static RxRingBuffer getSpmcInstance() { private RxRingBuffer(Queue queue, int size) { this.queue = queue; - this.pool = null; this.size = size; } - private RxRingBuffer(ObjectPool> pool, int size) { - this.pool = pool; - this.queue = pool.borrowObject(); + private RxRingBuffer(boolean spmc, int size) { + this.queue = spmc ? new SpmcArrayQueue(size) : new SpscArrayQueue(size); this.size = size; } public synchronized void release() { // NOPMD - Queue q = queue; - ObjectPool> p = pool; - if (p != null && q != null) { - q.clear(); - queue = null; - p.returnObject(q); - } + // 1.2.3: no longer pooling } @Override @@ -325,7 +297,7 @@ public void unsubscribe() { } /* package accessible for unit tests */RxRingBuffer() { - this(new SynchronizedQueue(SIZE), SIZE); + this(new SpscAtomicArrayQueue(SIZE), SIZE); } /** diff --git a/src/main/java/rx/internal/util/SynchronizedQueue.java b/src/main/java/rx/internal/util/SynchronizedQueue.java deleted file mode 100644 index 27ae5de7f5..0000000000 --- a/src/main/java/rx/internal/util/SynchronizedQueue.java +++ /dev/null @@ -1,163 +0,0 @@ -/** - * 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.internal.util; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Queue; - -/** - * Intended for use when the `sun.misc.Unsafe` implementations can't be used. - * - * @param - */ -public class SynchronizedQueue implements Queue, Cloneable { - - private final Queue list = new LinkedList(); - private final int size; - - public SynchronizedQueue() { - this.size = -1; - } - - public SynchronizedQueue(int size) { - this.size = size; - } - - @Override - public synchronized boolean isEmpty() { // NOPMD - return list.isEmpty(); - } - - @Override - public synchronized boolean contains(Object o) { // NOPMD - return list.contains(o); - } - - @Override - public synchronized Iterator iterator() { // NOPMD - return list.iterator(); - } - - @Override - public synchronized int size() { // NOPMD - return list.size(); - } - - @Override - public synchronized boolean add(T e) { // NOPMD - return list.add(e); - } - - @Override - public synchronized boolean remove(Object o) { // NOPMD - return list.remove(o); - } - - @Override - public synchronized boolean containsAll(Collection c) { // NOPMD - return list.containsAll(c); - } - - @Override - public synchronized boolean addAll(Collection c) { // NOPMD - return list.addAll(c); - } - - @Override - public synchronized boolean removeAll(Collection c) { // NOPMD - return list.removeAll(c); - } - - @Override - public synchronized boolean retainAll(Collection c) { // NOPMD - return list.retainAll(c); - } - - @Override - public synchronized void clear() { // NOPMD - list.clear(); - } - - @Override - public synchronized String toString() { // NOPMD - return list.toString(); - } - - @Override - public int hashCode() { - return list.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - SynchronizedQueue other = (SynchronizedQueue) obj; - return list.equals(other.list); - } - - @Override - public synchronized T peek() { // NOPMD - return list.peek(); - } - - @Override - public synchronized T element() { // NOPMD - return list.element(); - } - - @Override - public synchronized T poll() { // NOPMD - return list.poll(); - } - - @Override - public synchronized T remove() { // NOPMD - return list.remove(); - } - - @Override - public synchronized boolean offer(T e) { // NOPMD - return !(size > -1 && list.size() + 1 > size) && list.offer(e); - } - - @Override - public synchronized Object clone() { // NOPMD - SynchronizedQueue q = new SynchronizedQueue(size); - q.addAll(list); - return q; - } - - @Override - public synchronized Object[] toArray() { // NOPMD - return list.toArray(); - } - - @Override - public synchronized R[] toArray(R[] a) { // NOPMD - return list.toArray(a); - } - -} diff --git a/src/main/java/rx/internal/util/atomic/AtomicReferenceArrayQueue.java b/src/main/java/rx/internal/util/atomic/AtomicReferenceArrayQueue.java index 8a167f0c72..24691ca832 100644 --- a/src/main/java/rx/internal/util/atomic/AtomicReferenceArrayQueue.java +++ b/src/main/java/rx/internal/util/atomic/AtomicReferenceArrayQueue.java @@ -36,7 +36,7 @@ public Iterator iterator() { @Override public void clear() { // we have to test isEmpty because of the weaker poll() guarantee - while (poll() != null || !isEmpty()) ; // NOPMD + while (poll() != null || !isEmpty()) { } // NOPMD } protected final int calcElementOffset(long index, int mask) { return (int)index & mask; diff --git a/src/main/java/rx/internal/util/atomic/BaseLinkedAtomicQueue.java b/src/main/java/rx/internal/util/atomic/BaseLinkedAtomicQueue.java index 81c12fc645..64e5bd9c49 100644 --- a/src/main/java/rx/internal/util/atomic/BaseLinkedAtomicQueue.java +++ b/src/main/java/rx/internal/util/atomic/BaseLinkedAtomicQueue.java @@ -70,7 +70,7 @@ public final int size() { // must chase the nodes all the way to the producer node, but there's no need to chase a moving target. while (chaserNode != producerNode && size < Integer.MAX_VALUE) { LinkedQueueNode next; - while((next = chaserNode.lvNext()) == null); // NOPMD + while ((next = chaserNode.lvNext()) == null) { } // NOPMD chaserNode = next; size++; } diff --git a/src/main/java/rx/internal/util/atomic/MpscLinkedAtomicQueue.java b/src/main/java/rx/internal/util/atomic/MpscLinkedAtomicQueue.java index 6831cbe923..54c4bbd1aa 100644 --- a/src/main/java/rx/internal/util/atomic/MpscLinkedAtomicQueue.java +++ b/src/main/java/rx/internal/util/atomic/MpscLinkedAtomicQueue.java @@ -94,7 +94,7 @@ public E poll() { } else if (currConsumerNode != lvProducerNode()) { // spin, we are no longer wait free - while((nextNode = currConsumerNode.lvNext()) == null); // NOPMD + while ((nextNode = currConsumerNode.lvNext()) == null) { } // NOPMD // got the next node... // we have to null out the value because we are going to hang on to the node @@ -114,7 +114,7 @@ public E peek() { } else if (currConsumerNode != lvProducerNode()) { // spin, we are no longer wait free - while((nextNode = currConsumerNode.lvNext()) == null); // NOPMD + while ((nextNode = currConsumerNode.lvNext()) == null) { } // NOPMD // got the next node... return nextNode.lpValue(); } diff --git a/src/main/java/rx/internal/util/atomic/SpscAtomicArrayQueue.java b/src/main/java/rx/internal/util/atomic/SpscAtomicArrayQueue.java index 3cd0b0e81f..5bf922346c 100644 --- a/src/main/java/rx/internal/util/atomic/SpscAtomicArrayQueue.java +++ b/src/main/java/rx/internal/util/atomic/SpscAtomicArrayQueue.java @@ -57,10 +57,10 @@ public boolean offer(E e) { final int offset = calcElementOffset(index, mask); if (index >= producerLookAhead) { int step = lookAheadStep; - if (null == lvElement(buffer, calcElementOffset(index + step, mask))) {// LoadLoad + if (null == lvElement(buffer, calcElementOffset(index + step, mask))) { // LoadLoad producerLookAhead = index + step; } - else if (null != lvElement(buffer, offset)){ + else if (null != lvElement(buffer, offset)) { return false; } } diff --git a/src/main/java/rx/internal/util/atomic/SpscExactAtomicArrayQueue.java b/src/main/java/rx/internal/util/atomic/SpscExactAtomicArrayQueue.java index 9e9affe472..b3f71e264c 100644 --- a/src/main/java/rx/internal/util/atomic/SpscExactAtomicArrayQueue.java +++ b/src/main/java/rx/internal/util/atomic/SpscExactAtomicArrayQueue.java @@ -82,7 +82,7 @@ public T peek() { } @Override public void clear() { - while (poll() != null || !isEmpty()); // NOPMD + while (poll() != null || !isEmpty()) { } // NOPMD } @Override public boolean isEmpty() { diff --git a/src/main/java/rx/internal/util/atomic/SpscLinkedArrayQueue.java b/src/main/java/rx/internal/util/atomic/SpscLinkedArrayQueue.java index c2b4f43eac..a796e1c373 100644 --- a/src/main/java/rx/internal/util/atomic/SpscLinkedArrayQueue.java +++ b/src/main/java/rx/internal/util/atomic/SpscLinkedArrayQueue.java @@ -78,7 +78,7 @@ public boolean offer(final T e) { final int lookAheadStep = producerLookAheadStep; // go around the buffer or resize if full (unless we hit max capacity) int lookAheadElementOffset = calcWrappedOffset(index + lookAheadStep, mask); - if (null == lvElement(buffer, lookAheadElementOffset)) {// LoadLoad + if (null == lvElement(buffer, lookAheadElementOffset)) { // LoadLoad producerLookAhead = index + lookAheadStep - 1; // joy, there's plenty of room return writeToQueue(buffer, e, index, offset); } else if (null == lvElement(buffer, calcWrappedOffset(index + 1, mask))) { // buffer is not full @@ -178,7 +178,7 @@ public T peek() { @Override public void clear() { - while (poll() != null || !isEmpty()); // NOPMD + while (poll() != null || !isEmpty()) { } // NOPMD } @SuppressWarnings("unchecked") diff --git a/src/main/java/rx/internal/util/atomic/SpscUnboundedAtomicArrayQueue.java b/src/main/java/rx/internal/util/atomic/SpscUnboundedAtomicArrayQueue.java index 9468173869..87bf5afc9a 100644 --- a/src/main/java/rx/internal/util/atomic/SpscUnboundedAtomicArrayQueue.java +++ b/src/main/java/rx/internal/util/atomic/SpscUnboundedAtomicArrayQueue.java @@ -78,7 +78,7 @@ public boolean offer(final T e) { final int lookAheadStep = producerLookAheadStep; // go around the buffer or resize if full (unless we hit max capacity) int lookAheadElementOffset = calcWrappedOffset(index + lookAheadStep, mask); - if (null == lvElement(buffer, lookAheadElementOffset)) {// LoadLoad + if (null == lvElement(buffer, lookAheadElementOffset)) { // LoadLoad producerLookAhead = index + lookAheadStep - 1; // joy, there's plenty of room return writeToQueue(buffer, e, index, offset); } else if (null != lvElement(buffer, calcWrappedOffset(index + 1, mask))) { // buffer is not full @@ -178,7 +178,7 @@ public T peek() { @Override public void clear() { - while (poll() != null || !isEmpty()); // NOPMD + while (poll() != null || !isEmpty()) { } // NOPMD } @SuppressWarnings("unchecked") diff --git a/src/main/java/rx/internal/util/unsafe/BaseLinkedQueue.java b/src/main/java/rx/internal/util/unsafe/BaseLinkedQueue.java index f2d80eb6c5..cdc5ed93d3 100644 --- a/src/main/java/rx/internal/util/unsafe/BaseLinkedQueue.java +++ b/src/main/java/rx/internal/util/unsafe/BaseLinkedQueue.java @@ -106,7 +106,7 @@ public final int size() { // must chase the nodes all the way to the producer node, but there's no need to chase a moving target. while (chaserNode != producerNode && size < Integer.MAX_VALUE) { LinkedQueueNode next; - while((next = chaserNode.lvNext()) == null); // NOPMD + while ((next = chaserNode.lvNext()) == null) { } // NOPMD chaserNode = next; size++; } diff --git a/src/main/java/rx/internal/util/unsafe/ConcurrentCircularArrayQueue.java b/src/main/java/rx/internal/util/unsafe/ConcurrentCircularArrayQueue.java index 7a11f99d85..08456f0b0e 100644 --- a/src/main/java/rx/internal/util/unsafe/ConcurrentCircularArrayQueue.java +++ b/src/main/java/rx/internal/util/unsafe/ConcurrentCircularArrayQueue.java @@ -182,6 +182,6 @@ public Iterator iterator() { @Override public void clear() { // we have to test isEmpty because of the weaker poll() guarantee - while (poll() != null || !isEmpty()) ; // NOPMD + while (poll() != null || !isEmpty()) { } // NOPMD } } diff --git a/src/main/java/rx/internal/util/unsafe/MpscLinkedQueue.java b/src/main/java/rx/internal/util/unsafe/MpscLinkedQueue.java index e6b4c350e9..b69a5a0daa 100644 --- a/src/main/java/rx/internal/util/unsafe/MpscLinkedQueue.java +++ b/src/main/java/rx/internal/util/unsafe/MpscLinkedQueue.java @@ -49,7 +49,7 @@ protected LinkedQueueNode xchgProducerNode(LinkedQueueNode newVal) { Object oldVal; do { oldVal = producerNode; - } while(!UNSAFE.compareAndSwapObject(this, P_NODE_OFFSET, oldVal, newVal)); + } while (!UNSAFE.compareAndSwapObject(this, P_NODE_OFFSET, oldVal, newVal)); return (LinkedQueueNode) oldVal; } @@ -110,7 +110,7 @@ public E poll() { } else if (currConsumerNode != lvProducerNode()) { // spin, we are no longer wait free - while((nextNode = currConsumerNode.lvNext()) == null); // NOPMD + while ((nextNode = currConsumerNode.lvNext()) == null) { } // NOPMD // got the next node... // we have to null out the value because we are going to hang on to the node @@ -130,7 +130,7 @@ public E peek() { } else if (currConsumerNode != lvProducerNode()) { // spin, we are no longer wait free - while((nextNode = currConsumerNode.lvNext()) == null); // NOPMD + while ((nextNode = currConsumerNode.lvNext()) == null) { } // NOPMD // got the next node... return nextNode.lpValue(); } diff --git a/src/main/java/rx/internal/util/unsafe/README.md b/src/main/java/rx/internal/util/unsafe/README.md index 1bff119cd7..c847ea77e5 100644 --- a/src/main/java/rx/internal/util/unsafe/README.md +++ b/src/main/java/rx/internal/util/unsafe/README.md @@ -2,7 +2,7 @@ This package contains code that relies on sun.misc.Unsafe. Before using it you M Much of the code in this package comes from or is inspired by the JCTools project: https://github.com/JCTools/JCTools -JCTools has now published artifacts (https://github.com/JCTools/JCTools/issues/17) so RxJava could add JCTools as a "shadow" dependency (https://github.com/ReactiveX/RxJava/issues/1735). +JCTools has now published artifacts (https://github.com/JCTools/JCTools/issues/17) so RxJava could add JCTools as a "shadow" dependency (https://github.com/ReactiveX/RxJava/issues/1735). RxJava has a "zero dependency" policy for the core library, so if we do add it as a dependency, it won't be an externally visible dependency that results in a separate jar. The license for the JCTools code is https://github.com/JCTools/JCTools/blob/master/LICENSE diff --git a/src/main/java/rx/internal/util/unsafe/SpmcArrayQueue.java b/src/main/java/rx/internal/util/unsafe/SpmcArrayQueue.java index 325bfd6eae..043511cac8 100644 --- a/src/main/java/rx/internal/util/unsafe/SpmcArrayQueue.java +++ b/src/main/java/rx/internal/util/unsafe/SpmcArrayQueue.java @@ -130,12 +130,12 @@ public boolean offer(final E e) { if (null != lvElement(lb, offset)) { long size = currProducerIndex - lvConsumerIndex(); - if(size > lMask) { + if (size > lMask) { return false; } else { // spin wait for slot to clear, buggers wait freedom - while(null != lvElement(lb, offset)); // NOPMD + while (null != lvElement(lb, offset)) { } // NOPMD } } spElement(lb, offset, e); diff --git a/src/main/java/rx/internal/util/unsafe/SpscArrayQueue.java b/src/main/java/rx/internal/util/unsafe/SpscArrayQueue.java index 15c9a9d06f..f5bab6f124 100644 --- a/src/main/java/rx/internal/util/unsafe/SpscArrayQueue.java +++ b/src/main/java/rx/internal/util/unsafe/SpscArrayQueue.java @@ -25,7 +25,7 @@ abstract class SpscArrayQueueColdField extends ConcurrentCircularArrayQueue extends SpscArrayQueueColdField { @@ -112,7 +112,7 @@ public boolean offer(final E e) { final E[] lElementBuffer = buffer; final long index = producerIndex; final long offset = calcElementOffset(index); - if (null != lvElement(lElementBuffer, offset)){ + if (null != lvElement(lElementBuffer, offset)) { return false; } soElement(lElementBuffer, offset, e); // StoreStore diff --git a/src/main/java/rx/internal/util/unsafe/SpscUnboundedArrayQueue.java b/src/main/java/rx/internal/util/unsafe/SpscUnboundedArrayQueue.java index eab0fec910..aa7baed670 100644 --- a/src/main/java/rx/internal/util/unsafe/SpscUnboundedArrayQueue.java +++ b/src/main/java/rx/internal/util/unsafe/SpscUnboundedArrayQueue.java @@ -50,7 +50,7 @@ abstract class SpscUnboundedArrayQueueConsumerField extends SpscUnboundedArra @SuppressAnimalSniffer public class SpscUnboundedArrayQueue extends SpscUnboundedArrayQueueConsumerField - implements QueueProgressIndicators{ + implements QueueProgressIndicators { static final int MAX_LOOK_AHEAD_STEP = Integer.getInteger("jctools.spsc.max.lookahead.step", 4096); private final static long P_INDEX_OFFSET; private final static long C_INDEX_OFFSET; @@ -126,7 +126,7 @@ public final boolean offer(final E e) { final int lookAheadStep = producerLookAheadStep; // go around the buffer or resize if full (unless we hit max capacity) long lookAheadElementOffset = calcWrappedOffset(index + lookAheadStep, mask); - if (null == lvElement(buffer, lookAheadElementOffset)) {// LoadLoad + if (null == lvElement(buffer, lookAheadElementOffset)) { // LoadLoad producerLookAhead = index + lookAheadStep - 1; // joy, there's plenty of room return writeToQueue(buffer, e, index, offset); } else if (null != lvElement(buffer, calcWrappedOffset(index + 1, mask))) { // buffer is not full @@ -159,11 +159,11 @@ private void resize(final E[] oldBuffer, final long currIndex, final long offset } private void soNext(E[] curr, E[] next) { - soElement(curr, calcDirectOffset(curr.length -1), next); + soElement(curr, calcDirectOffset(curr.length - 1), next); } @SuppressWarnings("unchecked") private E[] lvNext(E[] curr) { - return (E[]) lvElement(curr, calcDirectOffset(curr.length -1)); + return (E[]) lvElement(curr, calcDirectOffset(curr.length - 1)); } /** * {@inheritDoc} diff --git a/src/main/java/rx/observables/SyncOnSubscribe.java b/src/main/java/rx/observables/SyncOnSubscribe.java index 6e4b887da4..dc9e2a7a3c 100644 --- a/src/main/java/rx/observables/SyncOnSubscribe.java +++ b/src/main/java/rx/observables/SyncOnSubscribe.java @@ -261,7 +261,7 @@ public Void call(Void state, Observer subscriber) { return null; } }; - Action1 wrappedOnUnsubscribe = new Action1(){ + Action1 wrappedOnUnsubscribe = new Action1() { @Override public void call(Void t) { onUnsubscribe.call(); @@ -350,7 +350,7 @@ public boolean isUnsubscribed() { @Override public void unsubscribe() { - while(true) { + while (true) { long requestCount = get(); if (compareAndSet(0L, -1L)) { doUnsubscribe(); diff --git a/src/main/java/rx/schedulers/Schedulers.java b/src/main/java/rx/schedulers/Schedulers.java index 502a59bcf7..e6435965e5 100644 --- a/src/main/java/rx/schedulers/Schedulers.java +++ b/src/main/java/rx/schedulers/Schedulers.java @@ -15,19 +15,39 @@ */ package rx.schedulers; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; + import rx.Scheduler; import rx.annotations.Experimental; -import rx.internal.schedulers.ExecutorScheduler; -import rx.internal.schedulers.GenericScheduledExecutorService; -import rx.internal.schedulers.SchedulerLifecycle; -import rx.internal.util.RxRingBuffer; +import rx.internal.schedulers.*; import rx.plugins.*; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicReference; - /** * Static factory methods for creating Schedulers. + *

+ * System configuration properties: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Property nameDescriptionDefault
{@code rx.io-scheduler.keepalive}time (in seconds) to keep an unused backing + * thread-pool60
{@code rx.scheduler.max-computation-threads}number of threads the + * computation scheduler uses (between 1 and number of available processors) + * number of available processors.
{@code rx.scheduler.jdk6.purge-frequency-millis}time (in milliseconds) between calling + * purge on any active backing thread-pool on a Java 6 runtime1000
{@code rx.scheduler.jdk6.purge-force} boolean forcing the call to purge on any active + * backing thread-poolfalse
*/ public final class Schedulers { @@ -185,10 +205,6 @@ public static void start() { synchronized (s) { GenericScheduledExecutorService.INSTANCE.start(); - - RxRingBuffer.SPSC_POOL.start(); - - RxRingBuffer.SPMC_POOL.start(); } } /** @@ -201,10 +217,6 @@ public static void shutdown() { synchronized (s) { GenericScheduledExecutorService.INSTANCE.shutdown(); - - RxRingBuffer.SPSC_POOL.shutdown(); - - RxRingBuffer.SPMC_POOL.shutdown(); } } diff --git a/src/perf/java/rx/ScalarJustPerf.java b/src/perf/java/rx/ScalarJustPerf.java index 548d1764fd..c50f945672 100644 --- a/src/perf/java/rx/ScalarJustPerf.java +++ b/src/perf/java/rx/ScalarJustPerf.java @@ -126,7 +126,7 @@ void runAsync(Blackhole bh, Observable source) { source.subscribe(lo); - while (lo.latch.getCount() != 0L); + while (lo.latch.getCount() != 0L) { } } @Benchmark diff --git a/src/perf/java/rx/SingleSourcePerf.java b/src/perf/java/rx/SingleSourcePerf.java index c735e4e2b0..743d8669fb 100644 --- a/src/perf/java/rx/SingleSourcePerf.java +++ b/src/perf/java/rx/SingleSourcePerf.java @@ -169,7 +169,7 @@ public void await() { } public void awaitSpin() { - while (cdl.getCount() != 0L) ; + while (cdl.getCount() != 0L) { } } } diff --git a/src/perf/java/rx/jmh/InputWithIncrementingInteger.java b/src/perf/java/rx/jmh/InputWithIncrementingInteger.java index ad0c350c2d..9700db74c1 100644 --- a/src/perf/java/rx/jmh/InputWithIncrementingInteger.java +++ b/src/perf/java/rx/jmh/InputWithIncrementingInteger.java @@ -59,7 +59,7 @@ public void call(Subscriber s) { @Override public Iterator iterator() { return new Iterator() { - int i = 0; + int i; @Override public boolean hasNext() { diff --git a/src/perf/java/rx/jmh/PerfAsyncSingleSubscriber.java b/src/perf/java/rx/jmh/PerfAsyncSingleSubscriber.java index 01d7600d6f..0a579c3087 100644 --- a/src/perf/java/rx/jmh/PerfAsyncSingleSubscriber.java +++ b/src/perf/java/rx/jmh/PerfAsyncSingleSubscriber.java @@ -64,6 +64,6 @@ public void sleepAwait() { * Spins until the subscriber receives an events. */ public void spinAwait() { - while (cdl.getCount() != 0) ; + while (cdl.getCount() != 0) { } } } diff --git a/src/perf/java/rx/observables/SyncOnSubscribePerf.java b/src/perf/java/rx/observables/SyncOnSubscribePerf.java index 54377e433b..23c36e3d6b 100644 --- a/src/perf/java/rx/observables/SyncOnSubscribePerf.java +++ b/src/perf/java/rx/observables/SyncOnSubscribePerf.java @@ -49,7 +49,7 @@ private static Blackhole _jmh_tryInit_() { } private static OnSubscribe createSyncOnSubscribe(final Iterator iterator) { - return new SyncOnSubscribe(){ + return new SyncOnSubscribe() { @Override protected Void generateState() { @@ -60,12 +60,12 @@ protected Void generateState() { protected Void next(Void state, Observer observer) { if (iterator.hasNext()) { observer.onNext(iterator.next()); - } - else + } else { observer.onCompleted(); - return null; } - }; + return null; + } + }; } // @Benchmark diff --git a/src/perf/java/rx/operators/ZipPerf.java b/src/perf/java/rx/operators/ZipPerf.java index 36608aea53..1591c8e8d6 100644 --- a/src/perf/java/rx/operators/ZipPerf.java +++ b/src/perf/java/rx/operators/ZipPerf.java @@ -67,7 +67,7 @@ public void setup() { Integer[] array2 = new Integer[secondLen]; Arrays.fill(array2, 777); - baseline = Observable.from(firstLen < secondLen? array2 : array1); + baseline = Observable.from(firstLen < secondLen ? array2 : array1); Observable o1 = Observable.from(array1); @@ -107,7 +107,7 @@ public void syncAsync(Blackhole bh) throws Exception { firstSync.subscribe(o); if (small) { - while (o.latch.getCount() != 0); + while (o.latch.getCount() != 0) { } } else { o.latch.await(); } @@ -119,7 +119,7 @@ public void asyncSync(Blackhole bh) throws Exception { secondSync.subscribe(o); if (small) { - while (o.latch.getCount() != 0); + while (o.latch.getCount() != 0) { } } else { o.latch.await(); } @@ -131,7 +131,7 @@ public void asyncAsync(Blackhole bh) throws Exception { bothAsync.subscribe(o); if (small) { - while (o.latch.getCount() != 0); + while (o.latch.getCount() != 0) { } } else { o.latch.await(); } diff --git a/src/test/java/rx/BackpressureTests.java b/src/test/java/rx/BackpressureTests.java index 9556aff5e6..f9931f8754 100644 --- a/src/test/java/rx/BackpressureTests.java +++ b/src/test/java/rx/BackpressureTests.java @@ -600,7 +600,7 @@ private static Observable incrementingIntegers(final AtomicInteger coun @Override public void call(final Subscriber s) { s.setProducer(new Producer() { - int i = 0; + int i; @Override public void request(long n) { @@ -639,7 +639,7 @@ public void request(long n) { private static Observable firehose(final AtomicInteger counter) { return Observable.create(new OnSubscribe() { - int i = 0; + int i; @Override public void call(final Subscriber s) { diff --git a/src/test/java/rx/CapturingUncaughtExceptionHandler.java b/src/test/java/rx/CapturingUncaughtExceptionHandler.java index a44c6df080..27709943b8 100644 --- a/src/test/java/rx/CapturingUncaughtExceptionHandler.java +++ b/src/test/java/rx/CapturingUncaughtExceptionHandler.java @@ -19,7 +19,7 @@ import java.util.concurrent.CountDownLatch; public final class CapturingUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { - public int count = 0; + public int count; public Throwable caught; public CountDownLatch completed = new CountDownLatch(1); diff --git a/src/test/java/rx/CompletableTest.java b/src/test/java/rx/CompletableTest.java index 98ee57b5b2..97a40439c8 100644 --- a/src/test/java/rx/CompletableTest.java +++ b/src/test/java/rx/CompletableTest.java @@ -2606,7 +2606,7 @@ public void call(Throwable e) { public void subscribeTwoCallbacksFirstNull() { normal.completable.subscribe(null, new Action1() { @Override - public void call(Throwable throwable) {} + public void call(Throwable throwable) { } }); } @@ -2894,9 +2894,9 @@ public Observable call(Completable c) { } }); - flow.toBlocking().forEach(new Action1(){ + flow.toBlocking().forEach(new Action1() { @Override - public void call(Object e){ } + public void call(Object e) { } }); } @@ -3887,8 +3887,12 @@ private static void expectUncaughtTestException(Action0 action) { assertEquals("Should have received exactly 1 exception", 1, handler.count); Throwable caught = handler.caught; while (caught != null) { - if (caught instanceof TestException) break; - if (caught == caught.getCause()) break; + if (caught instanceof TestException) { + break; + } + if (caught == caught.getCause()) { + break; + } caught = caught.getCause(); } assertTrue("A TestException should have been delivered to the handler", diff --git a/src/test/java/rx/NotificationTest.java b/src/test/java/rx/NotificationTest.java index df79092ff4..c25e28d136 100644 --- a/src/test/java/rx/NotificationTest.java +++ b/src/test/java/rx/NotificationTest.java @@ -29,49 +29,49 @@ public class NotificationTest { @Test - public void testOnNextIntegerNotificationDoesNotEqualNullNotification(){ + public void testOnNextIntegerNotificationDoesNotEqualNullNotification() { final Notification integerNotification = Notification.createOnNext(1); final Notification nullNotification = Notification.createOnNext(null); assertFalse(integerNotification.equals(nullNotification)); } @Test - public void testOnNextNullNotificationDoesNotEqualIntegerNotification(){ + public void testOnNextNullNotificationDoesNotEqualIntegerNotification() { final Notification integerNotification = Notification.createOnNext(1); final Notification nullNotification = Notification.createOnNext(null); assertFalse(nullNotification.equals(integerNotification)); } @Test - public void testOnNextIntegerNotificationsWhenEqual(){ + public void testOnNextIntegerNotificationsWhenEqual() { final Notification integerNotification = Notification.createOnNext(1); final Notification integerNotification2 = Notification.createOnNext(1); assertTrue(integerNotification.equals(integerNotification2)); } @Test - public void testOnNextIntegerNotificationsWhenNotEqual(){ + public void testOnNextIntegerNotificationsWhenNotEqual() { final Notification integerNotification = Notification.createOnNext(1); final Notification integerNotification2 = Notification.createOnNext(2); assertFalse(integerNotification.equals(integerNotification2)); } @Test - public void testOnErrorIntegerNotificationDoesNotEqualNullNotification(){ + public void testOnErrorIntegerNotificationDoesNotEqualNullNotification() { final Notification integerNotification = Notification.createOnError(new Exception()); final Notification nullNotification = Notification.createOnError(null); assertFalse(integerNotification.equals(nullNotification)); } @Test - public void testOnErrorNullNotificationDoesNotEqualIntegerNotification(){ + public void testOnErrorNullNotificationDoesNotEqualIntegerNotification() { final Notification integerNotification = Notification.createOnError(new Exception()); final Notification nullNotification = Notification.createOnError(null); assertFalse(nullNotification.equals(integerNotification)); } @Test - public void testOnErrorIntegerNotificationsWhenEqual(){ + public void testOnErrorIntegerNotificationsWhenEqual() { final Exception exception = new Exception(); final Notification onErrorNotification = Notification.createOnError(exception); final Notification onErrorNotification2 = Notification.createOnError(exception); @@ -79,7 +79,7 @@ public void testOnErrorIntegerNotificationsWhenEqual(){ } @Test - public void testOnErrorIntegerNotificationWhenNotEqual(){ + public void testOnErrorIntegerNotificationWhenNotEqual() { final Notification onErrorNotification = Notification.createOnError(new Exception()); final Notification onErrorNotification2 = Notification.createOnError(new Exception()); assertFalse(onErrorNotification.equals(onErrorNotification2)); @@ -256,5 +256,10 @@ public boolean equals(Object o) { } return false; } + + @Override + public int hashCode() { + return getMessage().hashCode(); + } } } diff --git a/src/test/java/rx/ObservableTests.java b/src/test/java/rx/ObservableTests.java index 433d56331b..bed04b4cdc 100644 --- a/src/test/java/rx/ObservableTests.java +++ b/src/test/java/rx/ObservableTests.java @@ -1089,7 +1089,7 @@ public void testSubscribingSubscriberAsObserverMaintainsSubscriptionChain() { subscriber.assertUnsubscribed(); } - @Test(expected=OnErrorNotImplementedException.class) + @Test(expected = OnErrorNotImplementedException.class) public void testForEachWithError() { Observable.error(new Exception("boo")) // @@ -1100,7 +1100,7 @@ public void call(Object t) { }}); } - @Test(expected=IllegalArgumentException.class) + @Test(expected = IllegalArgumentException.class) public void testForEachWithNull() { Observable.error(new Exception("boo")) // diff --git a/src/test/java/rx/SingleTest.java b/src/test/java/rx/SingleTest.java index 41b75e73f7..eefcde2699 100644 --- a/src/test/java/rx/SingleTest.java +++ b/src/test/java/rx/SingleTest.java @@ -2055,7 +2055,7 @@ public Single call(Integer v) { }) .subscribe(); - while (!ps.hasObservers() && !Thread.currentThread().isInterrupted()) ; + while (!ps.hasObservers() && !Thread.currentThread().isInterrupted()) { } s.unsubscribe(); diff --git a/src/test/java/rx/SubscriberTest.java b/src/test/java/rx/SubscriberTest.java index 82abd5fee6..5180966a1a 100644 --- a/src/test/java/rx/SubscriberTest.java +++ b/src/test/java/rx/SubscriberTest.java @@ -489,7 +489,7 @@ public void testOnStartRequestsAreAdditiveAndOverflowBecomesMaxValue() { @Override public void onStart() { request(2); - request(Long.MAX_VALUE-1); + request(Long.MAX_VALUE - 1); } @Override diff --git a/src/test/java/rx/TestUtil.java b/src/test/java/rx/TestUtil.java index 7beb6d0f4a..15414b510e 100644 --- a/src/test/java/rx/TestUtil.java +++ b/src/test/java/rx/TestUtil.java @@ -67,7 +67,7 @@ public static void race(Action0 r1, final Action0 r2) { @Override public void call() { if (counter.decrementAndGet() != 0) { - while (counter.get() != 0); + while (counter.get() != 0) { } } try { @@ -81,7 +81,7 @@ public void call() { }); if (counter.decrementAndGet() != 0) { - while (counter.get() != 0); + while (counter.get() != 0) { } } try { diff --git a/src/test/java/rx/exceptions/CompositeExceptionTest.java b/src/test/java/rx/exceptions/CompositeExceptionTest.java index 5451a8cf10..e7f33251c5 100644 --- a/src/test/java/rx/exceptions/CompositeExceptionTest.java +++ b/src/test/java/rx/exceptions/CompositeExceptionTest.java @@ -15,18 +15,12 @@ */ package rx.exceptions; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.io.*; +import java.util.*; -import org.junit.Test; +import org.junit.*; import rx.exceptions.CompositeException.CompositeExceptionCausalChain; @@ -159,7 +153,7 @@ private static Throwable getRootCause(Throwable ex) { if (root == null) { return null; } else { - while(true) { + while (true) { if (root.getCause() == null) { return root; } else { @@ -257,7 +251,7 @@ public void complexCauses() { e5.initCause(e6); CompositeException compositeException = new CompositeException(e1, e3, e5); - assert(compositeException.getCause() instanceof CompositeExceptionCausalChain); + Assert.assertTrue(compositeException.getCause() instanceof CompositeExceptionCausalChain); List causeChain = new ArrayList(); Throwable cause = compositeException.getCause().getCause(); diff --git a/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java b/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java index 5a85995d7b..97d8cdb250 100644 --- a/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java +++ b/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java @@ -58,7 +58,7 @@ public void testExceptionWithMoreThanOneElement() throws Throwable { // we expect an exception since there are more than 1 element f.get(); } - catch(ExecutionException e) { + catch (ExecutionException e) { throw e.getCause(); } } @@ -83,7 +83,7 @@ public void call(Subscriber observer) { } } - @Test(expected=CancellationException.class) + @Test(expected = CancellationException.class) public void testGetAfterCancel() throws Exception { Observable obs = Observable.create(new OperationNeverComplete()); Future f = toFuture(obs); @@ -92,7 +92,7 @@ public void testGetAfterCancel() throws Exception { f.get(); // Future.get() docs require this to throw } - @Test(expected=CancellationException.class) + @Test(expected = CancellationException.class) public void testGetWithTimeoutAfterCancel() throws Exception { Observable obs = Observable.create(new OperationNeverComplete()); Future f = toFuture(obs); @@ -118,7 +118,7 @@ public void testGetWithEmptyObservable() throws Throwable { try { f.get(); } - catch(ExecutionException e) { + catch (ExecutionException e) { throw e.getCause(); } } diff --git a/src/test/java/rx/internal/operators/DeferredScalarSubscriberTest.java b/src/test/java/rx/internal/operators/DeferredScalarSubscriberTest.java index 6d09cfb950..c3ad148e75 100644 --- a/src/test/java/rx/internal/operators/DeferredScalarSubscriberTest.java +++ b/src/test/java/rx/internal/operators/DeferredScalarSubscriberTest.java @@ -317,14 +317,14 @@ public void emissionRequestRace() { @Override public void call() { ready.decrementAndGet(); - while (ready.get() != 0) ; + while (ready.get() != 0) { } ts.requestMore(1); } }); ready.decrementAndGet(); - while (ready.get() != 0) ; + while (ready.get() != 0) { } ds.onCompleted(); @@ -361,7 +361,7 @@ public void emissionRequestRace2() { @Override public void call() { ready.decrementAndGet(); - while (ready.get() != 0) ; + while (ready.get() != 0) { } ts.requestMore(1); } @@ -371,14 +371,14 @@ public void call() { @Override public void call() { ready.decrementAndGet(); - while (ready.get() != 0) ; + while (ready.get() != 0) { } ts.requestMore(1); } }); ready.decrementAndGet(); - while (ready.get() != 0) ; + while (ready.get() != 0) { } ds.onCompleted(); diff --git a/src/test/java/rx/internal/operators/OnSubscribeCombineLatestTest.java b/src/test/java/rx/internal/operators/OnSubscribeCombineLatestTest.java index 1fb0518112..b5ebd07e5e 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeCombineLatestTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeCombineLatestTest.java @@ -831,7 +831,7 @@ public Long call(Long t1, Integer t2) { assertEquals(SIZE, count.get()); } - @Test(timeout=10000) + @Test(timeout = 10000) public void testCombineLatestRequestOverflow() throws InterruptedException { @SuppressWarnings("unchecked") List> sources = Arrays.asList(Observable.from(Arrays.asList(1,2,3,4)), Observable.from(Arrays.asList(5,6,7,8))); @@ -862,7 +862,7 @@ public void onError(Throwable e) { @Override public void onNext(Integer t) { latch.countDown(); - request(Long.MAX_VALUE-1); + request(Long.MAX_VALUE - 1); }}); assertTrue(latch.await(10, TimeUnit.SECONDS)); } diff --git a/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java b/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java index 397b6496be..8cf5bdd2cc 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java @@ -124,7 +124,7 @@ public void testIssue1451Case1() { // https://github.com/Netflix/RxJava/issues/1451 final int expectedCount = 3; final AtomicInteger count = new AtomicInteger(); - for (int i=0; i < expectedCount; i++) { + for (int i = 0; i < expectedCount; i++) { Observable .just(Boolean.TRUE, Boolean.FALSE) .takeWhile(new Func1() { @@ -150,7 +150,7 @@ public void testIssue1451Case2() { // https://github.com/Netflix/RxJava/issues/1451 final int expectedCount = 3; final AtomicInteger count = new AtomicInteger(); - for (int i=0; i < expectedCount; i++) { + for (int i = 0; i < expectedCount; i++) { Observable .just(Boolean.TRUE, Boolean.FALSE, Boolean.FALSE) .takeWhile(new Func1() { @@ -288,7 +288,7 @@ public void call(Integer t) { @Test public void testIfOnNextActionFailsEmitsErrorAndReportsMoreErrorsToRxJavaHooksNotDownstream() { try { - final List list= new CopyOnWriteArrayList(); + final List list = new CopyOnWriteArrayList(); RxJavaHooks.setOnError(new Action1() { @Override diff --git a/src/test/java/rx/internal/operators/OnSubscribeFromEmitterTest.java b/src/test/java/rx/internal/operators/OnSubscribeFromEmitterTest.java index b7579b5b6f..8298625a9b 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeFromEmitterTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeFromEmitterTest.java @@ -145,7 +145,7 @@ public void normalError() { @Test public void overflowErrorIsNotFollowedByAnotherErrorDueToOnNextFromUpstream() { - Action1> source = new Action1>(){ + Action1> source = new Action1>() { @Override public void call(Emitter emitter) { @@ -164,7 +164,7 @@ public void call(Emitter emitter) { @Test public void overflowErrorIsNotFollowedByAnotherCompletedDueToCompletedFromUpstream() { - Action1> source = new Action1>(){ + Action1> source = new Action1>() { @Override public void call(Emitter emitter) { @@ -191,7 +191,7 @@ public void call(Throwable t) { list.add(t); }}); final RuntimeException e = new RuntimeException(); - Action1> source = new Action1>(){ + Action1> source = new Action1>() { @Override public void call(Emitter emitter) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java b/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java index 4feca72cdd..43993ca137 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java @@ -66,7 +66,7 @@ public void testRawIterable() { public Iterator iterator() { return new Iterator() { - int i = 0; + int i; @Override public boolean hasNext() { @@ -184,7 +184,7 @@ public void onError(Throwable e) { @Override public void onNext(Integer t) { latch.countDown(); - request(Long.MAX_VALUE-1); + request(Long.MAX_VALUE - 1); }}); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @@ -237,8 +237,9 @@ public boolean hasNext() { if (count > 1) { called.set(true); return false; - } else + } else { return true; + } } @Override @@ -274,8 +275,9 @@ public boolean hasNext() { if (count > 1) { called.set(true); return false; - } else + } else { return true; + } } @Override diff --git a/src/test/java/rx/internal/operators/OnSubscribeMapTest.java b/src/test/java/rx/internal/operators/OnSubscribeMapTest.java index 4cc589a7cc..6477bdbdc5 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeMapTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeMapTest.java @@ -278,7 +278,7 @@ public Observable call(Object object) { }; Func1 mapper = new Func1() { - private int count = 0; + private int count; @Override public Object call(Object object) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java b/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java index 68b860d97f..e169cbb68e 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java @@ -280,7 +280,7 @@ public void testUsingDisposesEagerlyBeforeCompletion() { final List events = new ArrayList(); Func0 resourceFactory = createResourceFactory(events); final Action0 completion = createOnCompletedAction(events); - final Action0 unsub =createUnsubAction(events); + final Action0 unsub = createUnsubAction(events); Func1> observableFactory = new Func1>() { @Override @@ -305,7 +305,7 @@ public void testUsingDoesNotDisposesEagerlyBeforeCompletion() { final List events = new ArrayList(); Func0 resourceFactory = createResourceFactory(events); final Action0 completion = createOnCompletedAction(events); - final Action0 unsub =createUnsubAction(events); + final Action0 unsub = createUnsubAction(events); Func1> observableFactory = new Func1>() { @Override diff --git a/src/test/java/rx/internal/operators/OperatorAllTest.java b/src/test/java/rx/internal/operators/OperatorAllTest.java index 264c0abc88..0ca615d515 100644 --- a/src/test/java/rx/internal/operators/OperatorAllTest.java +++ b/src/test/java/rx/internal/operators/OperatorAllTest.java @@ -236,9 +236,9 @@ public void request(long n) { boolean once = true; @Override public Boolean call(Integer t) { - if (once) + if (once) { throw new RuntimeException("boo"); - else { + } else { once = false; return true; } diff --git a/src/test/java/rx/internal/operators/OperatorAnyTest.java b/src/test/java/rx/internal/operators/OperatorAnyTest.java index 7ddbfa6a23..776d6e8f72 100644 --- a/src/test/java/rx/internal/operators/OperatorAnyTest.java +++ b/src/test/java/rx/internal/operators/OperatorAnyTest.java @@ -298,9 +298,9 @@ public void request(long n) { boolean once = true; @Override public Boolean call(Integer t) { - if (once) + if (once) { throw new RuntimeException("boo"); - else { + } else { once = false; return true; } diff --git a/src/test/java/rx/internal/operators/OperatorBufferTest.java b/src/test/java/rx/internal/operators/OperatorBufferTest.java index 2a14f7797e..99f4cf5c0f 100644 --- a/src/test/java/rx/internal/operators/OperatorBufferTest.java +++ b/src/test/java/rx/internal/operators/OperatorBufferTest.java @@ -309,7 +309,7 @@ public void testLongTimeAction() throws InterruptedException { private static class LongTimeAction implements Action1> { CountDownLatch latch; - boolean fail = false; + boolean fail; public LongTimeAction(CountDownLatch latch) { this.latch = latch; diff --git a/src/test/java/rx/internal/operators/OperatorConcatTest.java b/src/test/java/rx/internal/operators/OperatorConcatTest.java index 99f4ae1a25..564eb9e709 100644 --- a/src/test/java/rx/internal/operators/OperatorConcatTest.java +++ b/src/test/java/rx/internal/operators/OperatorConcatTest.java @@ -84,11 +84,11 @@ public void testConcatMapIterable() { final String[] l = { "a", "b", "c", "d", "e" }; Func1,List> identity = new Func1, List>() { - @Override - public List call(List t) { - return t; - } - }; + @Override + public List call(List t) { + return t; + } + }; final Observable> listObs = Observable.just(Arrays.asList(l)); final Observable concatMap = listObs.concatMapIterable(identity); @@ -497,8 +497,8 @@ public boolean isUnsubscribed() { }; private final List values; - private Thread t = null; - private int count = 0; + private Thread t; + private int count; private boolean subscribed = true; private final CountDownLatch once; private final CountDownLatch okToContinue; @@ -535,20 +535,24 @@ public void call(final Subscriber observer) { public void run() { try { while (count < size && subscribed) { - if (null != values) + if (null != values) { observer.onNext(values.get(count)); - else + } else { observer.onNext(seed); + } count++; //Unblock the main thread to call unsubscribe. - if (null != once) + if (null != once) { once.countDown(); + } //Block until the main thread has called unsubscribe. - if (null != okToContinue) + if (null != okToContinue) { okToContinue.await(5, TimeUnit.SECONDS); + } } - if (subscribed) + if (subscribed) { observer.onCompleted(); + } } catch (InterruptedException e) { e.printStackTrace(); fail(e.getMessage()); @@ -821,8 +825,9 @@ public void concatMapRangeAsyncLoopIssue2876() { final long startTime = System.currentTimeMillis(); for (int i = 0;; i++) { //only run this for a max of ten seconds - if (System.currentTimeMillis()-startTime > TimeUnit.SECONDS.toMillis(durationSeconds)) + if (System.currentTimeMillis() - startTime > TimeUnit.SECONDS.toMillis(durationSeconds)) { return; + } if (i % 1000 == 0) { System.out.println("concatMapRangeAsyncLoop > " + i); } diff --git a/src/test/java/rx/internal/operators/OperatorDelayTest.java b/src/test/java/rx/internal/operators/OperatorDelayTest.java index d92aac8569..8c2bfbf9f2 100644 --- a/src/test/java/rx/internal/operators/OperatorDelayTest.java +++ b/src/test/java/rx/internal/operators/OperatorDelayTest.java @@ -671,7 +671,7 @@ public void testBackpressureWithTimedDelay() { .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t) { @@ -700,7 +700,7 @@ public void testBackpressureWithSubscriptionTimedDelay() { .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t) { @@ -735,7 +735,7 @@ public Observable call(Integer i) { .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t) { @@ -776,7 +776,7 @@ public Observable call(Integer i) { .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t) { diff --git a/src/test/java/rx/internal/operators/OperatorGroupByTest.java b/src/test/java/rx/internal/operators/OperatorGroupByTest.java index 2b9328795d..2d90e6f29a 100644 --- a/src/test/java/rx/internal/operators/OperatorGroupByTest.java +++ b/src/test/java/rx/internal/operators/OperatorGroupByTest.java @@ -1142,7 +1142,7 @@ public Observable call(final GroupedObservable g) { System.out.println("-----------> NEXT: " + g.getKey()); return g.take(2).map(new Func1() { - int count = 0; + int count; @Override public String call(String v) { @@ -1264,7 +1264,7 @@ public void call() { }).observeOn(Schedulers.computation()).map(new Func1() { - int c = 0; + int c; @Override public String call(Integer l) { @@ -1481,7 +1481,7 @@ public void onError(Throwable e) { public void onNext(Integer t) { System.out.println(t); //provoke possible request overflow - request(Long.MAX_VALUE-1); + request(Long.MAX_VALUE - 1); }}); assertTrue(completed.get()); } @@ -1812,10 +1812,10 @@ public Integer call(Integer pair) { @Test public void mapFactoryEvictionWorks() { - Func1 keySelector = new Func1 (){ + Func1 keySelector = new Func1 () { @Override public Integer call(Integer t) { - return t /10; + return t / 10; }}; Func1 elementSelector = UtilityFunctions.identity(); final List evictedKeys = new ArrayList(); @@ -1831,7 +1831,7 @@ public Map call(final Action1 evicted) { return new ConcurrentHashMap() { private static final long serialVersionUID = -7519109652858021153L; - Integer lastKey = null; + Integer lastKey; @Override public Object put(Integer key, Object value) { @@ -1867,7 +1867,7 @@ public String call(Integer x) { .map(new Func1() { @Override public String call(Integer x) { - return (x /10) + ":" + x; + return (x / 10) + ":" + x; } }) .toList().toBlocking().single(); @@ -1876,10 +1876,10 @@ public String call(Integer x) { private static final Func1 EVICTING_MAP_ELEMENT_SELECTOR = UtilityFunctions.identity(); - private static final Func1 EVICTING_MAP_KEY_SELECTOR = new Func1 (){ + private static final Func1 EVICTING_MAP_KEY_SELECTOR = new Func1 () { @Override public Integer call(Integer t) { - return t /10; + return t / 10; }}; @Test @@ -1969,7 +1969,7 @@ public String call(Integer x) { .map(new Func1() { @Override public String call(Integer x) { - return (x /10) + ":" + x; + return (x / 10) + ":" + x; } }) .toList().toBlocking().single(); @@ -1996,7 +1996,7 @@ public void testEvictingMapFactoryIfMapCreateThrowsRuntimeExceptionThenErrorEmit ts.assertError(exception); } - @Test(expected=OnErrorNotImplementedException.class) + @Test(expected = OnErrorNotImplementedException.class) public void testEvictingMapFactoryIfMapCreateThrowsFatalErrorThenSubscribeThrows() { final OnErrorNotImplementedException exception = new OnErrorNotImplementedException("boo", new RuntimeException()); Func1, Map> mapFactory = createMapFactoryThatThrowsOnCreate(exception); diff --git a/src/test/java/rx/internal/operators/OperatorMaterializeTest.java b/src/test/java/rx/internal/operators/OperatorMaterializeTest.java index 1ddaa6c45d..af090b4379 100644 --- a/src/test/java/rx/internal/operators/OperatorMaterializeTest.java +++ b/src/test/java/rx/internal/operators/OperatorMaterializeTest.java @@ -203,8 +203,8 @@ public void testUnsubscribeJustBeforeCompletionNotificationShouldPreventThatNoti private static class TestObserver extends Subscriber> { - boolean onCompleted = false; - boolean onError = false; + boolean onCompleted; + boolean onError; List> notifications = new Vector>(); @Override diff --git a/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java b/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java index 56aa690b84..56685b1630 100644 --- a/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java +++ b/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java @@ -92,7 +92,7 @@ private static class SubscriptionCheckObservable implements Observable.OnSubscri private final AtomicInteger subscriptionCount; private final int maxConcurrent; - volatile boolean failed = false; + volatile boolean failed; SubscriptionCheckObservable(AtomicInteger subscriptionCount, int maxConcurrent) { this.subscriptionCount = subscriptionCount; diff --git a/src/test/java/rx/internal/operators/OperatorMergeTest.java b/src/test/java/rx/internal/operators/OperatorMergeTest.java index 746f794158..d79649667d 100644 --- a/src/test/java/rx/internal/operators/OperatorMergeTest.java +++ b/src/test/java/rx/internal/operators/OperatorMergeTest.java @@ -667,13 +667,14 @@ public void testBackpressureDownstreamWithConcurrentStreams() throws Interrupted TestSubscriber testSubscriber = new TestSubscriber() { @Override public void onNext(Integer t) { - if (t < 100) + if (t < 100) { try { // force a slow consumer Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } + } // System.err.println("testSubscriber received => " + t + " on thread " + Thread.currentThread()); super.onNext(t); } @@ -708,13 +709,14 @@ public Observable call(Integer t1) { TestSubscriber testSubscriber = new TestSubscriber() { @Override public void onNext(Integer t) { - if (t < 100) + if (t < 100) { try { // force a slow consumer Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } + } // System.err.println("testSubscriber received => " + t + " on thread " + Thread.currentThread()); super.onNext(t); } @@ -759,17 +761,18 @@ public Observable call(Integer t1) { }); TestSubscriber testSubscriber = new TestSubscriber() { - int i = 0; + int i; @Override public void onNext(Integer t) { - if (i++ < 400) + if (i++ < 400) { try { // force a slow consumer Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } + } // System.err.println("testSubscriber received => " + t + " on thread " + Thread.currentThread()); super.onNext(t); } @@ -1197,7 +1200,7 @@ public void onError(Throwable e) { public void onNext(Integer t) { latch.countDown(); request(2); - request(Long.MAX_VALUE-1); + request(Long.MAX_VALUE - 1); }}); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @@ -1311,7 +1314,7 @@ public void onNext(Integer t) { @Test public void testUnboundedDefaultConcurrency() { List> os = new ArrayList>(); - for(int i=0; i < 2000; i++) { + for (int i = 0; i < 2000; i++) { os.add(Observable.never()); } os.add(Observable.range(0, 100)); @@ -1326,7 +1329,7 @@ public void testUnboundedDefaultConcurrency() { @Test public void testConcurrencyLimit() { List> os = new ArrayList>(); - for(int i=0; i < 2000; i++) { + for (int i = 0; i < 2000; i++) { os.add(Observable.never()); } os.add(Observable.range(0, 100)); diff --git a/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java b/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java index aef7303848..ea48f2847e 100644 --- a/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java @@ -129,7 +129,7 @@ public void call() { int size = ts.getOnNextEvents().size(); assertTrue(size <= 150); // will get up to 50 more - assertTrue(ts.getOnNextEvents().get(size-1) == size-1); + assertTrue(ts.getOnNextEvents().get(size - 1) == size - 1); assertTrue(s.isUnsubscribed()); } diff --git a/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java b/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java index 947af54695..87d748e2ea 100644 --- a/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java @@ -121,7 +121,7 @@ public void onError(Throwable e) { public void onNext(Long t) { count.incrementAndGet(); //cause overflow of requested if not handled properly in onBackpressureDrop operator - request(Long.MAX_VALUE-1); + request(Long.MAX_VALUE - 1); }}); assertEquals(n, count.get()); } @@ -308,7 +308,7 @@ private static final Observable range(final long n) { @Override public void call(Subscriber s) { - for (long i=0;i < n;i++) { + for (long i = 0;i < n;i++) { if (s.isUnsubscribed()) { break; } diff --git a/src/test/java/rx/internal/operators/OperatorOnBackpressureLatestTest.java b/src/test/java/rx/internal/operators/OperatorOnBackpressureLatestTest.java index cbcd3d26f8..a226159529 100644 --- a/src/test/java/rx/internal/operators/OperatorOnBackpressureLatestTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnBackpressureLatestTest.java @@ -124,7 +124,7 @@ public void onNext(Integer t) { if (rnd.nextDouble() < 0.001) { try { Thread.sleep(1); - } catch(InterruptedException ex) { + } catch (InterruptedException ex) { ex.printStackTrace(); } } diff --git a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java index d4ec5d756d..9076e2f542 100644 --- a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java @@ -242,8 +242,9 @@ public void testMapResumeAsyncNext() { w = w.map(new Func1() { @Override public String call(String s) { - if ("fail".equals(s)) + if ("fail".equals(s)) { throw new RuntimeException("Forced Failure"); + } System.out.println("BadMapper:" + s); return s; } @@ -277,7 +278,7 @@ private static class TestObservable implements Observable.OnSubscribe { final Subscription s; final String[] values; - Thread t = null; + Thread t; public TestObservable(Subscription s, String... values) { this.s = s; @@ -326,7 +327,7 @@ public Observable call(Throwable t1) { }) .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t1) { diff --git a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java index 418324f7f4..a7315a9158 100644 --- a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java @@ -79,8 +79,9 @@ public void testMapResumeAsyncNext() { w = w.map(new Func1() { @Override public String call(String s) { - if ("fail".equals(s)) + if ("fail".equals(s)) { throw new RuntimeException("Forced Failure"); + } System.out.println("BadMapper:" + s); return s; } @@ -158,7 +159,7 @@ private static class TestObservable implements Observable.OnSubscribe { final Subscription s; final String[] values; - Thread t = null; + Thread t; public TestObservable(Subscription s, String... values) { this.s = s; @@ -176,8 +177,9 @@ public void run() { try { System.out.println("running TestObservable thread"); for (String s : values) { - if ("fail".equals(s)) + if ("fail".equals(s)) { throw new RuntimeException("Forced Failure"); + } System.out.println("TestObservable onNext: " + s); observer.onNext(s); } @@ -203,7 +205,7 @@ public void testBackpressure() { .onErrorResumeNext(Observable.just(1)) .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t1) { diff --git a/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java b/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java index 1b08ced1ca..57a16e7829 100644 --- a/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java @@ -119,8 +119,9 @@ public void testMapResumeAsyncNext() { w = w.map(new Func1() { @Override public String call(String s) { - if ("fail".equals(s)) + if ("fail".equals(s)) { throw new RuntimeException("Forced Failure"); + } System.out.println("BadMapper:" + s); return s; } @@ -163,7 +164,7 @@ public Integer call(Throwable t1) { }) .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t1) { @@ -187,7 +188,7 @@ public Integer call(Integer t1) { private static class TestObservable implements Observable.OnSubscribe { final String[] values; - Thread t = null; + Thread t; public TestObservable(String... values) { this.values = values; diff --git a/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java b/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java index 7522ae6d86..3b403f90e1 100644 --- a/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java @@ -156,8 +156,9 @@ public void testMapResumeAsyncNext() { w = w.map(new Func1() { @Override public String call(String s) { - if ("fail".equals(s)) + if ("fail".equals(s)) { throw new RuntimeException("Forced Failure"); + } System.out.println("BadMapper:" + s); return s; } @@ -195,7 +196,7 @@ public void testBackpressure() { .onExceptionResumeNext(Observable.just(1)) .observeOn(Schedulers.computation()) .map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer t1) { @@ -220,7 +221,7 @@ public Integer call(Integer t1) { private static class TestObservable implements Observable.OnSubscribe { final String[] values; - Thread t = null; + Thread t; public TestObservable(String... values) { this.values = values; @@ -236,14 +237,15 @@ public void run() { try { System.out.println("running TestObservable thread"); for (String s : values) { - if ("EXCEPTION".equals(s)) + if ("EXCEPTION".equals(s)) { throw new Exception("Forced Exception"); - else if ("RUNTIMEEXCEPTION".equals(s)) + } else if ("RUNTIMEEXCEPTION".equals(s)) { throw new RuntimeException("Forced RuntimeException"); - else if ("ON_OVERFLOW_ERROR".equals(s)) + } else if ("ON_OVERFLOW_ERROR".equals(s)) { throw new Error("Forced Error"); - else if ("THROWABLE".equals(s)) + } else if ("THROWABLE".equals(s)) { throw new Throwable("Forced Throwable"); + } System.out.println("TestObservable onNext: " + s); observer.onNext(s); } diff --git a/src/test/java/rx/internal/operators/OperatorPublishTest.java b/src/test/java/rx/internal/operators/OperatorPublishTest.java index ba2f114742..d0f524159f 100644 --- a/src/test/java/rx/internal/operators/OperatorPublishTest.java +++ b/src/test/java/rx/internal/operators/OperatorPublishTest.java @@ -98,7 +98,7 @@ public void call() { }); Observable slow = is.observeOn(Schedulers.computation()).map(new Func1() { - int c = 0; + int c; @Override public Integer call(Integer i) { diff --git a/src/test/java/rx/internal/operators/OperatorRetryTest.java b/src/test/java/rx/internal/operators/OperatorRetryTest.java index 100891b792..7937f8945f 100644 --- a/src/test/java/rx/internal/operators/OperatorRetryTest.java +++ b/src/test/java/rx/internal/operators/OperatorRetryTest.java @@ -57,9 +57,9 @@ public void call(Subscriber t1) { if (count.getAndDecrement() == 0) { t1.onNext("hello"); t1.onCompleted(); - } - else + } else { t1.onError(new RuntimeException()); + } } }); @@ -75,7 +75,7 @@ public Observable call(Observable attempts) { public Tuple call(Throwable n) { return new Tuple(new Long(1), n); }}) - .scan(new Func2(){ + .scan(new Func2() { @Override public Tuple call(Tuple t, Tuple n) { return new Tuple(t.count + n.count, n.n); @@ -83,10 +83,10 @@ public Tuple call(Tuple t, Tuple n) { .flatMap(new Func1>() { @Override public Observable call(Tuple t) { - System.out.println("Retry # "+t.count); + System.out.println("Retry # " + t.count); return t.count > 20 ? Observable.error(t.n) : - Observable.timer(t.count *1L, TimeUnit.MILLISECONDS); + Observable.timer(t.count * 1L, TimeUnit.MILLISECONDS); }}); } }).subscribe(ts); @@ -398,7 +398,7 @@ public void call(final Subscriber o) { final AtomicLong req = new AtomicLong(); // 0 = not set, 1 = fast path, 2 = backpressure final AtomicInteger path = new AtomicInteger(0); - volatile boolean done = false; + volatile boolean done; @Override public void request(long n) { @@ -463,7 +463,7 @@ public void testRetryAllowsSubscriptionAfterAllSubscriptionsUnsubscribed() throw public void call(Subscriber s) { subsCount.incrementAndGet(); s.add(new Subscription() { - boolean unsubscribed = false; + boolean unsubscribed; @Override public void unsubscribe() { @@ -695,7 +695,7 @@ public void testTimeoutWithRetry() { @Test//(timeout = 15000) public void testRetryWithBackpressure() throws InterruptedException { final int NUM_LOOPS = 1; - for (int j=0;j o) { - for(int i=0; i list = new CopyOnWriteArrayList(); final AtomicBoolean isFirst = new AtomicBoolean(true); - Observable. just(1L, 2L, 3L).map(new Func1(){ + Observable. just(1L, 2L, 3L).map(new Func1() { @Override public Long call(Long x) { System.out.println("map " + x); @@ -348,7 +348,7 @@ public void call(Long t) { public void testIssue3008RetryInfinite() { final List list = new CopyOnWriteArrayList(); final AtomicBoolean isFirst = new AtomicBoolean(true); - Observable. just(1L, 2L, 3L).map(new Func1(){ + Observable. just(1L, 2L, 3L).map(new Func1() { @Override public Long call(Long x) { System.out.println("map " + x); diff --git a/src/test/java/rx/internal/operators/OperatorSerializeTest.java b/src/test/java/rx/internal/operators/OperatorSerializeTest.java index 153df50fa2..450e2e0185 100644 --- a/src/test/java/rx/internal/operators/OperatorSerializeTest.java +++ b/src/test/java/rx/internal/operators/OperatorSerializeTest.java @@ -223,7 +223,7 @@ private enum TestConcurrencyobserverEvent { private static class TestSingleThreadedObservable implements Observable.OnSubscribe { final String[] values; - private Thread t = null; + private Thread t; public TestSingleThreadedObservable(final String... values) { this.values = values; @@ -270,7 +270,7 @@ public void waitToFinish() { */ private static class TestMultiThreadedObservable implements Observable.OnSubscribe { final String[] values; - Thread t = null; + Thread t; AtomicInteger threadsRunning = new AtomicInteger(); AtomicInteger maxConcurrentThreads = new AtomicInteger(); ExecutorService threadPool; @@ -302,8 +302,9 @@ public void run() { System.out.println("TestMultiThreadedObservable onNext: null"); // force an error throw npe; - } else + } else { System.out.println("TestMultiThreadedObservable onNext: " + s); + } observer.onNext(s); // capture 'maxThreads' int concurrentThreads = threadsRunning.get(); @@ -350,8 +351,8 @@ public void waitToFinish() { } private static class BusyObserver extends Subscriber { - volatile boolean onCompleted = false; - volatile boolean onError = false; + volatile boolean onCompleted; + volatile boolean onError; AtomicInteger onNextCount = new AtomicInteger(); AtomicInteger threadsRunning = new AtomicInteger(); AtomicInteger maxConcurrentThreads = new AtomicInteger(); diff --git a/src/test/java/rx/internal/operators/OperatorSkipTest.java b/src/test/java/rx/internal/operators/OperatorSkipTest.java index 649c562bb2..fdfd12de1d 100644 --- a/src/test/java/rx/internal/operators/OperatorSkipTest.java +++ b/src/test/java/rx/internal/operators/OperatorSkipTest.java @@ -172,7 +172,7 @@ public void call(Long n) { @Test public void testRequestOverflowDoesNotOccur() { - TestSubscriber ts = new TestSubscriber(Long.MAX_VALUE-1); + TestSubscriber ts = new TestSubscriber(Long.MAX_VALUE - 1); Observable.range(1, 10).skip(5).subscribe(ts); ts.assertTerminalEvent(); ts.assertCompleted(); diff --git a/src/test/java/rx/internal/operators/OperatorSkipWhileTest.java b/src/test/java/rx/internal/operators/OperatorSkipWhileTest.java index f17b3ac07a..205ed930bb 100644 --- a/src/test/java/rx/internal/operators/OperatorSkipWhileTest.java +++ b/src/test/java/rx/internal/operators/OperatorSkipWhileTest.java @@ -44,14 +44,15 @@ public class OperatorSkipWhileTest { private static final Func1 LESS_THAN_FIVE = new Func1() { @Override public Boolean call(Integer v) { - if (v == 42) + if (v == 42) { throw new RuntimeException("that's not the answer to everything!"); + } return v < 5; } }; private static final Func1 INDEX_LESS_THAN_THREE = new Func1() { - int index = 0; + int index; @Override public Boolean call(Integer value) { return index++ < 3; diff --git a/src/test/java/rx/internal/operators/OperatorSwitchTest.java b/src/test/java/rx/internal/operators/OperatorSwitchTest.java index 9b1d1be8b4..1a8732e341 100644 --- a/src/test/java/rx/internal/operators/OperatorSwitchTest.java +++ b/src/test/java/rx/internal/operators/OperatorSwitchTest.java @@ -412,16 +412,16 @@ public void testBackpressure() { public void call(final Subscriber observer) { observer.setProducer(new Producer() { - private int emitted = 0; + private int emitted; @Override public void request(long n) { - for(int i = 0; i < n && emitted < 10 && !observer.isUnsubscribed(); i++) { + for (int i = 0; i < n && emitted < 10 && !observer.isUnsubscribed(); i++) { scheduler.advanceTimeBy(5, TimeUnit.MILLISECONDS); emitted++; observer.onNext("a" + emitted); } - if(emitted == 10) { + if (emitted == 10) { observer.onCompleted(); } } @@ -433,16 +433,16 @@ public void request(long n) { public void call(final Subscriber observer) { observer.setProducer(new Producer() { - private int emitted = 0; + private int emitted; @Override public void request(long n) { - for(int i = 0; i < n && emitted < 10 && !observer.isUnsubscribed(); i++) { + for (int i = 0; i < n && emitted < 10 && !observer.isUnsubscribed(); i++) { scheduler.advanceTimeBy(5, TimeUnit.MILLISECONDS); emitted++; observer.onNext("b" + emitted); } - if(emitted == 10) { + if (emitted == 10) { observer.onCompleted(); } } @@ -454,15 +454,15 @@ public void request(long n) { public void call(final Subscriber observer) { observer.setProducer(new Producer() { - private int emitted = 0; + private int emitted; @Override public void request(long n) { - for(int i = 0; i < n && emitted < 10 && !observer.isUnsubscribed(); i++) { + for (int i = 0; i < n && emitted < 10 && !observer.isUnsubscribed(); i++) { emitted++; observer.onNext("c" + emitted); } - if(emitted == 10) { + if (emitted == 10) { observer.onCompleted(); } } @@ -481,7 +481,7 @@ public void call(Subscriber> observer) { final TestSubscriber testSubscriber = new TestSubscriber(); Observable.switchOnNext(o).subscribe(new Subscriber() { - private int requested = 0; + private int requested; @Override public void onStart() { @@ -503,7 +503,7 @@ public void onError(Throwable e) { public void onNext(String s) { testSubscriber.onNext(s); requested--; - if(requested == 0) { + if (requested == 0) { requested = 3; request(3); } @@ -657,7 +657,7 @@ public Observable call(Long t) { ts.awaitTerminalEvent(); assertTrue(ts.getOnNextEvents().size() > 0); assertEquals(4, requests.size()); // depends on the request pattern - assertEquals(Long.MAX_VALUE, (long) requests.get(requests.size()-1)); + assertEquals(Long.MAX_VALUE, (long) requests.get(requests.size() - 1)); } @Test diff --git a/src/test/java/rx/internal/operators/OperatorTakeLastTest.java b/src/test/java/rx/internal/operators/OperatorTakeLastTest.java index 23a4361f0f..1a2eddec64 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeLastTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeLastTest.java @@ -133,7 +133,7 @@ public void testBackpressure2() { private Func1 newSlowProcessor() { return new Func1() { - int c = 0; + int c; @Override public Integer call(Integer i) { @@ -292,7 +292,7 @@ public void onNext(Integer integer) { assertEquals(1,count.get()); } - @Test(timeout=10000) + @Test(timeout = 10000) public void testRequestOverflow() { final List list = new ArrayList(); Observable.range(1, 100).takeLast(50).subscribe(new Subscriber() { @@ -315,7 +315,7 @@ public void onError(Throwable e) { @Override public void onNext(Integer t) { list.add(t); - request(Long.MAX_VALUE-1); + request(Long.MAX_VALUE - 1); }}); assertEquals(50, list.size()); } @@ -343,7 +343,7 @@ public void completionRequestRace() { w.schedule(new Action0() { @Override public void call() { - while (!go.get()); + while (!go.get()) { } ts.requestMore(n + 1); } }); diff --git a/src/test/java/rx/internal/operators/OperatorTakeLastTimedTest.java b/src/test/java/rx/internal/operators/OperatorTakeLastTimedTest.java index 70794d1aa1..491825d3f9 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeLastTimedTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeLastTimedTest.java @@ -237,7 +237,7 @@ public void completionRequestRace() { w.schedule(new Action0() { @Override public void call() { - while (!go.get()); + while (!go.get()) { } ts.requestMore(n + 1); } }); diff --git a/src/test/java/rx/internal/operators/OperatorTakeTest.java b/src/test/java/rx/internal/operators/OperatorTakeTest.java index c056e8b8f8..0dc3dbc8c4 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeTest.java @@ -245,7 +245,7 @@ public void call(Integer t1) { private static class TestObservableFunc implements Observable.OnSubscribe { final String[] values; - Thread t = null; + Thread t; public TestObservableFunc(String... values) { this.values = values; diff --git a/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java b/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java index f51aa9cd26..28c0c432ff 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java @@ -163,7 +163,7 @@ public void testTakeUntilOtherCompleted() { private static class TestObservable implements Observable.OnSubscribe { - Observer observer = null; + Observer observer; Subscription s; public TestObservable(Subscription s) { diff --git a/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java b/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java index f80b863f9c..0a3cd3ec94 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java @@ -87,7 +87,7 @@ public Boolean call(Integer input) { public void testTakeWhile2() { Observable w = Observable.just("one", "two", "three"); Observable take = w.takeWhile(new Func1() { - int index = 0; + int index; @Override public Boolean call(String input) { @@ -158,7 +158,7 @@ public void testUnsubscribeAfterTake() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); Observable take = Observable.create(w).takeWhile(new Func1() { - int index = 0; + int index; @Override public Boolean call(String s) { @@ -186,7 +186,7 @@ private static class TestObservable implements Observable.OnSubscribe { final Subscription s; final String[] values; - Thread t = null; + Thread t; public TestObservable(Subscription s, String... values) { this.s = s; diff --git a/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java b/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java index 456f48a998..d2d0e2e567 100644 --- a/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java +++ b/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java @@ -393,7 +393,7 @@ public void run() { source.timeout(timeoutFunc, Observable.just(3)).subscribe(ts); source.onNext(1); // start timeout try { - if(!enteredTimeoutOne.await(30, TimeUnit.SECONDS)) { + if (!enteredTimeoutOne.await(30, TimeUnit.SECONDS)) { latchTimeout.set(true); } } catch (InterruptedException e) { @@ -401,7 +401,7 @@ public void run() { } source.onNext(2); // disable timeout try { - if(!timeoutEmittedOne.await(30, TimeUnit.SECONDS)) { + if (!timeoutEmittedOne.await(30, TimeUnit.SECONDS)) { latchTimeout.set(true); } } catch (InterruptedException e) { @@ -412,7 +412,7 @@ public void run() { }).start(); - if(!observerCompleted.await(30, TimeUnit.SECONDS)) { + if (!observerCompleted.await(30, TimeUnit.SECONDS)) { latchTimeout.set(true); } diff --git a/src/test/java/rx/internal/operators/OperatorToObservableSortedListTest.java b/src/test/java/rx/internal/operators/OperatorToObservableSortedListTest.java index 2fb7bc4d28..5081c2cb63 100644 --- a/src/test/java/rx/internal/operators/OperatorToObservableSortedListTest.java +++ b/src/test/java/rx/internal/operators/OperatorToObservableSortedListTest.java @@ -259,11 +259,11 @@ public void testSortedWithNonComparable() { testSubscriber.assertNotCompleted(); } - final static class NonComparable{ + final static class NonComparable { public int i; public String s; - NonComparable(int i, String s){ + NonComparable(int i, String s) { this.i = i; this.s = s; } diff --git a/src/test/java/rx/internal/operators/OperatorZipIterableTest.java b/src/test/java/rx/internal/operators/OperatorZipIterableTest.java index d82465428d..bfcd20c09d 100644 --- a/src/test/java/rx/internal/operators/OperatorZipIterableTest.java +++ b/src/test/java/rx/internal/operators/OperatorZipIterableTest.java @@ -366,8 +366,8 @@ static final class SquareStr implements Func1 { @Override public String call(Integer t1) { counter.incrementAndGet(); - System.out.println("Omg I'm calculating so hard: " + t1 + "*" + t1 + "=" + (t1*t1)); - return " " + (t1*t1); + System.out.println("Omg I'm calculating so hard: " + t1 + "*" + t1 + "=" + (t1 * t1)); + return " " + (t1 * t1); } } diff --git a/src/test/java/rx/internal/operators/OperatorZipTest.java b/src/test/java/rx/internal/operators/OperatorZipTest.java index 950d506201..908f44a23d 100644 --- a/src/test/java/rx/internal/operators/OperatorZipTest.java +++ b/src/test/java/rx/internal/operators/OperatorZipTest.java @@ -1315,7 +1315,7 @@ public void testZipRace() { // time limit of 9 seconds ( 1 second less than the test timeout) is // used so that this test will not timeout on slow machines. int i = 0; - while (System.currentTimeMillis()-startTime < 9000 && i++ < 100000) { + while (System.currentTimeMillis() - startTime < 9000 && i++ < 100000) { int value = Observable.zip(src, src, new Func2() { @Override public Integer call(Integer t1, Integer t2) { diff --git a/src/test/java/rx/internal/operators/SafeSubscriberTest.java b/src/test/java/rx/internal/operators/SafeSubscriberTest.java index 8cd7c18031..cf71a8f5d1 100644 --- a/src/test/java/rx/internal/operators/SafeSubscriberTest.java +++ b/src/test/java/rx/internal/operators/SafeSubscriberTest.java @@ -126,7 +126,7 @@ public void testOnErrorAfterOnCompleted() { */ private static class TestObservable implements Observable.OnSubscribe { - Observer observer = null; + Observer observer; /* used to simulate subscription */ public void sendOnCompleted() { diff --git a/src/test/java/rx/internal/operators/SingleOnSubscribeUsingTest.java b/src/test/java/rx/internal/operators/SingleOnSubscribeUsingTest.java index 61c2015b4e..e8fc60ead5 100644 --- a/src/test/java/rx/internal/operators/SingleOnSubscribeUsingTest.java +++ b/src/test/java/rx/internal/operators/SingleOnSubscribeUsingTest.java @@ -273,7 +273,7 @@ public void disposesEagerlyBeforeCompletion() { final List events = new ArrayList(); Func0 resourceFactory = createResourceFactory(events); final Action1 completion = createOnSuccessAction(events); - final Action0 unsub =createUnsubAction(events); + final Action0 unsub = createUnsubAction(events); Func1> observableFactory = new Func1>() { @Override @@ -298,7 +298,7 @@ public void doesNotDisposesEagerlyBeforeCompletion() { final List events = new ArrayList(); Func0 resourceFactory = createResourceFactory(events); final Action1 completion = createOnSuccessAction(events); - final Action0 unsub =createUnsubAction(events); + final Action0 unsub = createUnsubAction(events); Func1> observableFactory = new Func1>() { @Override diff --git a/src/test/java/rx/internal/producers/SingleDelayedProducerTest.java b/src/test/java/rx/internal/producers/SingleDelayedProducerTest.java index d3e074df04..f21753f4a3 100644 --- a/src/test/java/rx/internal/producers/SingleDelayedProducerTest.java +++ b/src/test/java/rx/internal/producers/SingleDelayedProducerTest.java @@ -56,14 +56,14 @@ public void requestCompleteRace() throws Exception { @Override public void call() { waiter.decrementAndGet(); - while (waiter.get() != 0) ; + while (waiter.get() != 0) { } pa.request(1); cdl.countDown(); } }); waiter.decrementAndGet(); - while (waiter.get() != 0) ; + while (waiter.get() != 0) { } pa.setValue(1); if (!cdl.await(5, TimeUnit.SECONDS)) { Assert.fail("The wait for completion timed out"); diff --git a/src/test/java/rx/internal/schedulers/NewThreadWorkerTest.java b/src/test/java/rx/internal/schedulers/NewThreadWorkerTest.java index 4368953241..f162ad958b 100644 --- a/src/test/java/rx/internal/schedulers/NewThreadWorkerTest.java +++ b/src/test/java/rx/internal/schedulers/NewThreadWorkerTest.java @@ -49,7 +49,7 @@ public void findSetRemoveOnCancelPolicyMethodShouldNotFindMethod() { private static abstract class ScheduledExecutorServiceWithSetRemoveOnCancelPolicy implements ScheduledExecutorService { // Just declaration of required method to allow run tests on JDK 6 - public void setRemoveOnCancelPolicy(boolean value) {} + public void setRemoveOnCancelPolicy(boolean value) { } } @Test diff --git a/src/test/java/rx/internal/util/IndexedRingBufferTest.java b/src/test/java/rx/internal/util/IndexedRingBufferTest.java index 5ed75ea5e5..233557ac08 100644 --- a/src/test/java/rx/internal/util/IndexedRingBufferTest.java +++ b/src/test/java/rx/internal/util/IndexedRingBufferTest.java @@ -186,7 +186,7 @@ public Boolean call(String t1) { list.clear(); nextIndex = buffer.forEach(new Func1() { - int i = 0; + int i; @Override public Boolean call(String t1) { diff --git a/src/test/java/rx/internal/util/JCToolsQueueTests.java b/src/test/java/rx/internal/util/JCToolsQueueTests.java index 1ec3c202bb..eb89381d94 100644 --- a/src/test/java/rx/internal/util/JCToolsQueueTests.java +++ b/src/test/java/rx/internal/util/JCToolsQueueTests.java @@ -169,7 +169,7 @@ public void run() { Integer j; for (int i = 0; i < 1000 * 1000; i++) { - while ((j = q.poll()) == null); + while ((j = q.poll()) == null) { } assertTrue("Value " + j + " already removed", set.remove(j)); } assertTrue("Set is not empty", set.isEmpty()); @@ -242,7 +242,7 @@ public void run() { Integer j; for (int i = 0; i < 1000 * 1000; i++) { - while ((j = q.poll()) == null); + while ((j = q.poll()) == null) { } assertTrue("Value " + j + " already removed", set.remove(j)); } assertTrue("Set is not empty", set.isEmpty()); @@ -366,7 +366,7 @@ public void testSpscLinkedAtomicQueuePipelined() throws InterruptedException { public void run() { Integer j; for (int i = 0; i < 1000 * 1000; i++) { - while ((j = q.poll()) == null); + while ((j = q.poll()) == null) { } if (j == i) { count.getAndIncrement(); } @@ -424,7 +424,7 @@ public void testSpscLinkedQueuePipelined() throws InterruptedException { public void run() { Integer j; for (int i = 0; i < 1000 * 1000; i++) { - while ((j = q.poll()) == null); + while ((j = q.poll()) == null) { } if (j == i) { count.getAndIncrement(); } diff --git a/src/test/java/rx/internal/util/SynchronizedQueueTest.java b/src/test/java/rx/internal/util/SynchronizedQueueTest.java deleted file mode 100644 index 977c458d7c..0000000000 --- a/src/test/java/rx/internal/util/SynchronizedQueueTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/** - * Copyright 2016 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.internal.util; - -import static org.junit.Assert.assertTrue; - -import java.util.*; - -import org.junit.*; - -public class SynchronizedQueueTest { - SynchronizedQueue q = new SynchronizedQueue(); - - @Test - public void testEquals() { - - assertTrue(q.equals(q)); - } - - @Test - public void contains() { - q.offer(1); - Assert.assertTrue(q.add(2)); - - Assert.assertEquals(2, q.size()); - Assert.assertTrue(q.contains(1)); - Assert.assertTrue(q.contains(2)); - Assert.assertFalse(q.contains(3)); - } - - @Test - public void iterator() { - q.offer(1); - - Assert.assertEquals(1, q.iterator().next()); - } - - @Test - public void remove() { - q.offer(1); - q.offer(2); - q.offer(3); - - Assert.assertTrue(q.remove(2)); - Assert.assertFalse(q.remove(2)); - } - - @Test - public void addAllContainsAll() { - q.addAll(Arrays.asList(1, 2, 3, 4)); - - q.removeAll(Arrays.asList(2, 3)); - - Assert.assertEquals(2, q.size()); - Assert.assertTrue(q.contains(1)); - Assert.assertFalse(q.contains(2)); - Assert.assertFalse(q.contains(3)); - Assert.assertTrue(q.contains(4)); - - Assert.assertTrue(q.containsAll(Arrays.asList(1, 4))); - Assert.assertFalse(q.containsAll(Arrays.asList(2, 3))); - } - - @Test - public void retainAll() { - q.addAll(Arrays.asList(1, 2, 3, 4)); - - q.retainAll(Arrays.asList(2, 3)); - - Assert.assertEquals(2, q.size()); - Assert.assertFalse(q.contains(1)); - Assert.assertTrue(q.contains(2)); - Assert.assertTrue(q.contains(3)); - Assert.assertFalse(q.contains(4)); - } - - @Test - public void clear() { - q.addAll(Arrays.asList(1, 2, 3, 4)); - - q.clear(); - - Assert.assertEquals(0, q.size()); - Assert.assertTrue(q.isEmpty()); - } - - @Test - public void toStringValue() { - q.offer(1); - - Assert.assertEquals("[1]", q.toString()); - } - - @Test - public void equalsTo() { - q.offer(1); - - SynchronizedQueue q2 = new SynchronizedQueue(); - q2.offer(1); - - SynchronizedQueue q3 = new SynchronizedQueue(); - q3.offer(2); - - Assert.assertEquals(q, q2); - Assert.assertEquals(q.hashCode(), q2.hashCode()); - Assert.assertNotEquals(q, q3); - - Assert.assertFalse(q.equals(null)); - Assert.assertFalse(q.equals(1)); - - Assert.assertEquals(q, q.clone()); - - } - - @Test - public void toArray() { - q.offer(1); - - Object[] a = q.toArray(); - - Object[] b = q.toArray(new Integer[1]); - - Assert.assertEquals(1, a[0]); - Assert.assertEquals(1, b[0]); - } - - @Test - public void peekElement() { - q.offer(1); - - Assert.assertEquals(1, q.peek()); - Assert.assertEquals(1, q.element()); - Assert.assertEquals(1, q.remove()); - try { - q.element(); - Assert.fail("Failed to throw on empty queue"); - } catch (NoSuchElementException ex) { - // expected - } - } -} diff --git a/src/test/java/rx/observables/AsyncOnSubscribeTest.java b/src/test/java/rx/observables/AsyncOnSubscribeTest.java index 931b7c1d3f..a711d92c91 100644 --- a/src/test/java/rx/observables/AsyncOnSubscribeTest.java +++ b/src/test/java/rx/observables/AsyncOnSubscribeTest.java @@ -60,12 +60,12 @@ public void setup() { @Test public void testSerializesConcurrentObservables() throws InterruptedException { final TestScheduler scheduler = new TestScheduler(); - AsyncOnSubscribe os = AsyncOnSubscribe.createStateful(new Func0(){ + AsyncOnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { if (state == 1) { @@ -76,9 +76,9 @@ public Integer call(Integer state, Long requested, Observer o = Observable.just(5, 6, 7, 8); observer.onNext(o); - } - else + } else { observer.onCompleted(); + } return state + 1; }}); // initial request emits [[1, 2, 3, 4]] on delay @@ -105,7 +105,7 @@ else if (state == 2) { public void testSubscribedByBufferingOperator() { final TestScheduler scheduler = new TestScheduler(); OnSubscribe os = AsyncOnSubscribe.createStateless( - new Action2>>(){ + new Action2>>() { @Override public void call(Long requested, Observer> observer) { observer.onNext(Observable.range(1, requested.intValue())); @@ -121,19 +121,19 @@ public void call(Long requested, Observer> observe @Test public void testOnUnsubscribeHasCorrectState() throws InterruptedException { final AtomicInteger lastState = new AtomicInteger(-1); - OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { if (state < 3) { observer.onNext(Observable.just(state)); - } - else + } else { observer.onCompleted(); + } return state + 1; }}, new Action1() { @@ -153,7 +153,7 @@ public void call(Integer t) { @Test public void testOnCompleteOuter() throws InterruptedException { - OnSubscribe os = AsyncOnSubscribe.createStateless(new Action2>>(){ + OnSubscribe os = AsyncOnSubscribe.createStateless(new Action2>>() { @Override public void call(Long requested, Observer> observer) { observer.onCompleted(); @@ -167,7 +167,7 @@ public void call(Long requested, Observer> observe @Test public void testTryOnNextTwice() throws InterruptedException { - OnSubscribe os = AsyncOnSubscribe.createStateless(new Action2>>(){ + OnSubscribe os = AsyncOnSubscribe.createStateless(new Action2>>() { @Override public void call(Long requested, Observer> observer) { observer.onNext(Observable.just(1)); @@ -184,7 +184,7 @@ public void call(Long requested, Observer> observe @Test public void testThrowException() throws InterruptedException { OnSubscribe os = AsyncOnSubscribe.createStateless( - new Action2>>(){ + new Action2>>() { @Override public void call(Long requested, Observer> observer) { throw new TestException(); @@ -198,12 +198,12 @@ public void call(Long requested, Observer> observe @Test public void testThrowExceptionAfterTerminal() throws InterruptedException { - OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { observer.onCompleted(); @@ -218,12 +218,12 @@ public Integer call(Integer state, Long requested, Observer os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { observer.onCompleted(); @@ -239,12 +239,12 @@ public Integer call(Integer state, Long requested, Observer os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { observer.onError(new TestException()); @@ -260,12 +260,12 @@ public Integer call(Integer state, Long requested, Observer os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { observer.onNext(Observable.empty()); @@ -281,12 +281,12 @@ public Integer call(Integer state, Long requested, Observer os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { observer.onError(new TestException()); @@ -302,12 +302,12 @@ public Integer call(Integer state, Long requested, Observer os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { observer.onCompleted(); @@ -326,19 +326,19 @@ public Integer call(Integer state, Long requested, Observer os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { Observable o1; switch (state) { case 1: o1 = Observable.just(1) - .doOnUnsubscribe(new Action0(){ + .doOnUnsubscribe(new Action0() { @Override public void call() { l1.incrementAndGet(); @@ -346,7 +346,7 @@ public void call() { break; case 2: o1 = Observable.just(2) - .doOnUnsubscribe(new Action0(){ + .doOnUnsubscribe(new Action0() { @Override public void call() { l2.incrementAndGet(); @@ -380,19 +380,19 @@ public void testUnsubscribesFromAllNonTerminatedObservables() throws Interrupted final AtomicInteger l2 = new AtomicInteger(); final TestScheduler scheduler = new TestScheduler(); final AtomicReference sub = new AtomicReference(); - OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { switch (state) { case 1: observer.onNext(Observable.range(1, requested.intValue()) .subscribeOn(scheduler) - .doOnUnsubscribe(new Action0(){ + .doOnUnsubscribe(new Action0() { @Override public void call() { l1.incrementAndGet(); @@ -402,7 +402,7 @@ public void call() { observer.onNext(Observable.just(1) .concatWith(Observable.never()) .subscribeOn(scheduler) - .doOnUnsubscribe(new Action0(){ + .doOnUnsubscribe(new Action0() { @Override public void call() { l2.incrementAndGet(); @@ -429,29 +429,30 @@ public void call() { assertEquals("did not unsub from Observable.never() inner obs", 1, l2.get()); } - private static class Foo {} - private static class Bar extends Foo {} + private static class Foo { } + private static class Bar extends Foo { } @Test public void testGenerics() { - AsyncOnSubscribe.createStateless(new Action2>>(){ + AsyncOnSubscribe.createStateless(new Action2>>() { @Override public void call(Long state, Observer> observer) { - if (state == null) + if (state == null) { observer.onNext(Observable.just(new Foo())); - else + } else { observer.onNext(Observable.just(new Bar())); + } }}); } @Test public void testUnderdeliveryCorrection() { - OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = AsyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; }}, - new Func3>, Integer>(){ + new Func3>, Integer>() { @Override public Integer call(Integer state, Long requested, Observer> observer) { switch (state) { diff --git a/src/test/java/rx/observables/BlockingObservableTest.java b/src/test/java/rx/observables/BlockingObservableTest.java index 43e0889318..dfb57d26ff 100644 --- a/src/test/java/rx/observables/BlockingObservableTest.java +++ b/src/test/java/rx/observables/BlockingObservableTest.java @@ -565,7 +565,7 @@ private Observable createSynchronousObservable() { @Override public Iterator iterator() { return new Iterator() { - private boolean nextCalled = false; + private boolean nextCalled; @Override public boolean hasNext() { diff --git a/src/test/java/rx/observables/SyncOnSubscribeTest.java b/src/test/java/rx/observables/SyncOnSubscribeTest.java index 398c1a4d45..630561b0a3 100644 --- a/src/test/java/rx/observables/SyncOnSubscribeTest.java +++ b/src/test/java/rx/observables/SyncOnSubscribeTest.java @@ -62,7 +62,7 @@ public void call(Observer subscriber) { @Test public void testStateAfterTerminal() { final AtomicInteger finalStateValue = new AtomicInteger(-1); - OnSubscribe os = SyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = SyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return 1; @@ -299,7 +299,7 @@ public void call(Observer subscriber) { public void testRange() { final int start = 1; final int count = 4000; - OnSubscribe os = SyncOnSubscribe.createStateful(new Func0(){ + OnSubscribe os = SyncOnSubscribe.createStateful(new Func0() { @Override public Integer call() { return start; @@ -557,7 +557,7 @@ public void call(Observer observer) { observer.onNext(null); currentlyEvaluating.set(false); }}, - new Action0(){ + new Action0() { @Override public void call() { calledUnsubscribe.incrementAndGet(); @@ -569,10 +569,10 @@ public void call() { final CountDownLatch latch = new CountDownLatch(1); final TestSubscriber ts = new TestSubscriber(o); - Observable.create(os).lift(new Operator(){ + Observable.create(os).lift(new Operator() { @Override public Subscriber call(final Subscriber subscriber) { - return new Subscriber(subscriber){ + return new Subscriber(subscriber) { @Override public void setProducer(Producer p) { p.request(1); @@ -590,7 +590,7 @@ public void onError(Throwable e) { @Override public void onNext(final Void t) { subscriber.onNext(t); - new Thread(new Runnable(){ + new Thread(new Runnable() { @Override public void run() { try { @@ -709,8 +709,9 @@ public void testObserveOn() { @Override public Integer call(Integer calls, Observer observer) { observer.onNext(calls); - if (calls == count) + if (calls == count) { observer.onCompleted(); + } return calls + 1; }}, onUnSubscribe); @@ -812,10 +813,10 @@ protected void onUnsubscribe(Object state) { assertEquals(1, countUnsubs.get()); } - private interface FooQux {} - private static class Foo implements FooQux {} - private interface BarQux extends FooQux {} - private static class Bar extends Foo implements BarQux {} + private interface FooQux { } + private static class Foo implements FooQux { } + private interface BarQux extends FooQux { } + private static class Bar extends Foo implements BarQux { } @Test public void testGenericsCreateSingleState() { @@ -932,7 +933,7 @@ private void assertJustBehavior(OnSubscribe os) { } @Test - public void testConcurrentUnsubscribe3000Iterations() throws InterruptedException, BrokenBarrierException, ExecutionException{ + public void testConcurrentUnsubscribe3000Iterations() throws InterruptedException, BrokenBarrierException, ExecutionException { ExecutorService exec = null; try { exec = Executors.newSingleThreadExecutor(); @@ -986,7 +987,9 @@ public Object call() throws Exception { assertEquals("Unsubscribe supposed to be called once", 1, wip.get()); } } finally { - if (exec != null) exec.shutdownNow(); + if (exec != null) { + exec.shutdownNow(); + } } } diff --git a/src/test/java/rx/observers/SafeSubscriberTest.java b/src/test/java/rx/observers/SafeSubscriberTest.java index 7d60a71c9f..3fdd8bbf66 100644 --- a/src/test/java/rx/observers/SafeSubscriberTest.java +++ b/src/test/java/rx/observers/SafeSubscriberTest.java @@ -80,7 +80,7 @@ public void onCompleted() { assertTrue(safe.isUnsubscribed()); } - @Test(expected=OnCompletedFailedException.class) + @Test(expected = OnCompletedFailedException.class) public void testPluginException() { RxJavaPlugins.getInstance().registerErrorHandler(new RxJavaErrorHandler() { @Override @@ -261,7 +261,7 @@ public void call() { try { safe.onCompleted(); Assert.fail(); - } catch(UnsubscribeFailedException e) { + } catch (UnsubscribeFailedException e) { assertEquals(1, calls.get()); assertEquals(0, errors.get()); } @@ -301,7 +301,7 @@ public void call() { try { safe.onCompleted(); Assert.fail(); - } catch(UnsubscribeFailedException e) { + } catch (UnsubscribeFailedException e) { assertEquals(2, calls.get()); assertEquals(0, errors.get()); } diff --git a/src/test/java/rx/observers/SerializedObserverTest.java b/src/test/java/rx/observers/SerializedObserverTest.java index 41d6d2da6d..b53ac9fd5d 100644 --- a/src/test/java/rx/observers/SerializedObserverTest.java +++ b/src/test/java/rx/observers/SerializedObserverTest.java @@ -589,7 +589,7 @@ public int assertEvents(TestConcurrencyObserverEvent expectedEndingEvent) throws private static class TestSingleThreadedObservable implements Observable.OnSubscribe { final String[] values; - private Thread t = null; + private Thread t; public TestSingleThreadedObservable(final String... values) { this.values = values; @@ -637,7 +637,7 @@ public void waitToFinish() { private static class TestMultiThreadedObservable implements Observable.OnSubscribe { final String[] values; - Thread t = null; + Thread t; AtomicInteger threadsRunning = new AtomicInteger(); AtomicInteger maxConcurrentThreads = new AtomicInteger(); ExecutorService threadPool; @@ -726,8 +726,8 @@ public void waitToFinish() { } private static class BusyObserver extends Subscriber { - volatile boolean onCompleted = false; - volatile boolean onError = false; + volatile boolean onCompleted; + volatile boolean onError; AtomicInteger onNextCount = new AtomicInteger(); AtomicInteger threadsRunning = new AtomicInteger(); AtomicInteger maxConcurrentThreads = new AtomicInteger(); diff --git a/src/test/java/rx/plugins/RxJavaPluginsTest.java b/src/test/java/rx/plugins/RxJavaPluginsTest.java index ebcee62325..1c69ff1389 100644 --- a/src/test/java/rx/plugins/RxJavaPluginsTest.java +++ b/src/test/java/rx/plugins/RxJavaPluginsTest.java @@ -72,7 +72,7 @@ public void testErrorHandlerViaProperty() { public static class RxJavaErrorHandlerTestImpl extends RxJavaErrorHandler { private volatile Throwable e; - private volatile int count = 0; + private volatile int count; @Override public void handleError(Throwable e) { diff --git a/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java b/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java index 5e5686b396..a7cec8ab86 100644 --- a/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java +++ b/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java @@ -111,7 +111,7 @@ public void testUnsubscribeRecursiveScheduleFromOutside() throws InterruptedExce public void call() { inner.schedule(new Action0() { - int i = 0; + int i; @Override public void call() { @@ -159,7 +159,7 @@ public void testUnsubscribeRecursiveScheduleFromInside() throws InterruptedExcep public void call() { inner.schedule(new Action0() { - int i = 0; + int i; @Override public void call() { @@ -239,7 +239,7 @@ public void recursionFromOuterActionAndUnsubscribeInside() throws InterruptedExc try { inner.schedule(new Action0() { - int i = 0; + int i; @Override public void call() { @@ -268,7 +268,7 @@ public void testRecursion() throws InterruptedException { try { inner.schedule(new Action0() { - private long i = 0; + private long i; @Override public void call() { diff --git a/src/test/java/rx/schedulers/AbstractSchedulerTests.java b/src/test/java/rx/schedulers/AbstractSchedulerTests.java index c0502a6fe0..5875328d70 100644 --- a/src/test/java/rx/schedulers/AbstractSchedulerTests.java +++ b/src/test/java/rx/schedulers/AbstractSchedulerTests.java @@ -299,7 +299,7 @@ public final void testRecursiveExecutionWithDelayTime() throws InterruptedExcept inner.schedule(new Action0() { - int state = 0; + int state; @Override public void call() { @@ -328,7 +328,7 @@ public void call(final Subscriber observer) { final Scheduler.Worker inner = getScheduler().createWorker(); observer.add(inner); inner.schedule(new Action0() { - int i = 0; + int i; @Override public void call() { @@ -508,7 +508,7 @@ public void periodicTaskCancelsItself() throws Exception { @Override public void call() { executions[0]++; - while (cancel.get() == null); + while (cancel.get() == null) { } cancel.get().unsubscribe(); cdl.countDown(); diff --git a/src/test/java/rx/schedulers/ComputationSchedulerTests.java b/src/test/java/rx/schedulers/ComputationSchedulerTests.java index 0841d815a9..d83a456f56 100644 --- a/src/test/java/rx/schedulers/ComputationSchedulerTests.java +++ b/src/test/java/rx/schedulers/ComputationSchedulerTests.java @@ -52,7 +52,7 @@ public void testThreadSafetyWhenSchedulerIsHoppingBetweenThreads() { inner.schedule(new Action0() { private HashMap statefulMap = map; - int nonThreadSafeCounter = 0; + int nonThreadSafeCounter; @Override public void call() { diff --git a/src/test/java/rx/schedulers/SchedulerTests.java b/src/test/java/rx/schedulers/SchedulerTests.java index c216580284..f750a47d4d 100644 --- a/src/test/java/rx/schedulers/SchedulerTests.java +++ b/src/test/java/rx/schedulers/SchedulerTests.java @@ -65,8 +65,12 @@ public static void testUnhandledErrorIsDeliveredToThreadHandler(Scheduler schedu assertEquals("Should have received exactly 1 exception", 1, handler.count); Throwable cause = handler.caught; while (cause != null) { - if (error.equals(cause)) break; - if (cause == cause.getCause()) break; + if (error.equals(cause)) { + break; + } + if (cause == cause.getCause()) { + break; + } cause = cause.getCause(); } assertEquals("Our error should have been delivered to the handler", error, cause); @@ -105,8 +109,12 @@ public static void testHandledErrorIsNotDeliveredToThreadHandler(Scheduler sched Throwable cause = observer.error; while (cause != null) { - if (error.equals(cause)) break; - if (cause == cause.getCause()) break; + if (error.equals(cause)) { + break; + } + if (cause == cause.getCause()) { + break; + } cause = cause.getCause(); } assertEquals("Our error should have been delivered to the observer", error, cause); @@ -183,8 +191,8 @@ public void call() { private static final class CapturingObserver implements Observer { CountDownLatch completed = new CountDownLatch(1); - int errorCount = 0; - int nextCount = 0; + int errorCount; + int nextCount; Throwable error; @Override diff --git a/src/test/java/rx/schedulers/SchedulerWhenTest.java b/src/test/java/rx/schedulers/SchedulerWhenTest.java index ed0e2f3792..c3b9761e64 100644 --- a/src/test/java/rx/schedulers/SchedulerWhenTest.java +++ b/src/test/java/rx/schedulers/SchedulerWhenTest.java @@ -30,184 +30,184 @@ import rx.observers.TestSubscriber; public class SchedulerWhenTest { - @Test - public void testAsyncMaxConcurrent() { - TestScheduler tSched = new TestScheduler(); - SchedulerWhen sched = maxConcurrentScheduler(tSched); - TestSubscriber tSub = TestSubscriber.create(); + @Test + public void testAsyncMaxConcurrent() { + TestScheduler tSched = new TestScheduler(); + SchedulerWhen sched = maxConcurrentScheduler(tSched); + TestSubscriber tSub = TestSubscriber.create(); - asyncWork(sched).subscribe(tSub); + asyncWork(sched).subscribe(tSub); - tSub.assertValueCount(0); + tSub.assertValueCount(0); - tSched.advanceTimeBy(0, SECONDS); - tSub.assertValueCount(0); + tSched.advanceTimeBy(0, SECONDS); + tSub.assertValueCount(0); - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(2); + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(2); - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(4); + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(4); - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(5); - tSub.assertCompleted(); + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(5); + tSub.assertCompleted(); - sched.unsubscribe(); - } + sched.unsubscribe(); + } + + @Test + public void testAsyncDelaySubscription() { + final TestScheduler tSched = new TestScheduler(); + SchedulerWhen sched = throttleScheduler(tSched); + TestSubscriber tSub = TestSubscriber.create(); + + asyncWork(sched).subscribe(tSub); + + tSub.assertValueCount(0); + + tSched.advanceTimeBy(0, SECONDS); + tSub.assertValueCount(0); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(1); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(1); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(2); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(2); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(3); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(3); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(4); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(4); + + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(5); + tSub.assertCompleted(); + + sched.unsubscribe(); + } + + @Test + public void testSyncMaxConcurrent() { + TestScheduler tSched = new TestScheduler(); + SchedulerWhen sched = maxConcurrentScheduler(tSched); + TestSubscriber tSub = TestSubscriber.create(); + + syncWork(sched).subscribe(tSub); + + tSub.assertValueCount(0); + tSched.advanceTimeBy(0, SECONDS); + + // since all the work is synchronous nothing is blocked and its all done + tSub.assertValueCount(5); + tSub.assertCompleted(); - @Test - public void testAsyncDelaySubscription() { - final TestScheduler tSched = new TestScheduler(); - SchedulerWhen sched = throttleScheduler(tSched); - TestSubscriber tSub = TestSubscriber.create(); + sched.unsubscribe(); + } + + @Test + public void testSyncDelaySubscription() { + final TestScheduler tSched = new TestScheduler(); + SchedulerWhen sched = throttleScheduler(tSched); + TestSubscriber tSub = TestSubscriber.create(); + + syncWork(sched).subscribe(tSub); + + tSub.assertValueCount(0); + + tSched.advanceTimeBy(0, SECONDS); + tSub.assertValueCount(1); - asyncWork(sched).subscribe(tSub); + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(2); - tSub.assertValueCount(0); + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(3); - tSched.advanceTimeBy(0, SECONDS); - tSub.assertValueCount(0); + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(4); - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(1); + tSched.advanceTimeBy(1, SECONDS); + tSub.assertValueCount(5); + tSub.assertCompleted(); - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(1); + sched.unsubscribe(); + } - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(2); + private Observable asyncWork(final Scheduler sched) { + return Observable.range(1, 5).flatMap(new Func1>() { + @Override + public Observable call(Integer t) { + return Observable.timer(1, SECONDS, sched); + } + }); + } - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(2); + private Observable syncWork(final Scheduler sched) { + return Observable.range(1, 5).flatMap(new Func1>() { + @Override + public Observable call(Integer t) { + return Observable.defer(new Func0>() { + @Override + public Observable call() { + return Observable.just(0l); + } + }).subscribeOn(sched); + } + }); + } - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(3); + private SchedulerWhen maxConcurrentScheduler(TestScheduler tSched) { + SchedulerWhen sched = new SchedulerWhen(new Func1>, Completable>() { + @Override + public Completable call(Observable> workerActions) { + Observable workers = workerActions.map(new Func1, Completable>() { + @Override + public Completable call(Observable actions) { + return Completable.concat(actions); + } + }); + return Completable.merge(workers, 2); + } + }, tSched); + return sched; + } - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(3); + private SchedulerWhen throttleScheduler(final TestScheduler tSched) { + SchedulerWhen sched = new SchedulerWhen(new Func1>, Completable>() { + @Override + public Completable call(Observable> workerActions) { + Observable workers = workerActions.map(new Func1, Completable>() { + @Override + public Completable call(Observable actions) { + return Completable.concat(actions); + } + }); + return Completable.concat(workers.map(new Func1() { + @Override + public Completable call(Completable worker) { + return worker.delay(1, SECONDS, tSched); + } + })); + } + }, tSched); + return sched; + } - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(4); - - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(4); - - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(5); - tSub.assertCompleted(); - - sched.unsubscribe(); - } - - @Test - public void testSyncMaxConcurrent() { - TestScheduler tSched = new TestScheduler(); - SchedulerWhen sched = maxConcurrentScheduler(tSched); - TestSubscriber tSub = TestSubscriber.create(); - - syncWork(sched).subscribe(tSub); - - tSub.assertValueCount(0); - tSched.advanceTimeBy(0, SECONDS); - - // since all the work is synchronous nothing is blocked and its all done - tSub.assertValueCount(5); - tSub.assertCompleted(); - - sched.unsubscribe(); - } - - @Test - public void testSyncDelaySubscription() { - final TestScheduler tSched = new TestScheduler(); - SchedulerWhen sched = throttleScheduler(tSched); - TestSubscriber tSub = TestSubscriber.create(); - - syncWork(sched).subscribe(tSub); - - tSub.assertValueCount(0); - - tSched.advanceTimeBy(0, SECONDS); - tSub.assertValueCount(1); - - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(2); - - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(3); - - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(4); - - tSched.advanceTimeBy(1, SECONDS); - tSub.assertValueCount(5); - tSub.assertCompleted(); - - sched.unsubscribe(); - } - - private Observable asyncWork(final Scheduler sched) { - return Observable.range(1, 5).flatMap(new Func1>() { - @Override - public Observable call(Integer t) { - return Observable.timer(1, SECONDS, sched); - } - }); - } - - private Observable syncWork(final Scheduler sched) { - return Observable.range(1, 5).flatMap(new Func1>() { - @Override - public Observable call(Integer t) { - return Observable.defer(new Func0>() { - @Override - public Observable call() { - return Observable.just(0l); - } - }).subscribeOn(sched); - } - }); - } - - private SchedulerWhen maxConcurrentScheduler(TestScheduler tSched) { - SchedulerWhen sched = new SchedulerWhen(new Func1>, Completable>() { - @Override - public Completable call(Observable> workerActions) { - Observable workers = workerActions.map(new Func1, Completable>() { - @Override - public Completable call(Observable actions) { - return Completable.concat(actions); - } - }); - return Completable.merge(workers, 2); - } - }, tSched); - return sched; - } - - private SchedulerWhen throttleScheduler(final TestScheduler tSched) { - SchedulerWhen sched = new SchedulerWhen(new Func1>, Completable>() { - @Override - public Completable call(Observable> workerActions) { - Observable workers = workerActions.map(new Func1, Completable>() { - @Override - public Completable call(Observable actions) { - return Completable.concat(actions); - } - }); - return Completable.concat(workers.map(new Func1() { - @Override - public Completable call(Completable worker) { - return worker.delay(1, SECONDS, tSched); - } - })); - } - }, tSched); - return sched; - } - - @Test(timeout=1000) + @Test(timeout = 1000) public void testRaceConditions() { Scheduler comp = Schedulers.computation(); Scheduler limited = comp.when(new Func1>, Completable>() { diff --git a/src/test/java/rx/schedulers/TrampolineSchedulerTest.java b/src/test/java/rx/schedulers/TrampolineSchedulerTest.java index f191fa9819..61e6b4f3e2 100644 --- a/src/test/java/rx/schedulers/TrampolineSchedulerTest.java +++ b/src/test/java/rx/schedulers/TrampolineSchedulerTest.java @@ -125,7 +125,7 @@ public Subscription call(Long count) { return trampolineWorker.schedule(new Action0() { @Override - public void call() {} + public void call() { } }); } diff --git a/src/test/java/rx/subjects/BufferUntilSubscriberTest.java b/src/test/java/rx/subjects/BufferUntilSubscriberTest.java index d1ad426a96..6d8aebe167 100644 --- a/src/test/java/rx/subjects/BufferUntilSubscriberTest.java +++ b/src/test/java/rx/subjects/BufferUntilSubscriberTest.java @@ -33,8 +33,9 @@ public class BufferUntilSubscriberTest { public void testIssue1677() throws InterruptedException { final AtomicLong counter = new AtomicLong(); final Integer[] numbers = new Integer[5000]; - for (int i = 0; i < numbers.length; i++) + for (int i = 0; i < numbers.length; i++) { numbers[i] = i + 1; + } final int NITERS = 250; final CountDownLatch latch = new CountDownLatch(NITERS); for (int iters = 0; iters < NITERS; iters++) { @@ -72,13 +73,15 @@ public void call(List integers) { } }) .subscribe(); - if (!innerLatch.await(30, TimeUnit.SECONDS)) + if (!innerLatch.await(30, TimeUnit.SECONDS)) { Assert.fail("Failed inner latch wait, iteration " + iters); + } } - if (!latch.await(30, TimeUnit.SECONDS)) + if (!latch.await(30, TimeUnit.SECONDS)) { Assert.fail("Incomplete! Went through " + latch.getCount() + " iterations"); - else + } else { Assert.assertEquals(NITERS, counter.get()); + } } @Test diff --git a/src/test/java/rx/util/AssertObservable.java b/src/test/java/rx/util/AssertObservable.java index 41ddaaad1e..d1a0072a34 100644 --- a/src/test/java/rx/util/AssertObservable.java +++ b/src/test/java/rx/util/AssertObservable.java @@ -102,24 +102,30 @@ public Notification call(Notification expectedNotfication, Notificati if (expectedNotfication.equals(actualNotification)) { StringBuilder message = new StringBuilder(); message.append(expectedNotfication.getKind()); - if (expectedNotfication.hasValue()) + if (expectedNotfication.hasValue()) { message.append(" ").append(expectedNotfication.getValue()); - if (expectedNotfication.hasThrowable()) + } + if (expectedNotfication.hasThrowable()) { message.append(" ").append(expectedNotfication.getThrowable()); + } return Notification.createOnNext("equals " + message.toString()); } else { StringBuilder error = new StringBuilder(); error.append("expected:<").append(expectedNotfication.getKind()); - if (expectedNotfication.hasValue()) + if (expectedNotfication.hasValue()) { error.append(" ").append(expectedNotfication.getValue()); - if (expectedNotfication.hasThrowable()) + } + if (expectedNotfication.hasThrowable()) { error.append(" ").append(expectedNotfication.getThrowable()); + } error.append("> but was:<").append(actualNotification.getKind()); - if (actualNotification.hasValue()) + if (actualNotification.hasValue()) { error.append(" ").append(actualNotification.getValue()); - if (actualNotification.hasThrowable()) + } + if (actualNotification.hasThrowable()) { error.append(" ").append(actualNotification.getThrowable()); + } error.append(">"); return Notification.createOnError(new AssertionError(error.toString())); @@ -136,10 +142,11 @@ public Notification call(Notification a, Notification b) message += "\n\t" + (b.isOnError() ? b.getThrowable().getMessage() : b.getValue()); fail |= b.isOnError(); - if (fail) + if (fail) { return Notification.createOnError(new AssertionError(message)); - else + } else { return Notification.createOnNext(message); + } } }; From fb3d0e81bce9183272913e33dd5e0aa7b1a021ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Karnok?= Date: Mon, 14 Nov 2016 20:14:15 +0100 Subject: [PATCH 09/74] 1.x: fix Completable.concat & merge hanging in async situations --- .../CompletableOnSubscribeConcat.java | 74 ++++++++++--------- .../CompletableOnSubscribeMerge.java | 2 +- .../operators/CompletableConcatTest.java | 45 +++++++++++ .../operators/CompletableMergeTest.java | 45 +++++++++++ 4 files changed, 132 insertions(+), 34 deletions(-) create mode 100644 src/test/java/rx/internal/operators/CompletableConcatTest.java create mode 100644 src/test/java/rx/internal/operators/CompletableMergeTest.java diff --git a/src/main/java/rx/internal/operators/CompletableOnSubscribeConcat.java b/src/main/java/rx/internal/operators/CompletableOnSubscribeConcat.java index 1960a93207..10a7801beb 100644 --- a/src/main/java/rx/internal/operators/CompletableOnSubscribeConcat.java +++ b/src/main/java/rx/internal/operators/CompletableOnSubscribeConcat.java @@ -21,9 +21,9 @@ import rx.*; import rx.Completable.OnSubscribe; import rx.exceptions.MissingBackpressureException; +import rx.internal.subscriptions.SequentialSubscription; import rx.internal.util.unsafe.SpscArrayQueue; import rx.plugins.RxJavaHooks; -import rx.subscriptions.SerialSubscription; public final class CompletableOnSubscribeConcat implements OnSubscribe { final Observable sources; @@ -39,30 +39,29 @@ public CompletableOnSubscribeConcat(Observable sources, i public void call(CompletableSubscriber s) { CompletableConcatSubscriber parent = new CompletableConcatSubscriber(s, prefetch); s.onSubscribe(parent); - sources.subscribe(parent); + sources.unsafeSubscribe(parent); } static final class CompletableConcatSubscriber extends Subscriber { final CompletableSubscriber actual; - final SerialSubscription sr; + final SequentialSubscription sr; final SpscArrayQueue queue; - volatile boolean done; + final ConcatInnerSubscriber inner; final AtomicBoolean once; - final ConcatInnerSubscriber inner; + volatile boolean done; - final AtomicInteger wip; + volatile boolean active; public CompletableConcatSubscriber(CompletableSubscriber actual, int prefetch) { this.actual = actual; this.queue = new SpscArrayQueue(prefetch); - this.sr = new SerialSubscription(); + this.sr = new SequentialSubscription(); this.inner = new ConcatInnerSubscriber(); - this.wip = new AtomicInteger(); this.once = new AtomicBoolean(); add(sr); request(prefetch); @@ -74,9 +73,7 @@ public void onNext(Completable t) { onError(new MissingBackpressureException()); return; } - if (wip.getAndIncrement() == 0) { - next(); - } + drain(); } @Override @@ -94,9 +91,7 @@ public void onCompleted() { return; } done = true; - if (wip.getAndIncrement() == 0) { - next(); - } + drain(); } void innerError(Throwable e) { @@ -105,32 +100,45 @@ void innerError(Throwable e) { } void innerComplete() { - if (wip.decrementAndGet() != 0) { - next(); - } - if (!done) { - request(1); - } + active = false; + drain(); } - void next() { - boolean d = done; - Completable c = queue.poll(); - if (c == null) { - if (d) { - if (once.compareAndSet(false, true)) { - actual.onCompleted(); - } - return; - } - RxJavaHooks.onError(new IllegalStateException("Queue is empty?!")); + void drain() { + ConcatInnerSubscriber inner = this.inner; + if (inner.getAndIncrement() != 0) { return; } - c.unsafeSubscribe(inner); + do { + if (isUnsubscribed()) { + return; + } + if (!active) { + boolean d = done; + Completable c = queue.poll(); + boolean empty = c == null; + + if (d && empty) { + actual.onCompleted(); + return; + } + + if (!empty) { + active = true; + c.subscribe(inner); + + request(1); + } + } + } while (inner.decrementAndGet() != 0); } - final class ConcatInnerSubscriber implements CompletableSubscriber { + final class ConcatInnerSubscriber + extends AtomicInteger + implements CompletableSubscriber { + private static final long serialVersionUID = 7233503139645205620L; + @Override public void onSubscribe(Subscription d) { sr.set(d); diff --git a/src/main/java/rx/internal/operators/CompletableOnSubscribeMerge.java b/src/main/java/rx/internal/operators/CompletableOnSubscribeMerge.java index 19f5aa3857..b60f6c56ed 100644 --- a/src/main/java/rx/internal/operators/CompletableOnSubscribeMerge.java +++ b/src/main/java/rx/internal/operators/CompletableOnSubscribeMerge.java @@ -43,7 +43,7 @@ public CompletableOnSubscribeMerge(Observable source, int public void call(CompletableSubscriber s) { CompletableMergeSubscriber parent = new CompletableMergeSubscriber(s, maxConcurrency, delayErrors); s.onSubscribe(parent); - source.subscribe(parent); + source.unsafeSubscribe(parent); } static final class CompletableMergeSubscriber diff --git a/src/test/java/rx/internal/operators/CompletableConcatTest.java b/src/test/java/rx/internal/operators/CompletableConcatTest.java new file mode 100644 index 0000000000..7ce2529322 --- /dev/null +++ b/src/test/java/rx/internal/operators/CompletableConcatTest.java @@ -0,0 +1,45 @@ +package rx.internal.operators; + +import java.util.concurrent.TimeUnit; + +import org.junit.*; + +import rx.*; +import rx.functions.*; +import rx.schedulers.Schedulers; + +public class CompletableConcatTest { + + @Test + public void asyncObservables() { + + final int[] calls = { 0 }; + + Completable.concat(Observable.range(1, 5).map(new Func1() { + @Override + public Completable call(final Integer v) { + System.out.println("Mapping " + v); + return Completable.fromAction(new Action0() { + @Override + public void call() { + System.out.println("Processing " + (calls[0] + 1)); + calls[0]++; + } + }) + .subscribeOn(Schedulers.io()) + .doOnCompleted(new Action0() { + @Override + public void call() { + System.out.println("Inner complete " + v); + } + }) + .observeOn(Schedulers.computation()); + } + }) + ).test() + .awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS) + .assertResult(); + + Assert.assertEquals(5, calls[0]); + } +} diff --git a/src/test/java/rx/internal/operators/CompletableMergeTest.java b/src/test/java/rx/internal/operators/CompletableMergeTest.java new file mode 100644 index 0000000000..790d51d5f4 --- /dev/null +++ b/src/test/java/rx/internal/operators/CompletableMergeTest.java @@ -0,0 +1,45 @@ +package rx.internal.operators; + +import java.util.concurrent.TimeUnit; + +import org.junit.*; + +import rx.*; +import rx.functions.*; +import rx.schedulers.Schedulers; + +public class CompletableMergeTest { + + @Test + public void asyncObservables() { + + final int[] calls = { 0 }; + + Completable.merge(Observable.range(1, 5).map(new Func1() { + @Override + public Completable call(final Integer v) { + System.out.println("Mapping " + v); + return Completable.fromAction(new Action0() { + @Override + public void call() { + System.out.println("Processing " + (calls[0] + 1)); + calls[0]++; + } + }) + .subscribeOn(Schedulers.io()) + .doOnCompleted(new Action0() { + @Override + public void call() { + System.out.println("Inner complete " + v); + } + }) + .observeOn(Schedulers.computation()); + } + }), 1 + ).test() + .awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS) + .assertResult(); + + Assert.assertEquals(5, calls[0]); + } +} From a825d70701b3a013fc7ab882a10d61a856f4e351 Mon Sep 17 00:00:00 2001 From: akarnokd Date: Tue, 15 Nov 2016 10:22:06 +0100 Subject: [PATCH 10/74] 1.x: add Single.fromEmitter --- src/main/java/rx/Single.java | 40 ++++ src/main/java/rx/SingleEmitter.java | 70 ++++++ .../operators/CompletableFromEmitter.java | 6 +- .../operators/OnSubscribeFromEmitter.java | 41 +--- .../internal/operators/SingleFromEmitter.java | 118 ++++++++++ .../CancellableSubscription.java | 43 ++++ .../operators/SingleFromEmitterTest.java | 221 ++++++++++++++++++ 7 files changed, 497 insertions(+), 42 deletions(-) create mode 100644 src/main/java/rx/SingleEmitter.java create mode 100644 src/main/java/rx/internal/operators/SingleFromEmitter.java create mode 100644 src/main/java/rx/internal/subscriptions/CancellableSubscription.java create mode 100644 src/test/java/rx/internal/operators/SingleFromEmitterTest.java diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index 7b85c4d3a5..782d5c833f 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -573,6 +573,46 @@ public static Single fromCallable(final Callable func) { return create(new SingleFromCallable(func)); } + /** + * Provides an API (in a cold Single) that bridges the Single-reactive world + * with the callback-based world. + *

The {@link SingleEmitter} allows registering a callback for + * cancellation/unsubscription of a resource. + *

+ * Example: + *


+     * Single.fromEmitter(emitter -> {
+     *     Callback listener = new Callback() {
+     *         @Override
+     *         public void onEvent(Event e) {
+     *             emitter.onSuccess(e.getData());
+     *         }
+     *
+     *         @Override
+     *         public void onFailure(Exception e) {
+     *             emitter.onError(e);
+     *         }
+     *     };
+     *
+     *     AutoCloseable c = api.someMethod(listener);
+     *
+     *     emitter.setCancellation(c::close);
+     *
+     * });
+     * 
+ *

All of the SingleEmitter's methods are thread-safe and ensure the + * Single's protocol are held. + * @param the success value type + * @param producer the callback invoked for each incoming SingleSubscriber + * @return the new Single instance + * @since 1.2.3 - experimental (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + */ + @Experimental + public static Single fromEmitter(Action1> producer) { + if (producer == null) { throw new NullPointerException("producer is null"); } + return create(new SingleFromEmitter(producer)); + } + /** * Returns a {@code Single} that emits a specified item. *

diff --git a/src/main/java/rx/SingleEmitter.java b/src/main/java/rx/SingleEmitter.java new file mode 100644 index 0000000000..c4f3d11615 --- /dev/null +++ b/src/main/java/rx/SingleEmitter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016 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; + +import rx.annotations.Experimental; +import rx.functions.Cancellable; + +/** + * Abstraction over a {@link SingleSubscriber} that gets either an onSuccess or onError + * signal and allows registering an cancellation/unsubscription callback. + *

+ * All methods are thread-safe; calling onSuccess or onError twice or one after the other has + * no effect. + * @since 1.2.3 - experimental (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * + * @param the success value type + */ +@Experimental +public interface SingleEmitter { + + /** + * Notifies the SingleSubscriber that the {@link Single} has completed successfully with + * the given value. + *

+ * If the {@link Single} calls this method, it will not thereafter call + * {@link #onError}. + * + * @param t the success value + */ + void onSuccess(T t); + + /** + * Notifies the SingleSubscriber that the {@link Single} has experienced an error condition. + *

+ * If the {@link Single} calls this method, it will not thereafter call + * {@link #onSuccess}. + * + * @param t + * the exception encountered by the Observable + */ + void onError(Throwable t); + + /** + * Sets a Subscription on this emitter; any previous Subscription + * or Cancellation will be unsubscribed/cancelled. + * @param s the subscription, null is allowed + */ + void setSubscription(Subscription s); + + /** + * Sets a Cancellable on this emitter; any previous Subscription + * or Cancellation will be unsubscribed/cancelled. + * @param c the cancellable resource, null is allowed + */ + void setCancellation(Cancellable c); + +} diff --git a/src/main/java/rx/internal/operators/CompletableFromEmitter.java b/src/main/java/rx/internal/operators/CompletableFromEmitter.java index 1b7cea57c2..3be42f7aac 100644 --- a/src/main/java/rx/internal/operators/CompletableFromEmitter.java +++ b/src/main/java/rx/internal/operators/CompletableFromEmitter.java @@ -19,10 +19,8 @@ import rx.*; import rx.exceptions.Exceptions; -import rx.functions.Action1; -import rx.functions.Cancellable; -import rx.internal.operators.OnSubscribeFromEmitter.CancellableSubscription; -import rx.internal.subscriptions.SequentialSubscription; +import rx.functions.*; +import rx.internal.subscriptions.*; import rx.plugins.RxJavaHooks; /** diff --git a/src/main/java/rx/internal/operators/OnSubscribeFromEmitter.java b/src/main/java/rx/internal/operators/OnSubscribeFromEmitter.java index 2cfec566d4..355ae99c1d 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeFromEmitter.java +++ b/src/main/java/rx/internal/operators/OnSubscribeFromEmitter.java @@ -20,9 +20,9 @@ import rx.*; import rx.Observable.OnSubscribe; -import rx.exceptions.*; -import rx.functions.Action1; -import rx.functions.Cancellable; +import rx.exceptions.MissingBackpressureException; +import rx.functions.*; +import rx.internal.subscriptions.CancellableSubscription; import rx.internal.util.RxRingBuffer; import rx.internal.util.atomic.SpscUnboundedAtomicArrayQueue; import rx.internal.util.unsafe.*; @@ -73,41 +73,6 @@ public void call(Subscriber t) { } - /** - * A Subscription that wraps an Cancellable instance. - */ - static final class CancellableSubscription - extends AtomicReference - implements Subscription { - - /** */ - private static final long serialVersionUID = 5718521705281392066L; - - public CancellableSubscription(Cancellable cancellable) { - super(cancellable); - } - - @Override - public boolean isUnsubscribed() { - return get() == null; - } - - @Override - public void unsubscribe() { - if (get() != null) { - Cancellable c = getAndSet(null); - if (c != null) { - try { - c.cancel(); - } catch (Exception ex) { - Exceptions.throwIfFatal(ex); - RxJavaHooks.onError(ex); - } - } - } - } - } - static abstract class BaseEmitter extends AtomicLong implements Emitter, Producer, Subscription { diff --git a/src/main/java/rx/internal/operators/SingleFromEmitter.java b/src/main/java/rx/internal/operators/SingleFromEmitter.java new file mode 100644 index 0000000000..b87c90f054 --- /dev/null +++ b/src/main/java/rx/internal/operators/SingleFromEmitter.java @@ -0,0 +1,118 @@ +/** + * Copyright 2016 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.internal.operators; + +import java.util.concurrent.atomic.AtomicBoolean; + +import rx.*; +import rx.Single.OnSubscribe; +import rx.exceptions.Exceptions; +import rx.functions.*; +import rx.internal.subscriptions.*; +import rx.plugins.RxJavaHooks; + +/** + * Calls an action with a SingleEmitter instance for each individual subscribers that + * generates a terminal signal (eventually). + * + * @param the success value type + */ +public final class SingleFromEmitter implements OnSubscribe { + + final Action1> producer; + + public SingleFromEmitter(Action1> producer) { + this.producer = producer; + } + + @Override + public void call(SingleSubscriber t) { + SingleEmitterImpl parent = new SingleEmitterImpl(t); + t.add(parent); + + try { + producer.call(parent); + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + parent.onError(ex); + } + } + + static final class SingleEmitterImpl + extends AtomicBoolean + implements SingleEmitter, Subscription { + private static final long serialVersionUID = 8082834163465882809L; + + final SingleSubscriber actual; + + final SequentialSubscription resource; + + SingleEmitterImpl(SingleSubscriber actual) { + this.actual = actual; + this.resource = new SequentialSubscription(); + } + + @Override + public void unsubscribe() { + if (compareAndSet(false, true)) { + resource.unsubscribe(); + } + } + + @Override + public boolean isUnsubscribed() { + return get(); + } + + @Override + public void onSuccess(T t) { + if (compareAndSet(false, true)) { + try { + actual.onSuccess(t); + } finally { + resource.unsubscribe(); + } + } + } + + @Override + public void onError(Throwable t) { + if (t == null) { + t = new NullPointerException(); + } + if (compareAndSet(false, true)) { + try { + actual.onError(t); + } finally { + resource.unsubscribe(); + } + } else { + RxJavaHooks.onError(t); + } + } + + @Override + public void setSubscription(Subscription s) { + resource.update(s); + } + + @Override + public void setCancellation(Cancellable c) { + setSubscription(new CancellableSubscription(c)); + } + } +} diff --git a/src/main/java/rx/internal/subscriptions/CancellableSubscription.java b/src/main/java/rx/internal/subscriptions/CancellableSubscription.java new file mode 100644 index 0000000000..24c258b333 --- /dev/null +++ b/src/main/java/rx/internal/subscriptions/CancellableSubscription.java @@ -0,0 +1,43 @@ +package rx.internal.subscriptions; + +import java.util.concurrent.atomic.AtomicReference; + +import rx.Subscription; +import rx.exceptions.Exceptions; +import rx.functions.Cancellable; +import rx.plugins.RxJavaHooks; + +/** + * A Subscription that wraps an Cancellable instance. + */ +public final class CancellableSubscription +extends AtomicReference +implements Subscription { + + /** */ + private static final long serialVersionUID = 5718521705281392066L; + + public CancellableSubscription(Cancellable cancellable) { + super(cancellable); + } + + @Override + public boolean isUnsubscribed() { + return get() == null; + } + + @Override + public void unsubscribe() { + if (get() != null) { + Cancellable c = getAndSet(null); + if (c != null) { + try { + c.cancel(); + } catch (Exception ex) { + Exceptions.throwIfFatal(ex); + RxJavaHooks.onError(ex); + } + } + } + } +} diff --git a/src/test/java/rx/internal/operators/SingleFromEmitterTest.java b/src/test/java/rx/internal/operators/SingleFromEmitterTest.java new file mode 100644 index 0000000000..a9f8dfd5b1 --- /dev/null +++ b/src/test/java/rx/internal/operators/SingleFromEmitterTest.java @@ -0,0 +1,221 @@ +/** + * Copyright 2016 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.internal.operators; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.*; + +import org.junit.*; + +import rx.*; +import rx.exceptions.TestException; +import rx.functions.*; +import rx.observers.AssertableSubscriber; +import rx.plugins.RxJavaHooks; + +public class SingleFromEmitterTest implements Cancellable, Action1 { + + int calls; + + final List errors = Collections.synchronizedList(new ArrayList()); + + @Before + public void before() { + RxJavaHooks.setOnError(this); + } + + @After + public void after() { + RxJavaHooks.reset(); + } + + @Override + public void cancel() throws Exception { + calls++; + } + + @Override + public void call(Throwable t) { + errors.add(t); + } + + @Test + public void normal() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + e.onSuccess(1); + } + }) + .test() + .assertResult(1); + + assertEquals(1, calls); + } + + @Test + public void nullSuccess() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + e.onSuccess(null); + } + }) + .test() + .assertResult((Object)null); + + assertEquals(1, calls); + } + + @Test + public void error() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + e.onError(new TestException()); + } + }) + .test() + .assertFailure(TestException.class); + + assertEquals(1, calls); + } + + @Test + public void nullError() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + e.onError(null); + } + }) + .test() + .assertFailure(NullPointerException.class); + + assertEquals(1, calls); + } + + @Test + public void crash() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + + assertEquals(1, calls); + } + + @Test + public void crash2() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + e.onError(null); + throw new TestException(); + } + }) + .test() + .assertFailure(NullPointerException.class); + + assertEquals(1, calls); + + assertTrue(errors.get(0).toString(), errors.get(0) instanceof TestException); + } + + @Test + public void unsubscribe() { + @SuppressWarnings("unchecked") + final SingleEmitter[] emitter = new SingleEmitter[1]; + + AssertableSubscriber ts = Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + emitter[0] = e; + } + }) + .test(); + + ts.unsubscribe(); + + emitter[0].onSuccess(1); + emitter[0].onError(new TestException()); + + ts.assertNoErrors().assertNotCompleted().assertNoValues(); + + assertTrue(errors.get(0).toString(), errors.get(0) instanceof TestException); + } + + @Test + public void onSuccessThrows() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + e.onSuccess(1); + } + }) + .subscribe(new SingleSubscriber() { + @Override + public void onSuccess(Object value) { + throw new TestException(); + } + @Override + public void onError(Throwable error) { + } + }); + + assertEquals(1, calls); + + assertTrue(errors.get(0).toString(), errors.get(0) instanceof TestException); + } + + @Test + public void onErrorThrows() { + Single.fromEmitter(new Action1>() { + @Override + public void call(SingleEmitter e) { + e.setCancellation(SingleFromEmitterTest.this); + e.onError(new IOException()); + } + }) + .subscribe(new SingleSubscriber() { + @Override + public void onSuccess(Object value) { + } + @Override + public void onError(Throwable error) { + throw new TestException(); + } + }); + + assertEquals(1, calls); + + assertTrue(errors.get(0).toString(), errors.get(0) instanceof TestException); + } +} From 8812756697358511843d73900bed69a125455dc1 Mon Sep 17 00:00:00 2001 From: akarnokd Date: Tue, 15 Nov 2016 10:44:27 +0100 Subject: [PATCH 11/74] 1.x: Single::takeUntil CancellationException message enh. --- .../operators/SingleTakeUntilCompletable.java | 2 +- .../operators/SingleTakeUntilObservable.java | 2 +- .../operators/SingleTakeUntilSingle.java | 2 +- .../operators/SingleTakeUntilTest.java | 61 +++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/test/java/rx/internal/operators/SingleTakeUntilTest.java diff --git a/src/main/java/rx/internal/operators/SingleTakeUntilCompletable.java b/src/main/java/rx/internal/operators/SingleTakeUntilCompletable.java index 28110ade31..17111084e7 100644 --- a/src/main/java/rx/internal/operators/SingleTakeUntilCompletable.java +++ b/src/main/java/rx/internal/operators/SingleTakeUntilCompletable.java @@ -86,7 +86,7 @@ public void onError(Throwable error) { @Override public void onCompleted() { - onError(new CancellationException("Stream was canceled before emitting a terminal event.")); + onError(new CancellationException("Single::takeUntil(Completable) - Stream was canceled before emitting a terminal event.")); } } } diff --git a/src/main/java/rx/internal/operators/SingleTakeUntilObservable.java b/src/main/java/rx/internal/operators/SingleTakeUntilObservable.java index 81764449c4..604fda6f1f 100644 --- a/src/main/java/rx/internal/operators/SingleTakeUntilObservable.java +++ b/src/main/java/rx/internal/operators/SingleTakeUntilObservable.java @@ -96,7 +96,7 @@ public void onError(Throwable error) { @Override public void onCompleted() { - onError(new CancellationException("Stream was canceled before emitting a terminal event.")); + onError(new CancellationException("Single::takeUntil(Observable) - Stream was canceled before emitting a terminal event.")); } } } diff --git a/src/main/java/rx/internal/operators/SingleTakeUntilSingle.java b/src/main/java/rx/internal/operators/SingleTakeUntilSingle.java index 05dfc00efc..24c0439817 100644 --- a/src/main/java/rx/internal/operators/SingleTakeUntilSingle.java +++ b/src/main/java/rx/internal/operators/SingleTakeUntilSingle.java @@ -86,7 +86,7 @@ public void onError(Throwable error) { final class OtherSubscriber extends SingleSubscriber { @Override public void onSuccess(U value) { - onError(new CancellationException("Stream was canceled before emitting a terminal event.")); + onError(new CancellationException("Single::takeUntil(Single) - Stream was canceled before emitting a terminal event.")); } @Override diff --git a/src/test/java/rx/internal/operators/SingleTakeUntilTest.java b/src/test/java/rx/internal/operators/SingleTakeUntilTest.java new file mode 100644 index 0000000000..45a9bb23db --- /dev/null +++ b/src/test/java/rx/internal/operators/SingleTakeUntilTest.java @@ -0,0 +1,61 @@ +/** + * Copyright 2016 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.internal.operators; + +import java.util.concurrent.CancellationException; + +import static org.junit.Assert.*; +import org.junit.Test; + +import rx.*; +import rx.observers.AssertableSubscriber; + +public class SingleTakeUntilTest { + + @Test + public void withSingleMessage() { + AssertableSubscriber ts = Single.just(1).takeUntil(Single.just(2)) + .test() + .assertFailure(CancellationException.class); + + String message = ts.getOnErrorEvents().get(0).getMessage(); + + assertTrue(message, message.startsWith("Single::takeUntil(Single)")); + } + + @Test + public void withCompletableMessage() { + AssertableSubscriber ts = Single.just(1).takeUntil(Completable.complete()) + .test() + .assertFailure(CancellationException.class); + + String message = ts.getOnErrorEvents().get(0).getMessage(); + + assertTrue(message, message.startsWith("Single::takeUntil(Completable)")); + } + + @Test + public void withObservableMessage() { + AssertableSubscriber ts = Single.just(1).takeUntil(Observable.just(1)) + .test() + .assertFailure(CancellationException.class); + + String message = ts.getOnErrorEvents().get(0).getMessage(); + + assertTrue(message, message.startsWith("Single::takeUntil(Observable)")); + } +} From 8fff67d91f4d4740c0b1fa55ba238249242f2bb2 Mon Sep 17 00:00:00 2001 From: akarnokd Date: Wed, 23 Nov 2016 09:42:10 +0100 Subject: [PATCH 12/74] Release 1.2.3 --- CHANGES.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 1741085701..86551b818d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,28 @@ # RxJava Releases # +### Version 1.2.3 - November 23, 2016 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.3%7C)) + +#### Documentation enhancements + +- [Pull 4846](https://github.com/ReactiveX/RxJava/pull/4846): Specify the system parameters configuring the schedulers in the `Schedulers` javadoc. + +#### API enhancements + +- [Pull 4777](https://github.com/ReactiveX/RxJava/pull/4777): add `AssertableSubscriber` to provide method chained version of `TestSubscriber` and support a `test()` method on the base reactive classes. +- [Pull 4851](https://github.com/ReactiveX/RxJava/pull/4851): add `Single.fromEmitter` +- [Pull 4852](https://github.com/ReactiveX/RxJava/pull/4852): `Single.takeUntil` `CancellationException` message enhancements + +#### Performance enhancements + +- [Pull 4846](https://github.com/ReactiveX/RxJava/pull/4846): remove ObjectPool, code style cleanups + +#### Bugfixes + +- [Pull 4826](https://github.com/ReactiveX/RxJava/pull/4826): `Schedule.when()` bug fix +- [Pull 4830](https://github.com/ReactiveX/RxJava/pull/4830): `Completable.doAfterTerminate` to run after `onError` as well. +- [Pull 4841](https://github.com/ReactiveX/RxJava/pull/4841): replace non-serializable value of `OnNextValue` with its `toString`. +- [Pull 4849](https://github.com/ReactiveX/RxJava/pull/4849): fix `Completable.concat` & `merge` hanging in async situations. + ### Version 1.2.2 - November 3, 2016 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.2%7C)) Note that the interface `Cancellable` has been moved to `rx.functions` affecting `CompletableEmitter` and the experimental `Observable.fromEmitter(Action1> emitter, AsyncEmitter.BackpressureMode backpressure)` has been removed. From a606a26cc2fb9f7f313ef8104b342a96c378c054 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Mon, 28 Nov 2016 09:07:53 +0100 Subject: [PATCH 13/74] 1.x: enable TestScheduler with nanosecond periodic scheduling (#4884) --- src/main/java/rx/Scheduler.java | 58 +--------- .../schedulers/SchedulePeriodicHelper.java | 102 ++++++++++++++++++ .../java/rx/schedulers/TestScheduler.java | 15 ++- src/test/java/rx/SchedulerWorkerTest.java | 5 +- .../java/rx/schedulers/TestSchedulerTest.java | 37 ++++--- 5 files changed, 147 insertions(+), 70 deletions(-) create mode 100644 src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java diff --git a/src/main/java/rx/Scheduler.java b/src/main/java/rx/Scheduler.java index bbcd19ae34..b98615ff47 100644 --- a/src/main/java/rx/Scheduler.java +++ b/src/main/java/rx/Scheduler.java @@ -19,8 +19,7 @@ import rx.annotations.Experimental; import rx.functions.*; -import rx.internal.schedulers.SchedulerWhen; -import rx.internal.subscriptions.SequentialSubscription; +import rx.internal.schedulers.*; import rx.schedulers.Schedulers; /** @@ -44,18 +43,6 @@ public abstract class Scheduler { * : Without virtual extension methods even additive changes are breaking and thus severely impede library * maintenance. */ - - /** - * The tolerance for a clock drift in nanoseconds where the periodic scheduler will rebase. - *

- * The associated system parameter, {@code rx.scheduler.drift-tolerance}, expects its value in minutes. - */ - static final long CLOCK_DRIFT_TOLERANCE_NANOS; - static { - CLOCK_DRIFT_TOLERANCE_NANOS = TimeUnit.MINUTES.toNanos( - Long.getLong("rx.scheduler.drift-tolerance", 15)); - } - /** * Retrieves or creates a new {@link Scheduler.Worker} that represents serial execution of actions. *

@@ -121,47 +108,8 @@ public abstract static class Worker implements Subscription { * @return a subscription to be able to prevent or cancel the execution of the action */ public Subscription schedulePeriodically(final Action0 action, long initialDelay, long period, TimeUnit unit) { - final long periodInNanos = unit.toNanos(period); - final long firstNowNanos = TimeUnit.MILLISECONDS.toNanos(now()); - final long firstStartInNanos = firstNowNanos + unit.toNanos(initialDelay); - - final SequentialSubscription first = new SequentialSubscription(); - final SequentialSubscription mas = new SequentialSubscription(first); - - final Action0 recursiveAction = new Action0() { - long count; - long lastNowNanos = firstNowNanos; - long startInNanos = firstStartInNanos; - @Override - public void call() { - action.call(); - - if (!mas.isUnsubscribed()) { - - long nextTick; - - long nowNanos = TimeUnit.MILLISECONDS.toNanos(now()); - // If the clock moved in a direction quite a bit, rebase the repetition period - if (nowNanos + CLOCK_DRIFT_TOLERANCE_NANOS < lastNowNanos - || nowNanos >= lastNowNanos + periodInNanos + CLOCK_DRIFT_TOLERANCE_NANOS) { - nextTick = nowNanos + periodInNanos; - /* - * Shift the start point back by the drift as if the whole thing - * started count periods ago. - */ - startInNanos = nextTick - (periodInNanos * (++count)); - } else { - nextTick = startInNanos + (++count * periodInNanos); - } - lastNowNanos = nowNanos; - - long delay = nextTick - nowNanos; - mas.replace(schedule(this, delay, TimeUnit.NANOSECONDS)); - } - } - }; - first.replace(schedule(recursiveAction, initialDelay, unit)); - return mas; + return SchedulePeriodicHelper.schedulePeriodically(this, action, + initialDelay, period, unit, null); } /** diff --git a/src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java b/src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java new file mode 100644 index 0000000000..4ca7b74941 --- /dev/null +++ b/src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java @@ -0,0 +1,102 @@ +/** + * Copyright 2016 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.internal.schedulers; + +import java.util.concurrent.TimeUnit; + +import rx.Scheduler.Worker; +import rx.Subscription; +import rx.functions.Action0; +import rx.internal.subscriptions.SequentialSubscription; + +/** + * Utility method for scheduling tasks periodically (at a fixed rate) by using Worker.schedule(Action0, long, TimeUnit). + */ +public final class SchedulePeriodicHelper { + + /** Utility class. */ + private SchedulePeriodicHelper() { + throw new IllegalStateException("No instances!"); + } + + /** + * The tolerance for a clock drift in nanoseconds where the periodic scheduler will rebase. + *

+ * The associated system parameter, {@code rx.scheduler.drift-tolerance}, expects its value in minutes. + */ + public static final long CLOCK_DRIFT_TOLERANCE_NANOS; + static { + CLOCK_DRIFT_TOLERANCE_NANOS = TimeUnit.MINUTES.toNanos( + Long.getLong("rx.scheduler.drift-tolerance", 15)); + } + + /** + * Return the current time in nanoseconds. + */ + public interface NowNanoSupplier { + long nowNanos(); + } + + public static Subscription schedulePeriodically( + final Worker worker, + final Action0 action, + long initialDelay, long period, TimeUnit unit, + final NowNanoSupplier nowNanoSupplier) { + final long periodInNanos = unit.toNanos(period); + final long firstNowNanos = nowNanoSupplier != null ? nowNanoSupplier.nowNanos() : TimeUnit.MILLISECONDS.toNanos(worker.now()); + final long firstStartInNanos = firstNowNanos + unit.toNanos(initialDelay); + + final SequentialSubscription first = new SequentialSubscription(); + final SequentialSubscription mas = new SequentialSubscription(first); + + final Action0 recursiveAction = new Action0() { + long count; + long lastNowNanos = firstNowNanos; + long startInNanos = firstStartInNanos; + @Override + public void call() { + action.call(); + + if (!mas.isUnsubscribed()) { + + long nextTick; + + long nowNanos = nowNanoSupplier != null ? nowNanoSupplier.nowNanos() : TimeUnit.MILLISECONDS.toNanos(worker.now()); + // If the clock moved in a direction quite a bit, rebase the repetition period + if (nowNanos + CLOCK_DRIFT_TOLERANCE_NANOS < lastNowNanos + || nowNanos >= lastNowNanos + periodInNanos + CLOCK_DRIFT_TOLERANCE_NANOS) { + nextTick = nowNanos + periodInNanos; + /* + * Shift the start point back by the drift as if the whole thing + * started count periods ago. + */ + startInNanos = nextTick - (periodInNanos * (++count)); + } else { + nextTick = startInNanos + (++count * periodInNanos); + } + lastNowNanos = nowNanos; + + long delay = nextTick - nowNanos; + mas.replace(worker.schedule(this, delay, TimeUnit.NANOSECONDS)); + } + } + }; + first.replace(worker.schedule(recursiveAction, initialDelay, unit)); + return mas; + } + +} diff --git a/src/main/java/rx/schedulers/TestScheduler.java b/src/main/java/rx/schedulers/TestScheduler.java index f540569b19..89717914c9 100644 --- a/src/main/java/rx/schedulers/TestScheduler.java +++ b/src/main/java/rx/schedulers/TestScheduler.java @@ -23,6 +23,8 @@ import rx.Scheduler; import rx.Subscription; import rx.functions.Action0; +import rx.internal.schedulers.SchedulePeriodicHelper; +import rx.internal.schedulers.SchedulePeriodicHelper.NowNanoSupplier; import rx.subscriptions.BooleanSubscription; import rx.subscriptions.Subscriptions; @@ -130,7 +132,7 @@ public Worker createWorker() { return new InnerTestScheduler(); } - final class InnerTestScheduler extends Worker { + final class InnerTestScheduler extends Worker implements NowNanoSupplier { private final BooleanSubscription s = new BooleanSubscription(); @@ -172,10 +174,21 @@ public void call() { }); } + @Override + public Subscription schedulePeriodically(Action0 action, long initialDelay, long period, TimeUnit unit) { + return SchedulePeriodicHelper.schedulePeriodically(this, + action, initialDelay, period, unit, this); + } + @Override public long now() { return TestScheduler.this.now(); } + + @Override + public long nowNanos() { + return TestScheduler.this.time; + } } diff --git a/src/test/java/rx/SchedulerWorkerTest.java b/src/test/java/rx/SchedulerWorkerTest.java index 16d0c65553..159d3d34a7 100644 --- a/src/test/java/rx/SchedulerWorkerTest.java +++ b/src/test/java/rx/SchedulerWorkerTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import rx.functions.Action0; +import rx.internal.schedulers.SchedulePeriodicHelper; import rx.schedulers.Schedulers; public class SchedulerWorkerTest { @@ -85,7 +86,7 @@ public void call() { Thread.sleep(150); - s.drift = -1000 - TimeUnit.NANOSECONDS.toMillis(Scheduler.CLOCK_DRIFT_TOLERANCE_NANOS); + s.drift = -1000 - TimeUnit.NANOSECONDS.toMillis(SchedulePeriodicHelper.CLOCK_DRIFT_TOLERANCE_NANOS); Thread.sleep(400); @@ -127,7 +128,7 @@ public void call() { Thread.sleep(150); - s.drift = 1000 + TimeUnit.NANOSECONDS.toMillis(Scheduler.CLOCK_DRIFT_TOLERANCE_NANOS); + s.drift = 1000 + TimeUnit.NANOSECONDS.toMillis(SchedulePeriodicHelper.CLOCK_DRIFT_TOLERANCE_NANOS); Thread.sleep(400); diff --git a/src/test/java/rx/schedulers/TestSchedulerTest.java b/src/test/java/rx/schedulers/TestSchedulerTest.java index ba95fd1df9..18e3e46913 100644 --- a/src/test/java/rx/schedulers/TestSchedulerTest.java +++ b/src/test/java/rx/schedulers/TestSchedulerTest.java @@ -17,25 +17,18 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; +import org.mockito.*; -import rx.Observable; +import rx.*; import rx.Observable.OnSubscribe; -import rx.Scheduler; -import rx.Subscriber; -import rx.Subscription; -import rx.functions.Action0; -import rx.functions.Func1; +import rx.functions.*; +import rx.observers.TestSubscriber; public class TestSchedulerTest { @@ -222,4 +215,24 @@ public void call() { inner.unsubscribe(); } } + + @Test + public void resolution() { + for (final TimeUnit unit : TimeUnit.values()) { + TestScheduler scheduler = new TestScheduler(); + TestSubscriber testSubscriber = new TestSubscriber(); + + Observable.interval(30, unit, scheduler) + .map(new Func1() { + @Override + public String call(Long v) { + return v + "-" + unit; + } + }) + .subscribe(testSubscriber); + scheduler.advanceTimeTo(60, unit); + + testSubscriber.assertValues("0-" + unit, "1-" + unit); + } + } } From 4c51531b88c481087ff7d264c129818c682fe3c2 Mon Sep 17 00:00:00 2001 From: chanx2 Date: Mon, 28 Nov 2016 20:14:19 +0800 Subject: [PATCH 14/74] Update CHANGES.md (#4892) fix URL typo --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 86551b818d..5ae3df64cb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -273,7 +273,7 @@ This release contains mostly internal cleanups, reinforced Observable-protocol a #### Bugfixes - - [Pull 4231](https://github.com/ReactiveX/RxJava/pull/4213): `Schedulers.io()` workers now wait until a blocking task finishes before becoming available again. + - [Pull 4231](https://github.com/ReactiveX/RxJava/pull/4231): `Schedulers.io()` workers now wait until a blocking task finishes before becoming available again. - [Pull 4244](https://github.com/ReactiveX/RxJava/pull/4244): Fix `all` multiple terminal events. - [Pull 4241](https://github.com/ReactiveX/RxJava/pull/4241): Fix reentrancy bug in `repeatWhen` and `retryWhen` when the resubscription happens. - [Pull 4225](https://github.com/ReactiveX/RxJava/pull/4225): `PublishSubject` now checks for unsubscribed child while dispatching events. From 0b37a7e1c2f2415e86c24474239535dcac009cce Mon Sep 17 00:00:00 2001 From: David Karnok Date: Mon, 28 Nov 2016 15:41:00 +0100 Subject: [PATCH 15/74] 1.x: add Issue and PR "welcome" templates (#4890) --- .github/ISSUE_TEMPLATE.md | 13 +++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 7 +++++++ 2 files changed, 20 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..62ab68a18e --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,13 @@ +Thanks for using RxJava but before you post an issue, please consider the following points: + + - [ ] Please include the library version number, including the minor and patch version, in the issue text. In addition, if you'd include the major version in the title (such as `2.x`) that would be great. + + - [ ] If you think you found a bug, please include a code sample that reproduces the problem. Dumping a stacktrace is usually not enough for us. + + - [ ] RxJava has more than 150 operators, we recommend searching the [javadoc](http://reactivex.io/RxJava/1.x/javadoc/rx/Observable.html) for keywords of what you try to accomplish. + + - [ ] If you have a question/issue about a library/technology built on top of RxJava (such as Retrofit, RxNetty, etc.), please consider asking a question on StackOverflow first (then maybe on their issue list). + + - [ ] Questions like "how do I X with RxJava" are generally better suited for StackOverflow (where it may already have an answer). + + - [ ] Please avoid cross-posting questions on StackOverflow, this issue list, the Gitter room or the mailing list. \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..885315565f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +Thank you for contributing to RxJava. Before pressing the "Create Pull Request" button, please consider the following points: + + - [ ] Please give a description about what and why you are contributing, even if it's trivial. + + - [ ] Please include the issue list number(s) or other PR numbers in the description if you are contributing in response to those. + + - [ ] Please include a reasonable set of unit tests if you contribute new code or change an existing one. If you contribute an operator, (if applicable) please make sure you have tests for working with an `empty`, `just`, `range` of values as well as an `error` source, with and/or without backpressure and see if unsubscription/cancellation propagates correctly. From 57a9c09960933ce231e401d9e10bb615da2a8f79 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 7 Dec 2016 01:53:50 -0600 Subject: [PATCH 16/74] Use t instead of value to allow for IDE naming (#4908) --- src/main/java/rx/SingleSubscriber.java | 4 ++-- src/main/java/rx/observers/SafeSubscriber.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/rx/SingleSubscriber.java b/src/main/java/rx/SingleSubscriber.java index 53e9a70faa..0860dd331f 100644 --- a/src/main/java/rx/SingleSubscriber.java +++ b/src/main/java/rx/SingleSubscriber.java @@ -43,10 +43,10 @@ public abstract class SingleSubscriber implements Subscription { *

* The {@link Single} will not call this method if it calls {@link #onError}. * - * @param value + * @param t * the item emitted by the Single */ - public abstract void onSuccess(T value); + public abstract void onSuccess(T t); /** * Notifies the SingleSubscriber that the {@link Single} has experienced an error condition. diff --git a/src/main/java/rx/observers/SafeSubscriber.java b/src/main/java/rx/observers/SafeSubscriber.java index 717946c032..16027b0d52 100644 --- a/src/main/java/rx/observers/SafeSubscriber.java +++ b/src/main/java/rx/observers/SafeSubscriber.java @@ -124,14 +124,14 @@ public void onError(Throwable e) { * The {@code Observable} will not call this method again after it calls either {@link #onCompleted} or * {@link #onError}. * - * @param args + * @param t * the item emitted by the Observable */ @Override - public void onNext(T args) { + public void onNext(T t) { try { if (!done) { - actual.onNext(args); + actual.onNext(t); } } catch (Throwable e) { // we handle here instead of another method so we don't add stacks to the frame From 7c7c9b919db9f1a32a30fc5bc0648e1f7cd3f912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Puerta?= Date: Fri, 9 Dec 2016 09:03:19 -0800 Subject: [PATCH 17/74] Fix resolveAndroidApiVersion when running under Robolectric (#4912) PlatformDependent.resolveAndroidApiVersion() tries to determine the Android SDK version by reading the android.os.Build$VERSION#SDK_INT field. When running under Robolectric, the class will be found (since Robolectric bundles an original android.jar). However, the method is using the system class loader for loading it (instead of the Robolectric instrumenting class loader), which will not instrument the class to run in the JVM. As a result, static initialization of the class fails with an UnsatisfiedLinkError when calling SystemProperties.get(), which calls native method native_get. I fixed by using the default class loader instead. This would only make a difference in the extremely rare case that the Android application installs a class loader that's not capable of finding Android classes. I tested that this behaves as expected on a device, fixes the issue with Robolectric, and detects it's not Android otherwise (as proven by the unit test). --- .../rx/internal/util/PlatformDependent.java | 21 +------------------ .../internal/util/PlatformDependentTest.java | 9 ++++++++ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/main/java/rx/internal/util/PlatformDependent.java b/src/main/java/rx/internal/util/PlatformDependent.java index 1a48e8067b..2b6d5c6e65 100644 --- a/src/main/java/rx/internal/util/PlatformDependent.java +++ b/src/main/java/rx/internal/util/PlatformDependent.java @@ -15,9 +15,6 @@ */ package rx.internal.util; -import java.security.AccessController; -import java.security.PrivilegedAction; - /** * Allow platform dependent logic such as checks for Android. * @@ -67,7 +64,7 @@ public static int getAndroidApiVersion() { private static int resolveAndroidApiVersion() { try { return (Integer) Class - .forName("android.os.Build$VERSION", true, getSystemClassLoader()) + .forName("android.os.Build$VERSION") .getField("SDK_INT") .get(null); } catch (Exception e) { // NOPMD @@ -76,20 +73,4 @@ private static int resolveAndroidApiVersion() { return ANDROID_API_VERSION_IS_NOT_ANDROID; } } - - /** - * Return the system {@link ClassLoader}. - */ - static ClassLoader getSystemClassLoader() { - if (System.getSecurityManager() == null) { - return ClassLoader.getSystemClassLoader(); - } else { - return AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ClassLoader run() { - return ClassLoader.getSystemClassLoader(); - } - }); - } - } } diff --git a/src/test/java/rx/internal/util/PlatformDependentTest.java b/src/test/java/rx/internal/util/PlatformDependentTest.java index 64f47915b1..b868145a83 100644 --- a/src/test/java/rx/internal/util/PlatformDependentTest.java +++ b/src/test/java/rx/internal/util/PlatformDependentTest.java @@ -19,9 +19,18 @@ import rx.TestUtil; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + public class PlatformDependentTest { @Test public void constructorShouldBePrivate() { TestUtil.checkUtilityClass(PlatformDependent.class); } + + @Test + public void platformShouldNotBeAndroid() { + assertFalse(PlatformDependent.isAndroid()); + assertEquals(0, PlatformDependent.getAndroidApiVersion()); + } } From 4406bcb672b7e8e31830ba313e5bd7ebbaf3063a Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 15 Dec 2016 12:47:31 +0100 Subject: [PATCH 18/74] Release 1.2.4 --- CHANGES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 5ae3df64cb..f0558e3d6f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,13 @@ # RxJava Releases # +### Version 1.2.4 - December 15, 2016 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.4%7C)) + +#### Other + +- [Pull 4912](https://github.com/ReactiveX/RxJava/pull/4912): Fix `resolveAndroidApiVersion` when running under Robolectric +- [Pull 4908](https://github.com/ReactiveX/RxJava/pull/4908): Use `t` instead of value to allow for IDE naming. +- [Pull 4884](https://github.com/ReactiveX/RxJava/pull/4884): enable `TestScheduler` with nanosecond periodic scheduling + ### Version 1.2.3 - November 23, 2016 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.3%7C)) #### Documentation enhancements From 6de5c6fff60684e29e00b43e5f493884e8801393 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Wed, 28 Dec 2016 22:03:44 +0100 Subject: [PATCH 19/74] 1.x: Completable.mergeDelayError check unsafe availability (#4941) --- ...CompletableOnSubscribeMergeDelayErrorIterable.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/rx/internal/operators/CompletableOnSubscribeMergeDelayErrorIterable.java b/src/main/java/rx/internal/operators/CompletableOnSubscribeMergeDelayErrorIterable.java index 20477e64fd..0c8f5bafee 100644 --- a/src/main/java/rx/internal/operators/CompletableOnSubscribeMergeDelayErrorIterable.java +++ b/src/main/java/rx/internal/operators/CompletableOnSubscribeMergeDelayErrorIterable.java @@ -21,7 +21,8 @@ import rx.*; import rx.Completable.OnSubscribe; -import rx.internal.util.unsafe.MpscLinkedQueue; +import rx.internal.util.atomic.MpscLinkedAtomicQueue; +import rx.internal.util.unsafe.*; import rx.subscriptions.CompositeSubscription; public final class CompletableOnSubscribeMergeDelayErrorIterable implements OnSubscribe { @@ -53,7 +54,13 @@ public void call(final CompletableSubscriber s) { final AtomicInteger wip = new AtomicInteger(1); - final Queue queue = new MpscLinkedQueue(); + final Queue queue; + + if (UnsafeAccess.isUnsafeAvailable()) { + queue = new MpscLinkedQueue(); + } else { + queue = new MpscLinkedAtomicQueue(); + } for (;;) { if (set.isUnsubscribed()) { From eaf146a390fab0bf6a80a533229bbf4aa8ebe100 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 30 Dec 2016 16:20:25 +0100 Subject: [PATCH 20/74] 1.x: header and whitespace cleanup (#4949) --- .../schedulers/SchedulePeriodicHelper.java | 4 ++-- .../subscriptions/CancellableSubscription.java | 16 ++++++++++++++++ src/main/java/rx/schedulers/TestScheduler.java | 6 +++--- .../operators/CompletableConcatTest.java | 16 ++++++++++++++++ .../internal/operators/CompletableMergeTest.java | 16 ++++++++++++++++ .../java/rx/schedulers/TestSchedulerTest.java | 2 +- 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java b/src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java index 4ca7b74941..e11e072c0a 100644 --- a/src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java +++ b/src/main/java/rx/internal/schedulers/SchedulePeriodicHelper.java @@ -45,7 +45,7 @@ private SchedulePeriodicHelper() { } /** - * Return the current time in nanoseconds. + * Return the current time in nanoseconds. */ public interface NowNanoSupplier { long nowNanos(); @@ -53,7 +53,7 @@ public interface NowNanoSupplier { public static Subscription schedulePeriodically( final Worker worker, - final Action0 action, + final Action0 action, long initialDelay, long period, TimeUnit unit, final NowNanoSupplier nowNanoSupplier) { final long periodInNanos = unit.toNanos(period); diff --git a/src/main/java/rx/internal/subscriptions/CancellableSubscription.java b/src/main/java/rx/internal/subscriptions/CancellableSubscription.java index 24c258b333..dcfd1bd075 100644 --- a/src/main/java/rx/internal/subscriptions/CancellableSubscription.java +++ b/src/main/java/rx/internal/subscriptions/CancellableSubscription.java @@ -1,3 +1,19 @@ +/** + * Copyright 2016 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.internal.subscriptions; import java.util.concurrent.atomic.AtomicReference; diff --git a/src/main/java/rx/schedulers/TestScheduler.java b/src/main/java/rx/schedulers/TestScheduler.java index 89717914c9..0106cdbc67 100644 --- a/src/main/java/rx/schedulers/TestScheduler.java +++ b/src/main/java/rx/schedulers/TestScheduler.java @@ -176,15 +176,15 @@ public void call() { @Override public Subscription schedulePeriodically(Action0 action, long initialDelay, long period, TimeUnit unit) { - return SchedulePeriodicHelper.schedulePeriodically(this, + return SchedulePeriodicHelper.schedulePeriodically(this, action, initialDelay, period, unit, this); } - + @Override public long now() { return TestScheduler.this.now(); } - + @Override public long nowNanos() { return TestScheduler.this.time; diff --git a/src/test/java/rx/internal/operators/CompletableConcatTest.java b/src/test/java/rx/internal/operators/CompletableConcatTest.java index 7ce2529322..d05b11fc45 100644 --- a/src/test/java/rx/internal/operators/CompletableConcatTest.java +++ b/src/test/java/rx/internal/operators/CompletableConcatTest.java @@ -1,3 +1,19 @@ +/** + * Copyright 2016 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.internal.operators; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/rx/internal/operators/CompletableMergeTest.java b/src/test/java/rx/internal/operators/CompletableMergeTest.java index 790d51d5f4..a16518ab36 100644 --- a/src/test/java/rx/internal/operators/CompletableMergeTest.java +++ b/src/test/java/rx/internal/operators/CompletableMergeTest.java @@ -1,3 +1,19 @@ +/** + * Copyright 2016 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.internal.operators; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/rx/schedulers/TestSchedulerTest.java b/src/test/java/rx/schedulers/TestSchedulerTest.java index 18e3e46913..6c7b76e28e 100644 --- a/src/test/java/rx/schedulers/TestSchedulerTest.java +++ b/src/test/java/rx/schedulers/TestSchedulerTest.java @@ -215,7 +215,7 @@ public void call() { inner.unsubscribe(); } } - + @Test public void resolution() { for (final TimeUnit unit : TimeUnit.values()) { From b9c7f0ba94de070c9b0823e0c2b190ad09f3c5ac Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 6 Jan 2017 12:52:32 +0100 Subject: [PATCH 21/74] 1.x: add missing marbles, fix image sizes (#4963) --- src/main/java/rx/Observable.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 434cbd22e8..cdc03e518e 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -111,7 +111,7 @@ public static Observable create(OnSubscribe f) { * {@link Observable#create(AsyncOnSubscribe) asynchronous overload}. * *

- * + * *

* See Rx Design Guidelines (PDF) for detailed * information. @@ -153,7 +153,7 @@ public static Observable create(SyncOnSubscribe syncOnSubscribe) * with the {@link Observable#create(SyncOnSubscribe) synchronous overload}. * *

- * + * *

* See Rx Design Guidelines (PDF) for detailed * information. @@ -323,7 +323,7 @@ public Single toSingle() { * {@code ignoreAllElements()}) and calls onCompleted when this source observable calls * onCompleted. Error terminal events are propagated. *

- * *

@@ -5390,6 +5390,8 @@ public final Observable defaultIfEmpty(final T defaultValue) { * Returns an Observable that emits the items emitted by the source Observable or the items of an alternate * Observable if the source Observable is empty. *

+ *

+ * *

*
Backpressure:
*
If the source {@code Observable} is empty, the alternate {@code Observable} is expected to honor backpressure. From 371674746dc4136bf74515962edf52e21ca7d420 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 6 Jan 2017 12:52:56 +0100 Subject: [PATCH 22/74] Release 1.2.5 --- CHANGES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f0558e3d6f..9ec1cae969 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,15 @@ # RxJava Releases # +### Version 1.2.5 - January 6, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.5%7C)) + +#### Documentation + +- [Pull 4963](https://github.com/ReactiveX/RxJava/pull/4963): Add missing marbles, fix image sizes + +#### Bugfixes + +- [Pull 4941](https://github.com/ReactiveX/RxJava/pull/4941): Fix `Completable.mergeDelayError` to check unsafe availability + ### Version 1.2.4 - December 15, 2016 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.4%7C)) #### Other From 9f025638a2fb8e2579a1af5490ef2f608f81414d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brais=20Gab=C3=ADn?= Date: Tue, 17 Jan 2017 13:35:54 +0100 Subject: [PATCH 23/74] Add which are the other stardard methods of create (#5000) --- src/main/java/rx/Observable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index cdc03e518e..b00fea5bea 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -63,7 +63,7 @@ protected Observable(OnSubscribe f) { /** * This method requires advanced knowledge about building operators and data sources; please consider - * other standard methods first; + * other standard methods first, such as {@link Observable#fromEmitter(Action1, Emitter.BackpressureMode)}; * Returns an Observable that will execute the specified function when a {@link Subscriber} subscribes to * it. *

From 56d94b2d6dfbb54fb6c1c0d8ab0e04659ff05f0b Mon Sep 17 00:00:00 2001 From: David Karnok Date: Tue, 24 Jan 2017 12:32:01 +0100 Subject: [PATCH 24/74] 1.x: update sample(time) diagram to indicate emission of last (#5007) --- src/main/java/rx/Observable.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index b00fea5bea..67e4d6149e 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -9100,7 +9100,7 @@ public final Observable retryWhen(final Func1 - * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
@@ -9126,7 +9126,7 @@ public final Observable sample(long period, TimeUnit unit) { * Returns an Observable that emits the most recently emitted item (if any) emitted by the source Observable * within periodic time intervals, where the intervals are defined on a particular Scheduler. *

- * + * *

*
Backpressure:
*
This operator does not support backpressure as it uses time to control data flow.
From 748b56dfd0a14c41890f891e53d02c5dc87d5e8b Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sat, 28 Jan 2017 19:17:30 +0100 Subject: [PATCH 25/74] 1.x: fix groupBy consuming the upstream in an unbounded manner (#5030) --- .../internal/operators/OperatorGroupBy.java | 11 ++++--- .../operators/OperatorGroupByTest.java | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/main/java/rx/internal/operators/OperatorGroupBy.java b/src/main/java/rx/internal/operators/OperatorGroupBy.java index af2fd4347a..8892f0d4d0 100644 --- a/src/main/java/rx/internal/operators/OperatorGroupBy.java +++ b/src/main/java/rx/internal/operators/OperatorGroupBy.java @@ -202,7 +202,7 @@ public void onNext(T t) { return; } - boolean notNew = true; + boolean newGroup = false; Object mapKey = key != null ? key : NULL_KEY; GroupedUnicast group = groups.get(mapKey); if (group == null) { @@ -214,9 +214,7 @@ public void onNext(T t) { groupCount.getAndIncrement(); - notNew = false; - q.offer(group); - drain(); + newGroup = true; } else { return; } @@ -243,8 +241,9 @@ public void onNext(T t) { } } - if (notNew) { - s.request(1); + if (newGroup) { + q.offer(group); + drain(); } } diff --git a/src/test/java/rx/internal/operators/OperatorGroupByTest.java b/src/test/java/rx/internal/operators/OperatorGroupByTest.java index 2d90e6f29a..1cad5330c3 100644 --- a/src/test/java/rx/internal/operators/OperatorGroupByTest.java +++ b/src/test/java/rx/internal/operators/OperatorGroupByTest.java @@ -2017,4 +2017,34 @@ public Map call(Action1 t) { throw exception; }}; } + + @Test + public void outerConsumedInABoundedManner() { + final int[] counter = { 0 }; + + Observable.range(1, 10000) + .doOnRequest(new Action1() { + @Override + public void call(Long v) { + counter[0] += v; + } + }) + .groupBy(new Func1() { + @Override + public Integer call(Integer v) { + return 1; + } + }) + .flatMap(new Func1, Observable>() { + @Override + public Observable call(GroupedObservable v) { + return v; + } + }) + .test(0); + + int c = counter[0]; + assertTrue("" + c, c > 0); + assertTrue("" + c, c < 10000); + } } From 0901ffb30d41f045b995f1f3453219b142f20e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brais=20Gab=C3=ADn?= Date: Thu, 2 Feb 2017 19:45:07 +0100 Subject: [PATCH 26/74] Improve the BehaviorSubject Java doc (#5048) 1.x: Improve the BehaviorSubject Java doc --- src/main/java/rx/subjects/BehaviorSubject.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/rx/subjects/BehaviorSubject.java b/src/main/java/rx/subjects/BehaviorSubject.java index 551f7f6c23..8a45cf1df9 100644 --- a/src/main/java/rx/subjects/BehaviorSubject.java +++ b/src/main/java/rx/subjects/BehaviorSubject.java @@ -35,14 +35,14 @@ *

*

 {@code
 
-  // observer will receive all events.
+  // observer will receive all 4 events (including "default").
   BehaviorSubject subject = BehaviorSubject.create("default");
   subject.subscribe(observer);
   subject.onNext("one");
   subject.onNext("two");
   subject.onNext("three");
 
-  // observer will receive the "one", "two" and "three" events, but not "zero"
+  // observer will receive the "one", "two" and "three" events, but not "default" and "zero"
   BehaviorSubject subject = BehaviorSubject.create("default");
   subject.onNext("zero");
   subject.onNext("one");

From a37e292cfeb6c46559c397d730966d402b106fe5 Mon Sep 17 00:00:00 2001
From: David Karnok 
Date: Fri, 3 Feb 2017 09:18:13 +0100
Subject: [PATCH 27/74] Release 1.2.6

---
 CHANGES.md | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/CHANGES.md b/CHANGES.md
index 9ec1cae969..c20f538c36 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,17 @@
 # RxJava Releases #
 
+### Version 1.2.6 - February 3, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.6%7C))
+
+#### Documentation
+
+- [Pull 5000](https://github.com/ReactiveX/RxJava/pull/5000): Add which are the other stardard methods of create
+- [Pull 5007](https://github.com/ReactiveX/RxJava/pull/5007): update `sample(time)` diagram to indicate emission of last
+- [Pull 5048](https://github.com/ReactiveX/RxJava/pull/5048): Improve the javadoc of `BehaviorSubject`
+
+#### Bugfixes
+
+- [Pull 5030](https://github.com/ReactiveX/RxJava/pull/5030): fix `groupBy` consuming the upstream in an unbounded manner
+
 ### Version 1.2.5 - January 6, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.5%7C))
 
 #### Documentation

From 47e6c676c5a642c14053eafb03d861a9bf8c87be Mon Sep 17 00:00:00 2001
From: David Karnok 
Date: Fri, 10 Feb 2017 09:38:13 +0100
Subject: [PATCH 28/74] 1.x: deprecate create(), add alternatives (#5086)

---
 src/main/java/rx/Completable.java             |   2 +-
 src/main/java/rx/Observable.java              | 212 ++++++++++++------
 src/main/java/rx/Single.java                  |   2 +-
 .../operators/EmptyObservableHolder.java      |   2 +-
 .../operators/NeverObservableHolder.java      |   2 +-
 ...romEmitter.java => OnSubscribeCreate.java} |   6 +-
 .../operators/OnSubscribeFlattenIterable.java |   4 +-
 .../operators/OnSubscribeGroupJoin.java       |   2 +-
 .../internal/operators/OnSubscribeRedo.java   |  12 +-
 .../internal/operators/OperatorPublish.java   |   4 +-
 .../rx/internal/operators/OperatorReplay.java |   2 +-
 .../util/ScalarSynchronousObservable.java     |   4 +-
 .../java/rx/observables/AsyncOnSubscribe.java |   2 +-
 .../rx/observables/ConnectableObservable.java |   4 +-
 .../java/rx/observables/SyncOnSubscribe.java  |   2 +-
 .../RxJavaObservableExecutionHook.java        |   2 +-
 src/perf/java/rx/OneItemPerf.java             |   2 +-
 .../rx/jmh/InputWithIncrementingInteger.java  |   2 +-
 .../java/rx/operators/FromComparison.java     |   4 +-
 .../java/rx/operators/OperatorRangePerf.java  |   4 +-
 .../rx/operators/OperatorSerializePerf.java   |   6 +-
 .../rx/operators/OperatorTakeLastOnePerf.java |   2 +-
 src/test/java/rx/BackpressureTests.java       |   4 +-
 src/test/java/rx/CompletableTest.java         |   2 +-
 src/test/java/rx/ConcatTests.java             |   2 +-
 src/test/java/rx/EventStream.java             |   2 +-
 src/test/java/rx/MergeTests.java              |   2 +-
 src/test/java/rx/ObservableTests.java         |  26 +--
 src/test/java/rx/SubscriberTest.java          |   8 +-
 .../java/rx/exceptions/ExceptionsTest.java    |   8 +-
 .../operators/BlockingOperatorNextTest.java   |   2 +-
 .../BlockingOperatorToFutureTest.java         |   6 +-
 .../BlockingOperatorToIteratorTest.java       |   4 +-
 .../operators/CachedObservableTest.java       |   4 +-
 .../operators/OnSubscribeAmbTest.java         |  12 +-
 .../operators/OnSubscribeCollectTest.java     |   6 +-
 ...erTest.java => OnSubscribeCreateTest.java} |  88 ++++----
 .../operators/OnSubscribeDetachTest.java      |   2 +-
 .../operators/OnSubscribeDoOnEachTest.java    |   8 +-
 .../operators/OnSubscribeFromArrayTest.java   |   2 +-
 .../OnSubscribeFromIterableTest.java          |   6 +-
 .../operators/OnSubscribeMapTest.java         |   2 +-
 .../operators/OnSubscribeReduceTest.java      |   6 +-
 .../operators/OnSubscribeRefCountTest.java    |   4 +-
 .../operators/OnSubscribeToMapTest.java       |   6 +-
 .../operators/OnSubscribeToMultimapTest.java  |   6 +-
 .../operators/OnSubscribeUsingTest.java       |   2 +-
 .../internal/operators/OperatorAllTest.java   |   6 +-
 .../internal/operators/OperatorAnyTest.java   |   6 +-
 .../operators/OperatorBufferTest.java         |  36 +--
 .../operators/OperatorConcatTest.java         |  36 +--
 .../operators/OperatorDebounceTest.java       |   6 +-
 .../operators/OperatorDoOnRequestTest.java    |   2 +-
 .../operators/OperatorDoOnSubscribeTest.java  |   2 +-
 .../operators/OperatorGroupByTest.java        |  18 +-
 .../operators/OperatorMaterializeTest.java    |   6 +-
 .../OperatorMergeDelayErrorTest.java          |  66 +++---
 .../OperatorMergeMaxConcurrentTest.java       |   2 +-
 .../internal/operators/OperatorMergeTest.java |  44 ++--
 .../operators/OperatorObserveOnTest.java      |   2 +-
 .../OperatorOnBackpressureBufferTest.java     |   2 +-
 .../OperatorOnBackpressureDropTest.java       |  12 +-
 ...ratorOnErrorResumeNextViaFunctionTest.java |   6 +-
 ...torOnErrorResumeNextViaObservableTest.java |   8 +-
 .../operators/OperatorOnErrorReturnTest.java  |   4 +-
 ...nExceptionResumeNextViaObservableTest.java |  10 +-
 .../operators/OperatorPublishTest.java        |   4 +-
 .../operators/OperatorRepeatTest.java         |   4 +-
 .../operators/OperatorReplayTest.java         |   4 +-
 .../internal/operators/OperatorRetryTest.java |  40 ++--
 .../OperatorRetryWithPredicateTest.java       |  12 +-
 .../operators/OperatorSampleTest.java         |  12 +-
 .../internal/operators/OperatorScanTest.java  |   4 +-
 .../operators/OperatorSerializeTest.java      |   8 +-
 .../operators/OperatorSubscribeOnTest.java    |   8 +-
 .../operators/OperatorSwitchIfEmptyTest.java  |   8 +-
 .../operators/OperatorSwitchTest.java         |  54 ++---
 .../internal/operators/OperatorTakeTest.java  |  14 +-
 .../operators/OperatorTakeUntilTest.java      |  10 +-
 .../operators/OperatorTakeWhileTest.java      |   6 +-
 .../operators/OperatorThrottleFirstTest.java  |   4 +-
 .../operators/OperatorTimeoutTests.java       |   8 +-
 .../OperatorTimeoutWithSelectorTest.java      |   2 +-
 .../operators/OperatorUnsubscribeOnTest.java  |   4 +-
 .../operators/OperatorWindowWithSizeTest.java |   2 +-
 ...ratorWindowWithStartEndObservableTest.java |  10 +-
 .../operators/OperatorWindowWithTimeTest.java |   4 +-
 .../internal/operators/OperatorZipTest.java   |   8 +-
 .../operators/SafeSubscriberTest.java         |   8 +-
 .../rx/internal/producers/ProducersTest.java  |   2 +-
 .../rx/observables/AsyncOnSubscribeTest.java  |  28 +--
 .../observables/BlockingObservableTest.java   |   6 +-
 .../rx/observables/SyncOnSubscribeTest.java   |  46 ++--
 .../rx/observers/SerializedObserverTest.java  |  10 +-
 .../AbstractSchedulerConcurrencyTests.java    |   2 +-
 .../rx/schedulers/AbstractSchedulerTests.java |   6 +-
 .../java/rx/schedulers/TestSchedulerTest.java |   2 +-
 .../ReplaySubjectBoundedConcurrencyTest.java  |   2 +-
 .../ReplaySubjectConcurrencyTest.java         |   4 +-
 99 files changed, 595 insertions(+), 529 deletions(-)
 rename src/main/java/rx/internal/operators/{OnSubscribeFromEmitter.java => OnSubscribeCreate.java} (97%)
 rename src/test/java/rx/internal/operators/{OnSubscribeFromEmitterTest.java => OnSubscribeCreateTest.java} (80%)

diff --git a/src/main/java/rx/Completable.java b/src/main/java/rx/Completable.java
index e9b78c569f..536509b39a 100644
--- a/src/main/java/rx/Completable.java
+++ b/src/main/java/rx/Completable.java
@@ -2249,7 +2249,7 @@ public final  R to(Func1 converter) {
      * @return the new Observable created
      */
     public final  Observable toObservable() {
-        return Observable.create(new Observable.OnSubscribe() {
+        return Observable.unsafeCreate(new Observable.OnSubscribe() {
             @Override
             public void call(Subscriber s) {
                 unsafeSubscribe(s);
diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java
index 67e4d6149e..89e1aea07c 100644
--- a/src/main/java/rx/Observable.java
+++ b/src/main/java/rx/Observable.java
@@ -51,7 +51,7 @@ public class Observable {
     /**
      * Creates an Observable with a Function to execute when it is subscribed to.
      * 

- * Note: Use {@link #create(OnSubscribe)} to create an Observable, instead of this constructor, + * Note: Use {@link #unsafeCreate(OnSubscribe)} to create an Observable, instead of this constructor, * unless you specifically have a need for inheritance. * * @param f @@ -62,10 +62,72 @@ protected Observable(OnSubscribe f) { } /** - * This method requires advanced knowledge about building operators and data sources; please consider - * other standard methods first, such as {@link Observable#fromEmitter(Action1, Emitter.BackpressureMode)}; - * Returns an Observable that will execute the specified function when a {@link Subscriber} subscribes to - * it. + * Constructs an Observable in an unsafe manner, that is, unsubscription and backpressure handling + * is the responsibility of the OnSubscribe implementation. + * @param the value type emitted + * @param f the callback to execute for each individual Subscriber that subscribes to the + * returned Observable + * @return the new Observable instance + * @deprecated 1.2.7 - inherently unsafe, use the other create() methods for basic cases or + * see {@link #unsafeCreate(OnSubscribe)} for advanced cases (such as custom operators) + * @see #create(SyncOnSubscribe) + * @see #create(AsyncOnSubscribe) + * @see #create(Action1, rx.Emitter.BackpressureMode) + */ + @Deprecated + public static Observable create(OnSubscribe f) { + return new Observable(RxJavaHooks.onCreate(f)); + } + + /** + * Provides an API (via a cold Observable) that bridges the reactive world with the callback-style, + * generally non-backpressured world. + *

+ * Example: + *


+     * Observable.<Event>create(emitter -> {
+     *     Callback listener = new Callback() {
+     *         @Override
+     *         public void onEvent(Event e) {
+     *             emitter.onNext(e);
+     *             if (e.isLast()) {
+     *                 emitter.onCompleted();
+     *             }
+     *         }
+     *
+     *         @Override
+     *         public void onFailure(Exception e) {
+     *             emitter.onError(e);
+     *         }
+     *     };
+     *
+     *     AutoCloseable c = api.someMethod(listener);
+     *
+     *     emitter.setCancellation(c::close);
+     *
+     * }, BackpressureMode.BUFFER);
+     * 
+ *

+ * You should call the Emitter's onNext, onError and onCompleted methods in a serialized fashion. The + * rest of its methods are thread-safe. + * + * @param the element type + * @param emitter the emitter that is called when a Subscriber subscribes to the returned {@code Observable} + * @param backpressure the backpressure mode to apply if the downstream Subscriber doesn't request (fast) enough + * @return the new Observable instance + * @see Emitter + * @see Emitter.BackpressureMode + * @see rx.functions.Cancellable + * @since 1.2.7 - experimental + */ + @Experimental + public static Observable create(Action1> emitter, Emitter.BackpressureMode backpressure) { + return unsafeCreate(new OnSubscribeCreate(emitter, backpressure)); + } + + /** + * Returns an Observable that executes the given OnSubscribe action for each individual Subscriber + * that subscribes; unsubscription and backpressure must be implemented manually. *

* *

@@ -84,7 +146,7 @@ protected Observable(OnSubscribe f) { * document the fact that the consumer of the returned {@code Observable} has to apply one of * the {@code onBackpressureXXX} operators. *

Scheduler:
- *
{@code create} does not operate by default on a particular {@link Scheduler}.
+ *
{@code unsafeCreate} does not operate by default on a particular {@link Scheduler}.
* * * @param @@ -95,8 +157,10 @@ protected Observable(OnSubscribe f) { * @return an Observable that, when a {@link Subscriber} subscribes to it, will execute the specified * function * @see ReactiveX operators documentation: Create + * @since 1.2.7 - experimental */ - public static Observable create(OnSubscribe f) { + @Experimental + public static Observable unsafeCreate(OnSubscribe f) { return new Observable(RxJavaHooks.onCreate(f)); } @@ -140,7 +204,7 @@ public static Observable create(OnSubscribe f) { * @since 1.2 */ public static Observable create(SyncOnSubscribe syncOnSubscribe) { - return create((OnSubscribe)syncOnSubscribe); + return unsafeCreate(syncOnSubscribe); } /** @@ -183,7 +247,7 @@ public static Observable create(SyncOnSubscribe syncOnSubscribe) */ @Experimental public static Observable create(AsyncOnSubscribe asyncOnSubscribe) { - return create((OnSubscribe)asyncOnSubscribe); + return unsafeCreate(asyncOnSubscribe); } /** @@ -234,7 +298,7 @@ public interface Operator extends Func1, Subscriber< * @see RxJava wiki: Implementing Your Own Operators */ public final Observable lift(final Operator operator) { - return create(new OnSubscribeLift(onSubscribe, operator)); + return unsafeCreate(new OnSubscribeLift(onSubscribe, operator)); } /** @@ -373,7 +437,7 @@ public Completable toCompletable() { * @see ReactiveX operators documentation: Amb */ public static Observable amb(Iterable> sources) { - return create(OnSubscribeAmb.amb(sources)); + return unsafeCreate(OnSubscribeAmb.amb(sources)); } /** @@ -399,7 +463,7 @@ public static Observable amb(Iterable> * @see ReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2) { - return create(OnSubscribeAmb.amb(o1, o2)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2)); } /** @@ -427,7 +491,7 @@ public static Observable amb(Observable o1, ObservableReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2, Observable o3) { - return create(OnSubscribeAmb.amb(o1, o2, o3)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2, o3)); } /** @@ -457,7 +521,7 @@ public static Observable amb(Observable o1, ObservableReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2, Observable o3, Observable o4) { - return create(OnSubscribeAmb.amb(o1, o2, o3, o4)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2, o3, o4)); } /** @@ -489,7 +553,7 @@ public static Observable amb(Observable o1, ObservableReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2, Observable o3, Observable o4, Observable o5) { - return create(OnSubscribeAmb.amb(o1, o2, o3, o4, o5)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2, o3, o4, o5)); } /** @@ -523,7 +587,7 @@ public static Observable amb(Observable o1, ObservableReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2, Observable o3, Observable o4, Observable o5, Observable o6) { - return create(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6)); } /** @@ -559,7 +623,7 @@ public static Observable amb(Observable o1, ObservableReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2, Observable o3, Observable o4, Observable o5, Observable o6, Observable o7) { - return create(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6, o7)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6, o7)); } /** @@ -597,7 +661,7 @@ public static Observable amb(Observable o1, ObservableReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2, Observable o3, Observable o4, Observable o5, Observable o6, Observable o7, Observable o8) { - return create(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6, o7, o8)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6, o7, o8)); } /** @@ -637,7 +701,7 @@ public static Observable amb(Observable o1, ObservableReactiveX operators documentation: Amb */ public static Observable amb(Observable o1, Observable o2, Observable o3, Observable o4, Observable o5, Observable o6, Observable o7, Observable o8, Observable o9) { - return create(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6, o7, o8, o9)); + return unsafeCreate(OnSubscribeAmb.amb(o1, o2, o3, o4, o5, o6, o7, o8, o9)); } /** @@ -1020,7 +1084,7 @@ public static Observable combineLates * @see ReactiveX operators documentation: CombineLatest */ public static Observable combineLatest(List> sources, FuncN combineFunction) { - return create(new OnSubscribeCombineLatest(sources, combineFunction)); + return unsafeCreate(new OnSubscribeCombineLatest(sources, combineFunction)); } /** @@ -1049,7 +1113,7 @@ public static Observable combineLatest(ListReactiveX operators documentation: CombineLatest */ public static Observable combineLatest(Iterable> sources, FuncN combineFunction) { - return create(new OnSubscribeCombineLatest(sources, combineFunction)); + return unsafeCreate(new OnSubscribeCombineLatest(sources, combineFunction)); } /** @@ -1080,7 +1144,7 @@ public static Observable combineLatest(IterableReactiveX operators documentation: CombineLatest */ public static Observable combineLatestDelayError(Iterable> sources, FuncN combineFunction) { - return create(new OnSubscribeCombineLatest(null, sources, combineFunction, RxRingBuffer.SIZE, true)); + return unsafeCreate(new OnSubscribeCombineLatest(null, sources, combineFunction, RxRingBuffer.SIZE, true)); } /** @@ -1762,7 +1826,7 @@ public static Observable concatDelayError(Observable t1, Obs * @see ReactiveX operators documentation: Defer */ public static Observable defer(Func0> observableFactory) { - return create(new OnSubscribeDefer(observableFactory)); + return unsafeCreate(new OnSubscribeDefer(observableFactory)); } /** @@ -1808,7 +1872,7 @@ public static Observable empty() { * @see ReactiveX operators documentation: Throw */ public static Observable error(Throwable exception) { - return create(new OnSubscribeThrow(exception)); + return unsafeCreate(new OnSubscribeThrow(exception)); } /** @@ -1838,7 +1902,7 @@ public static Observable error(Throwable exception) { */ @SuppressWarnings("cast") public static Observable from(Future future) { - return (Observable)create(OnSubscribeToObservableFuture.toObservableFuture(future)); + return (Observable)unsafeCreate(OnSubscribeToObservableFuture.toObservableFuture(future)); } /** @@ -1872,7 +1936,7 @@ public static Observable from(Future future) { */ @SuppressWarnings("cast") public static Observable from(Future future, long timeout, TimeUnit unit) { - return (Observable)create(OnSubscribeToObservableFuture.toObservableFuture(future, timeout, unit)); + return (Observable)unsafeCreate(OnSubscribeToObservableFuture.toObservableFuture(future, timeout, unit)); } /** @@ -1904,7 +1968,7 @@ public static Observable from(Future future, long timeout, T public static Observable from(Future future, Scheduler scheduler) { // TODO in a future revision the Scheduler will become important because we'll start polling instead of blocking on the Future @SuppressWarnings("cast") - Observable o = (Observable)create(OnSubscribeToObservableFuture.toObservableFuture(future)); + Observable o = (Observable)unsafeCreate(OnSubscribeToObservableFuture.toObservableFuture(future)); return o.subscribeOn(scheduler); } @@ -1929,7 +1993,7 @@ public static Observable from(Future future, Scheduler sched * @see ReactiveX operators documentation: From */ public static Observable from(Iterable iterable) { - return create(new OnSubscribeFromIterable(iterable)); + return unsafeCreate(new OnSubscribeFromIterable(iterable)); } /** @@ -1959,7 +2023,7 @@ public static Observable from(T[] array) { if (n == 1) { return just(array[0]); } - return create(new OnSubscribeFromArray(array)); + return unsafeCreate(new OnSubscribeFromArray(array)); } /** @@ -2002,10 +2066,12 @@ public static Observable from(T[] array) { * @see Emitter.BackpressureMode * @see rx.functions.Cancellable * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @deprecated 1.2.7 - aliased to {@link #create(Action1, rx.Emitter.BackpressureMode)}, will be removed in 1.3.0 */ @Experimental + @Deprecated public static Observable fromEmitter(Action1> emitter, Emitter.BackpressureMode backpressure) { - return create(new OnSubscribeFromEmitter(emitter, backpressure)); + return unsafeCreate(new OnSubscribeCreate(emitter, backpressure)); } /** @@ -2033,7 +2099,7 @@ public static Observable fromEmitter(Action1> emitter, Emitter * @since 1.2 */ public static Observable fromCallable(Callable func) { - return create(new OnSubscribeFromCallable(func)); + return unsafeCreate(new OnSubscribeFromCallable(func)); } /** @@ -2140,7 +2206,7 @@ public static Observable interval(long initialDelay, long period, TimeUnit * @since 1.0.12 */ public static Observable interval(long initialDelay, long period, TimeUnit unit, Scheduler scheduler) { - return create(new OnSubscribeTimerPeriodically(initialDelay, period, unit, scheduler)); + return unsafeCreate(new OnSubscribeTimerPeriodically(initialDelay, period, unit, scheduler)); } /** @@ -3473,7 +3539,7 @@ public static Observable range(int start, int count) { if (count == 1) { return Observable.just(start); } - return Observable.create(new OnSubscribeRange(start, start + (count - 1))); + return Observable.unsafeCreate(new OnSubscribeRange(start, start + (count - 1))); } /** @@ -3733,7 +3799,7 @@ public static Observable timer(long delay, TimeUnit unit) { * @see ReactiveX operators documentation: Timer */ public static Observable timer(long delay, TimeUnit unit, Scheduler scheduler) { - return create(new OnSubscribeTimerOnce(delay, unit, scheduler)); + return unsafeCreate(new OnSubscribeTimerOnce(delay, unit, scheduler)); } /** @@ -3803,7 +3869,7 @@ public static Observable using( final Func0 resourceFactory, final Func1> observableFactory, final Action1 disposeAction, boolean disposeEagerly) { - return create(new OnSubscribeUsing(resourceFactory, observableFactory, disposeAction, disposeEagerly)); + return unsafeCreate(new OnSubscribeUsing(resourceFactory, observableFactory, disposeAction, disposeEagerly)); } /** @@ -5070,7 +5136,7 @@ public final Observable collect(Func0 stateFactory, final Action2(this, stateFactory, collector)); + return unsafeCreate(new OnSubscribeCollect(this, stateFactory, collector)); } /** @@ -5103,7 +5169,7 @@ public final Observable concatMap(Func1 scalar = (ScalarSynchronousObservable) this; return scalar.scalarFlatMap(func); } - return create(new OnSubscribeConcatMap(this, func, 2, OnSubscribeConcatMap.IMMEDIATE)); + return unsafeCreate(new OnSubscribeConcatMap(this, func, 2, OnSubscribeConcatMap.IMMEDIATE)); } /** @@ -5134,7 +5200,7 @@ public final Observable concatMapDelayError(Func1 scalar = (ScalarSynchronousObservable) this; return scalar.scalarFlatMap(func); } - return create(new OnSubscribeConcatMap(this, func, 2, OnSubscribeConcatMap.END)); + return unsafeCreate(new OnSubscribeConcatMap(this, func, 2, OnSubscribeConcatMap.END)); } /** @@ -5580,7 +5646,7 @@ public final Observable delaySubscription(long delay, TimeUnit unit) { * @see ReactiveX operators documentation: Delay */ public final Observable delaySubscription(long delay, TimeUnit unit, Scheduler scheduler) { - return create(new OnSubscribeDelaySubscription(this, delay, unit, scheduler)); + return unsafeCreate(new OnSubscribeDelaySubscription(this, delay, unit, scheduler)); } /** @@ -5606,7 +5672,7 @@ public final Observable delaySubscription(long delay, TimeUnit unit, Schedule * @see ReactiveX operators documentation: Delay */ public final Observable delaySubscription(Func0> subscriptionDelay) { - return create(new OnSubscribeDelaySubscriptionWithSelector(this, subscriptionDelay)); + return unsafeCreate(new OnSubscribeDelaySubscriptionWithSelector(this, subscriptionDelay)); } /** @@ -5633,7 +5699,7 @@ public final Observable delaySubscription(Observable other) { if (other == null) { throw new NullPointerException(); } - return create(new OnSubscribeDelaySubscriptionOther(this, other)); + return unsafeCreate(new OnSubscribeDelaySubscriptionOther(this, other)); } /** @@ -5800,7 +5866,7 @@ public final Observable doOnCompleted(final Action0 onCompleted) { Action1 onError = Actions.empty(); Observer observer = new ActionObserver(onNext, onError, onCompleted); - return create(new OnSubscribeDoOnEach(this, observer)); + return unsafeCreate(new OnSubscribeDoOnEach(this, observer)); } /** @@ -5822,7 +5888,7 @@ public final Observable doOnCompleted(final Action0 onCompleted) { */ public final Observable doOnEach(final Action1> onNotification) { Observer observer = new ActionNotificationObserver(onNotification); - return create(new OnSubscribeDoOnEach(this, observer)); + return unsafeCreate(new OnSubscribeDoOnEach(this, observer)); } /** @@ -5849,7 +5915,7 @@ public final Observable doOnEach(final Action1> onNot * @see ReactiveX operators documentation: Do */ public final Observable doOnEach(Observer observer) { - return create(new OnSubscribeDoOnEach(this, observer)); + return unsafeCreate(new OnSubscribeDoOnEach(this, observer)); } /** @@ -5877,7 +5943,7 @@ public final Observable doOnError(final Action1 onError) { Action0 onCompleted = Actions.empty(); Observer observer = new ActionObserver(onNext, onError, onCompleted); - return create(new OnSubscribeDoOnEach(this, observer)); + return unsafeCreate(new OnSubscribeDoOnEach(this, observer)); } /** @@ -5902,7 +5968,7 @@ public final Observable doOnNext(final Action1 onNext) { Action0 onCompleted = Actions.empty(); Observer observer = new ActionObserver(onNext, onError, onCompleted); - return create(new OnSubscribeDoOnEach(this, observer)); + return unsafeCreate(new OnSubscribeDoOnEach(this, observer)); } /** @@ -5983,7 +6049,7 @@ public final Observable doOnTerminate(final Action0 onTerminate) { Observer observer = new ActionObserver(onNext, onError, onTerminate); - return create(new OnSubscribeDoOnEach(this, observer)); + return unsafeCreate(new OnSubscribeDoOnEach(this, observer)); } /** @@ -6559,7 +6625,7 @@ public final Observable exists(Func1 predicate) { * @see ReactiveX operators documentation: Filter */ public final Observable filter(Func1 predicate) { - return create(new OnSubscribeFilter(this, predicate)); + return unsafeCreate(new OnSubscribeFilter(this, predicate)); } /** @@ -7301,7 +7367,7 @@ public final Observable> groupBy(final Func1 Observable groupJoin(Observable right, Func1> leftDuration, Func1> rightDuration, Func2, ? extends R> resultSelector) { - return create(new OnSubscribeGroupJoin(this, right, leftDuration, rightDuration, resultSelector)); + return unsafeCreate(new OnSubscribeGroupJoin(this, right, leftDuration, rightDuration, resultSelector)); } /** @@ -7383,7 +7449,7 @@ public final Observable isEmpty() { public final Observable join(Observable right, Func1> leftDurationSelector, Func1> rightDurationSelector, Func2 resultSelector) { - return create(new OnSubscribeJoin(this, right, leftDurationSelector, rightDurationSelector, resultSelector)); + return unsafeCreate(new OnSubscribeJoin(this, right, leftDurationSelector, rightDurationSelector, resultSelector)); } /** @@ -7531,7 +7597,7 @@ public final Observable limit(int count) { * @see ReactiveX operators documentation: Map */ public final Observable map(Func1 func) { - return create(new OnSubscribeMap(this, func)); + return unsafeCreate(new OnSubscribeMap(this, func)); } private Observable mapNotification(Func1 onNext, Func1 onError, Func0 onCompleted) { @@ -8108,7 +8174,7 @@ public final Observable onExceptionResumeNext(final Observable r */ @Experimental public final Observable onTerminateDetach() { - return create(new OnSubscribeDetach(this)); + return unsafeCreate(new OnSubscribeDetach(this)); } /** @@ -8225,7 +8291,7 @@ public final Observable reduce(Func2 accumulator) { * * It should use last() not takeLast(1) since it needs to emit an error if the sequence is empty. */ - return create(new OnSubscribeReduce(this, accumulator)); + return unsafeCreate(new OnSubscribeReduce(this, accumulator)); } /** @@ -8273,7 +8339,7 @@ public final Observable reduce(Func2 accumulator) { * @see Wikipedia: Fold (higher-order function) */ public final Observable reduce(R initialValue, Func2 accumulator) { - return create(new OnSubscribeReduceSeed(this, initialValue, accumulator)); + return unsafeCreate(new OnSubscribeReduceSeed(this, initialValue, accumulator)); } /** @@ -9486,7 +9552,7 @@ public final Observable skip(long time, TimeUnit unit) { * @see ReactiveX operators documentation: Skip */ public final Observable skip(long time, TimeUnit unit, Scheduler scheduler) { - return create(new OnSubscribeSkipTimed(this, time, unit, scheduler)); + return unsafeCreate(new OnSubscribeSkipTimed(this, time, unit, scheduler)); } /** @@ -10288,7 +10354,7 @@ public final Observable subscribeOn(Scheduler scheduler) { if (this instanceof ScalarSynchronousObservable) { return ((ScalarSynchronousObservable)this).scalarScheduleOn(scheduler); } - return create(new OperatorSubscribeOn(this, scheduler)); + return unsafeCreate(new OperatorSubscribeOn(this, scheduler)); } /** @@ -10483,7 +10549,7 @@ public final Observable takeLast(final int count) { if (count == 0) { return ignoreElements(); } else if (count == 1) { - return create(new OnSubscribeTakeLastOne(this)); + return unsafeCreate(new OnSubscribeTakeLastOne(this)); } else { return lift(new OperatorTakeLast(count)); } @@ -11441,7 +11507,7 @@ public final Observable> toList() { * @see ReactiveX operators documentation: To */ public final Observable> toMap(Func1 keySelector) { - return create(new OnSubscribeToMap(this, keySelector, UtilityFunctions.identity())); + return unsafeCreate(new OnSubscribeToMap(this, keySelector, UtilityFunctions.identity())); } /** @@ -11471,7 +11537,7 @@ public final Observable> toMap(Func1 keySe * @see ReactiveX operators documentation: To */ public final Observable> toMap(Func1 keySelector, Func1 valueSelector) { - return create(new OnSubscribeToMap(this, keySelector, valueSelector)); + return unsafeCreate(new OnSubscribeToMap(this, keySelector, valueSelector)); } /** @@ -11500,7 +11566,7 @@ public final Observable> toMap(Func1 ke * @see ReactiveX operators documentation: To */ public final Observable> toMap(Func1 keySelector, Func1 valueSelector, Func0> mapFactory) { - return create(new OnSubscribeToMap(this, keySelector, valueSelector, mapFactory)); + return unsafeCreate(new OnSubscribeToMap(this, keySelector, valueSelector, mapFactory)); } /** @@ -11523,7 +11589,7 @@ public final Observable> toMap(Func1 ke * @see ReactiveX operators documentation: To */ public final Observable>> toMultimap(Func1 keySelector) { - return create(new OnSubscribeToMultimap(this, keySelector, UtilityFunctions.identity())); + return unsafeCreate(new OnSubscribeToMultimap(this, keySelector, UtilityFunctions.identity())); } /** @@ -11551,7 +11617,7 @@ public final Observable>> toMultimap(Func1ReactiveX operators documentation: To */ public final Observable>> toMultimap(Func1 keySelector, Func1 valueSelector) { - return create(new OnSubscribeToMultimap(this, keySelector, valueSelector)); + return unsafeCreate(new OnSubscribeToMultimap(this, keySelector, valueSelector)); } /** @@ -11581,7 +11647,7 @@ public final Observable>> toMultimap(Func1ReactiveX operators documentation: To */ public final Observable>> toMultimap(Func1 keySelector, Func1 valueSelector, Func0>> mapFactory) { - return create(new OnSubscribeToMultimap(this, keySelector, valueSelector, mapFactory)); + return unsafeCreate(new OnSubscribeToMultimap(this, keySelector, valueSelector, mapFactory)); } /** @@ -11613,7 +11679,7 @@ public final Observable>> toMultimap(Func1ReactiveX operators documentation: To */ public final Observable>> toMultimap(Func1 keySelector, Func1 valueSelector, Func0>> mapFactory, Func1> collectionFactory) { - return create(new OnSubscribeToMultimap(this, keySelector, valueSelector, mapFactory, collectionFactory)); + return unsafeCreate(new OnSubscribeToMultimap(this, keySelector, valueSelector, mapFactory, collectionFactory)); } /** @@ -11857,7 +11923,7 @@ public final Observable withLatestFrom(Observable other, */ @Experimental public final Observable withLatestFrom(Observable o1, Observable o2, Func3 combiner) { - return create(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2 }, null, Functions.fromFunc(combiner))); + return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2 }, null, Functions.fromFunc(combiner))); } /** @@ -11894,7 +11960,7 @@ public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, Func4 combiner) { - return create(new OperatorWithLatestFromMany(this, + return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2, o3 }, null, Functions.fromFunc(combiner))); } @@ -11934,7 +12000,7 @@ public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, Observable o4, Func5 combiner) { - return create(new OperatorWithLatestFromMany(this, + return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2, o3, o4 }, null, Functions.fromFunc(combiner))); } /** @@ -11976,7 +12042,7 @@ public final Observable withLatestFrom( Observable o3, Observable o4, Observable o5, Func6 combiner) { - return create(new OperatorWithLatestFromMany(this, + return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2, o3, o4, o5 }, null, Functions.fromFunc(combiner))); } @@ -12021,7 +12087,7 @@ public final Observable withLatestFrom( Observable o3, Observable o4, Observable o5, Observable o6, Func7 combiner) { - return create(new OperatorWithLatestFromMany(this, + return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2, o3, o4, o5, o6 }, null, Functions.fromFunc(combiner))); } @@ -12069,7 +12135,7 @@ public final Observable withLatestFrom( Observable o5, Observable o6, Observable o7, Func8 combiner) { - return create(new OperatorWithLatestFromMany(this, + return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2, o3, o4, o5, o6, o7 }, null, Functions.fromFunc(combiner))); } @@ -12119,7 +12185,7 @@ public final Observable withLatestFrom( Observable o5, Observable o6, Observable o7, Observable o8, Func9 combiner) { - return create(new OperatorWithLatestFromMany(this, + return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2, o3, o4, o5, o6, o7, o8 }, null, Functions.fromFunc(combiner))); } @@ -12149,7 +12215,7 @@ public final Observable withLatestFrom( */ @Experimental public final Observable withLatestFrom(Observable[] others, FuncN combiner) { - return create(new OperatorWithLatestFromMany(this, others, null, combiner)); + return unsafeCreate(new OperatorWithLatestFromMany(this, others, null, combiner)); } /** @@ -12178,7 +12244,7 @@ public final Observable withLatestFrom(Observable[] others, FuncN c */ @Experimental public final Observable withLatestFrom(Iterable> others, FuncN combiner) { - return create(new OperatorWithLatestFromMany(this, null, others, combiner)); + return unsafeCreate(new OperatorWithLatestFromMany(this, null, others, combiner)); } /** diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index 782d5c833f..709b709f41 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -202,7 +202,7 @@ public interface Transformer extends Func1, Single> { */ private static Observable asObservable(Single t) { // is this sufficient, or do I need to keep the outer Single and subscribe to it? - return Observable.create(new SingleToObservable(t.onSubscribe)); + return Observable.unsafeCreate(new SingleToObservable(t.onSubscribe)); } /* ********************************************************************************************************* diff --git a/src/main/java/rx/internal/operators/EmptyObservableHolder.java b/src/main/java/rx/internal/operators/EmptyObservableHolder.java index e582407bee..e386539c66 100644 --- a/src/main/java/rx/internal/operators/EmptyObservableHolder.java +++ b/src/main/java/rx/internal/operators/EmptyObservableHolder.java @@ -28,7 +28,7 @@ public enum EmptyObservableHolder implements OnSubscribe { ; /** The singleton instance. */ - static final Observable EMPTY = Observable.create(INSTANCE); + static final Observable EMPTY = Observable.unsafeCreate(INSTANCE); /** diff --git a/src/main/java/rx/internal/operators/NeverObservableHolder.java b/src/main/java/rx/internal/operators/NeverObservableHolder.java index 6a80d22e8b..056c08b034 100644 --- a/src/main/java/rx/internal/operators/NeverObservableHolder.java +++ b/src/main/java/rx/internal/operators/NeverObservableHolder.java @@ -28,7 +28,7 @@ public enum NeverObservableHolder implements OnSubscribe { ; /** The singleton instance. */ - static final Observable NEVER = Observable.create(INSTANCE); + static final Observable NEVER = Observable.unsafeCreate(INSTANCE); /** * Returns a type-corrected singleton instance of the never Observable. diff --git a/src/main/java/rx/internal/operators/OnSubscribeFromEmitter.java b/src/main/java/rx/internal/operators/OnSubscribeCreate.java similarity index 97% rename from src/main/java/rx/internal/operators/OnSubscribeFromEmitter.java rename to src/main/java/rx/internal/operators/OnSubscribeCreate.java index 355ae99c1d..497b240ec0 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeFromEmitter.java +++ b/src/main/java/rx/internal/operators/OnSubscribeCreate.java @@ -29,13 +29,13 @@ import rx.plugins.RxJavaHooks; import rx.subscriptions.SerialSubscription; -public final class OnSubscribeFromEmitter implements OnSubscribe { +public final class OnSubscribeCreate implements OnSubscribe { final Action1> Emitter; final Emitter.BackpressureMode backpressure; - public OnSubscribeFromEmitter(Action1> Emitter, Emitter.BackpressureMode backpressure) { + public OnSubscribeCreate(Action1> Emitter, Emitter.BackpressureMode backpressure) { this.Emitter = Emitter; this.backpressure = backpressure; } @@ -268,7 +268,7 @@ public void onError(Throwable e) { @Override void onOverflow() { - onError(new MissingBackpressureException("fromEmitter: could not emit value due to lack of requests")); + onError(new MissingBackpressureException("create: could not emit value due to lack of requests")); } } diff --git a/src/main/java/rx/internal/operators/OnSubscribeFlattenIterable.java b/src/main/java/rx/internal/operators/OnSubscribeFlattenIterable.java index 608e6808b7..fe85e55369 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeFlattenIterable.java +++ b/src/main/java/rx/internal/operators/OnSubscribeFlattenIterable.java @@ -70,9 +70,9 @@ public static Observable createFrom(Observable source, Func1> mapper, int prefetch) { if (source instanceof ScalarSynchronousObservable) { T scalar = ((ScalarSynchronousObservable) source).get(); - return Observable.create(new OnSubscribeScalarFlattenIterable(scalar, mapper)); + return Observable.unsafeCreate(new OnSubscribeScalarFlattenIterable(scalar, mapper)); } - return Observable.create(new OnSubscribeFlattenIterable(source, mapper, prefetch)); + return Observable.unsafeCreate(new OnSubscribeFlattenIterable(source, mapper, prefetch)); } static final class FlattenIterableSubscriber extends Subscriber { diff --git a/src/main/java/rx/internal/operators/OnSubscribeGroupJoin.java b/src/main/java/rx/internal/operators/OnSubscribeGroupJoin.java index 4666751842..3c99b68262 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeGroupJoin.java +++ b/src/main/java/rx/internal/operators/OnSubscribeGroupJoin.java @@ -170,7 +170,7 @@ public void onNext(T1 args) { leftMap().put(id, subjSerial); } - Observable window = Observable.create(new WindowObservableFunc(subj, cancel)); + Observable window = Observable.unsafeCreate(new WindowObservableFunc(subj, cancel)); Observable duration = leftDuration.call(args); diff --git a/src/main/java/rx/internal/operators/OnSubscribeRedo.java b/src/main/java/rx/internal/operators/OnSubscribeRedo.java index fc9fe9e4d2..de4f5e4d15 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeRedo.java +++ b/src/main/java/rx/internal/operators/OnSubscribeRedo.java @@ -31,7 +31,7 @@ * limitations under the License. */ -import static rx.Observable.create; // NOPMD +import static rx.Observable.unsafeCreate; // NOPMD import java.util.concurrent.atomic.*; @@ -133,11 +133,11 @@ public static Observable retry(Observable source, final long count) { } public static Observable retry(Observable source, Func1>, ? extends Observable> notificationHandler) { - return create(new OnSubscribeRedo(source, notificationHandler, true, false, Schedulers.trampoline())); + return unsafeCreate(new OnSubscribeRedo(source, notificationHandler, true, false, Schedulers.trampoline())); } public static Observable retry(Observable source, Func1>, ? extends Observable> notificationHandler, Scheduler scheduler) { - return create(new OnSubscribeRedo(source, notificationHandler, true, false, scheduler)); + return unsafeCreate(new OnSubscribeRedo(source, notificationHandler, true, false, scheduler)); } public static Observable repeat(Observable source) { @@ -163,15 +163,15 @@ public static Observable repeat(Observable source, final long count, S } public static Observable repeat(Observable source, Func1>, ? extends Observable> notificationHandler) { - return create(new OnSubscribeRedo(source, notificationHandler, false, true, Schedulers.trampoline())); + return unsafeCreate(new OnSubscribeRedo(source, notificationHandler, false, true, Schedulers.trampoline())); } public static Observable repeat(Observable source, Func1>, ? extends Observable> notificationHandler, Scheduler scheduler) { - return create(new OnSubscribeRedo(source, notificationHandler, false, true, scheduler)); + return unsafeCreate(new OnSubscribeRedo(source, notificationHandler, false, true, scheduler)); } public static Observable redo(Observable source, Func1>, ? extends Observable> notificationHandler, Scheduler scheduler) { - return create(new OnSubscribeRedo(source, notificationHandler, false, false, scheduler)); + return unsafeCreate(new OnSubscribeRedo(source, notificationHandler, false, false, scheduler)); } private OnSubscribeRedo(Observable source, Func1>, ? extends Observable> f, boolean stopOnComplete, boolean stopOnError, diff --git a/src/main/java/rx/internal/operators/OperatorPublish.java b/src/main/java/rx/internal/operators/OperatorPublish.java index 7d087efcb4..c07d084abe 100644 --- a/src/main/java/rx/internal/operators/OperatorPublish.java +++ b/src/main/java/rx/internal/operators/OperatorPublish.java @@ -123,7 +123,7 @@ public static Observable create(final Observable source, public static Observable create(final Observable source, final Func1, ? extends Observable> selector, final boolean delayError) { - return create(new OnSubscribe() { + return unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber child) { final OnSubscribePublishMulticast op = new OnSubscribePublishMulticast(RxRingBuffer.SIZE, delayError); @@ -155,7 +155,7 @@ public void setProducer(Producer p) { child.add(op); child.add(subscriber); - selector.call(Observable.create(op)).unsafeSubscribe(subscriber); + selector.call(Observable.unsafeCreate(op)).unsafeSubscribe(subscriber); source.unsafeSubscribe(op.subscriber()); } diff --git a/src/main/java/rx/internal/operators/OperatorReplay.java b/src/main/java/rx/internal/operators/OperatorReplay.java index 53511f9c80..045eae96af 100644 --- a/src/main/java/rx/internal/operators/OperatorReplay.java +++ b/src/main/java/rx/internal/operators/OperatorReplay.java @@ -58,7 +58,7 @@ public Object call() { public static Observable multicastSelector( final Func0> connectableFactory, final Func1, ? extends Observable> selector) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber child) { ConnectableObservable co; diff --git a/src/main/java/rx/internal/util/ScalarSynchronousObservable.java b/src/main/java/rx/internal/util/ScalarSynchronousObservable.java index d14269953c..141030266e 100644 --- a/src/main/java/rx/internal/util/ScalarSynchronousObservable.java +++ b/src/main/java/rx/internal/util/ScalarSynchronousObservable.java @@ -122,7 +122,7 @@ public void call() { }; } - return create(new ScalarAsyncOnSubscribe(t, onSchedule)); + return unsafeCreate(new ScalarAsyncOnSubscribe(t, onSchedule)); } /** The OnSubscribe callback for the Observable constructor. */ @@ -225,7 +225,7 @@ public String toString() { * @return the new observable */ public Observable scalarFlatMap(final Func1> func) { - return create(new OnSubscribe() { + return unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber child) { Observable o = func.call(t); diff --git a/src/main/java/rx/observables/AsyncOnSubscribe.java b/src/main/java/rx/observables/AsyncOnSubscribe.java index 35eb618736..e3acb1627e 100644 --- a/src/main/java/rx/observables/AsyncOnSubscribe.java +++ b/src/main/java/rx/observables/AsyncOnSubscribe.java @@ -33,7 +33,7 @@ /** * A utility class to create {@code OnSubscribe} functions that respond correctly to back * pressure requests from subscribers. This is an improvement over - * {@link rx.Observable#create(OnSubscribe) Observable.create(OnSubscribe)} which does not provide + * {@link rx.Observable#unsafeCreate(OnSubscribe) Observable.create(OnSubscribe)} which does not provide * any means of managing back pressure requests out-of-the-box. This variant of an OnSubscribe * function allows for the asynchronous processing of requests. * diff --git a/src/main/java/rx/observables/ConnectableObservable.java b/src/main/java/rx/observables/ConnectableObservable.java index 09ac04257d..f1fffceb5f 100644 --- a/src/main/java/rx/observables/ConnectableObservable.java +++ b/src/main/java/rx/observables/ConnectableObservable.java @@ -76,7 +76,7 @@ public void call(Subscription t1) { * @see ReactiveX documentation: RefCount */ public Observable refCount() { - return create(new OnSubscribeRefCount(this)); + return unsafeCreate(new OnSubscribeRefCount(this)); } /** @@ -125,6 +125,6 @@ public Observable autoConnect(int numberOfSubscribers, Action1(this, numberOfSubscribers, connection)); + return unsafeCreate(new OnSubscribeAutoConnect(this, numberOfSubscribers, connection)); } } diff --git a/src/main/java/rx/observables/SyncOnSubscribe.java b/src/main/java/rx/observables/SyncOnSubscribe.java index dc9e2a7a3c..cf848e7bc4 100644 --- a/src/main/java/rx/observables/SyncOnSubscribe.java +++ b/src/main/java/rx/observables/SyncOnSubscribe.java @@ -29,7 +29,7 @@ /** * A utility class to create {@code OnSubscribe} functions that responds correctly to back * pressure requests from subscribers. This is an improvement over - * {@link rx.Observable#create(OnSubscribe) Observable.create(OnSubscribe)} which does not provide + * {@link rx.Observable#unsafeCreate(OnSubscribe) Observable.create(OnSubscribe)} which does not provide * any means of managing back pressure requests out-of-the-box. * * @param diff --git a/src/main/java/rx/plugins/RxJavaObservableExecutionHook.java b/src/main/java/rx/plugins/RxJavaObservableExecutionHook.java index f1b897fa21..47ab6e4095 100644 --- a/src/main/java/rx/plugins/RxJavaObservableExecutionHook.java +++ b/src/main/java/rx/plugins/RxJavaObservableExecutionHook.java @@ -41,7 +41,7 @@ */ public abstract class RxJavaObservableExecutionHook { // NOPMD /** - * Invoked during the construction by {@link Observable#create(OnSubscribe)} + * Invoked during the construction by {@link Observable#unsafeCreate(OnSubscribe)} *

* This can be used to decorate or replace the onSubscribe function or just perform extra * logging, metrics and other such things and pass through the function. diff --git a/src/perf/java/rx/OneItemPerf.java b/src/perf/java/rx/OneItemPerf.java index 43c6539992..7927268c69 100644 --- a/src/perf/java/rx/OneItemPerf.java +++ b/src/perf/java/rx/OneItemPerf.java @@ -70,7 +70,7 @@ public void call(SingleSubscriber t) { @Setup public void setup() { scalar = Observable.just(1); - one = Observable.create(new OnSubscribe() { + one = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { t.setProducer(new SingleProducer(t, 1)); diff --git a/src/perf/java/rx/jmh/InputWithIncrementingInteger.java b/src/perf/java/rx/jmh/InputWithIncrementingInteger.java index 9700db74c1..24468bb97b 100644 --- a/src/perf/java/rx/jmh/InputWithIncrementingInteger.java +++ b/src/perf/java/rx/jmh/InputWithIncrementingInteger.java @@ -44,7 +44,7 @@ public void setup(final Blackhole bh) { final int size = getSize(); observable = Observable.range(0, size); - firehose = Observable.create(new OnSubscribe() { + firehose = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/perf/java/rx/operators/FromComparison.java b/src/perf/java/rx/operators/FromComparison.java index 3ba2d3c751..763a938cae 100644 --- a/src/perf/java/rx/operators/FromComparison.java +++ b/src/perf/java/rx/operators/FromComparison.java @@ -49,8 +49,8 @@ public void setup() { Arrays.fill(array, 1); - iterableSource = Observable.create(new OnSubscribeFromIterable(Arrays.asList(array))); - arraySource = Observable.create(new OnSubscribeFromArray(array)); + iterableSource = Observable.unsafeCreate(new OnSubscribeFromIterable(Arrays.asList(array))); + arraySource = Observable.unsafeCreate(new OnSubscribeFromArray(array)); } @Benchmark diff --git a/src/perf/java/rx/operators/OperatorRangePerf.java b/src/perf/java/rx/operators/OperatorRangePerf.java index 53e06a0c94..78711e3d58 100644 --- a/src/perf/java/rx/operators/OperatorRangePerf.java +++ b/src/perf/java/rx/operators/OperatorRangePerf.java @@ -43,7 +43,7 @@ public static class InputUsingRequest { @Setup public void setup(final Blackhole bh) { - observable = Observable.create(new OnSubscribeRange(0, size)); + observable = Observable.unsafeCreate(new OnSubscribeRange(0, size)); this.bh = bh; } @@ -91,7 +91,7 @@ public static class InputWithoutRequest { @Setup public void setup(final Blackhole bh) { - observable = Observable.create(new OnSubscribeRange(0, size)); + observable = Observable.unsafeCreate(new OnSubscribeRange(0, size)); this.bh = bh; } diff --git a/src/perf/java/rx/operators/OperatorSerializePerf.java b/src/perf/java/rx/operators/OperatorSerializePerf.java index cae310b72c..70b61421ec 100644 --- a/src/perf/java/rx/operators/OperatorSerializePerf.java +++ b/src/perf/java/rx/operators/OperatorSerializePerf.java @@ -59,7 +59,7 @@ public void serializedSingleStream(Input input) throws InterruptedException { @Benchmark public void serializedTwoStreamsHighlyContended(final Input input) throws InterruptedException { LatchedObserver o = input.newLatchedObserver(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -101,7 +101,7 @@ public Integer call(Long t1) { @Benchmark public void serializedTwoStreamsSlightlyContended(final InputWithInterval input) throws InterruptedException { LatchedObserver o = input.newLatchedObserver(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -118,7 +118,7 @@ public void call(Subscriber s) { @Benchmark public void serializedTwoStreamsOneFastOneSlow(final InputWithInterval input) throws InterruptedException { LatchedObserver o = input.newLatchedObserver(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber s) { diff --git a/src/perf/java/rx/operators/OperatorTakeLastOnePerf.java b/src/perf/java/rx/operators/OperatorTakeLastOnePerf.java index 3b54689c53..c96f9a2c66 100644 --- a/src/perf/java/rx/operators/OperatorTakeLastOnePerf.java +++ b/src/perf/java/rx/operators/OperatorTakeLastOnePerf.java @@ -46,7 +46,7 @@ public void takeLastOneUsingTakeLast(Input input) { @Benchmark public void takeLastOneUsingTakeLastOne(Input input) { - Observable.create(new OnSubscribeTakeLastOne(input.observable)).subscribe(input.observer); + Observable.unsafeCreate(new OnSubscribeTakeLastOne(input.observable)).subscribe(input.observer); } } diff --git a/src/test/java/rx/BackpressureTests.java b/src/test/java/rx/BackpressureTests.java index f9931f8754..16a1565b0a 100644 --- a/src/test/java/rx/BackpressureTests.java +++ b/src/test/java/rx/BackpressureTests.java @@ -593,7 +593,7 @@ private static Observable incrementingIntegers(final AtomicInteger coun } private static Observable incrementingIntegers(final AtomicInteger counter, final ConcurrentLinkedQueue threadsSeen) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { final AtomicLong requested = new AtomicLong(); @@ -637,7 +637,7 @@ public void request(long n) { * @return */ private static Observable firehose(final AtomicInteger counter) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { int i; diff --git a/src/test/java/rx/CompletableTest.java b/src/test/java/rx/CompletableTest.java index 97a40439c8..23418b60e6 100644 --- a/src/test/java/rx/CompletableTest.java +++ b/src/test/java/rx/CompletableTest.java @@ -391,7 +391,7 @@ public void call(CompletableSubscriber cs) { cs.onError(e); } }) - .andThen(Observable.create(new Observable.OnSubscribe() { + .andThen(Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s) { hasRun.set(true); diff --git a/src/test/java/rx/ConcatTests.java b/src/test/java/rx/ConcatTests.java index 558f8af1dd..d00d812c52 100644 --- a/src/test/java/rx/ConcatTests.java +++ b/src/test/java/rx/ConcatTests.java @@ -149,7 +149,7 @@ public void testConcatCovariance4() { Media media = new Media(); HorrorMovie horrorMovie2 = new HorrorMovie(); - Observable o1 = Observable.create(new OnSubscribe() { + Observable o1 = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber o) { diff --git a/src/test/java/rx/EventStream.java b/src/test/java/rx/EventStream.java index 632e649601..91a6482a5c 100644 --- a/src/test/java/rx/EventStream.java +++ b/src/test/java/rx/EventStream.java @@ -32,7 +32,7 @@ private EventStream() { throw new IllegalStateException("No instances!"); } public static Observable getEventStream(final String type, final int numInstances) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber subscriber) { diff --git a/src/test/java/rx/MergeTests.java b/src/test/java/rx/MergeTests.java index 07bba783ea..c42579cc37 100644 --- a/src/test/java/rx/MergeTests.java +++ b/src/test/java/rx/MergeTests.java @@ -80,7 +80,7 @@ public void testMergeCovariance3() { @Test public void testMergeCovariance4() { - Observable o1 = Observable.create(new OnSubscribe() { + Observable o1 = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber o) { diff --git a/src/test/java/rx/ObservableTests.java b/src/test/java/rx/ObservableTests.java index bed04b4cdc..1ad7daaa72 100644 --- a/src/test/java/rx/ObservableTests.java +++ b/src/test/java/rx/ObservableTests.java @@ -94,7 +94,7 @@ public void fromArityArgs1() { @Test public void testCreate() { - Observable observable = Observable.create(new OnSubscribe() { + Observable observable = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber Observer) { @@ -140,7 +140,7 @@ public void testCountZeroItems() { @Test public void testCountError() { - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber obsv) { obsv.onError(new RuntimeException()); @@ -289,7 +289,7 @@ public void testOnSubscribeFails() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); final RuntimeException re = new RuntimeException("bad impl"); - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { @@ -330,7 +330,7 @@ public void testCustomObservableWithErrorInObserverAsynchronous() throws Interru final CountDownLatch latch = new CountDownLatch(1); final AtomicInteger count = new AtomicInteger(); final AtomicReference error = new AtomicReference(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -395,7 +395,7 @@ public void onNext(String v) { public void testCustomObservableWithErrorInObserverSynchronous() { final AtomicInteger count = new AtomicInteger(); final AtomicReference error = new AtomicReference(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { @@ -445,7 +445,7 @@ public void onNext(String v) { public void testCustomObservableWithErrorInObservableSynchronous() { final AtomicInteger count = new AtomicInteger(); final AtomicReference error = new AtomicReference(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { @@ -484,7 +484,7 @@ public void onNext(String v) { @Test public void testPublishLast() throws InterruptedException { final AtomicInteger count = new AtomicInteger(); - ConnectableObservable connectable = Observable.create(new OnSubscribe() { + ConnectableObservable connectable = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { count.incrementAndGet(); @@ -522,7 +522,7 @@ public void call(String value) { @Test public void testReplay() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - ConnectableObservable o = Observable.create(new OnSubscribe() { + ConnectableObservable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -577,7 +577,7 @@ public void call(String v) { @Test public void testCache() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -625,7 +625,7 @@ public void call(String v) { @Test public void testCacheWithCapacity() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -711,7 +711,7 @@ public void call(Object t1) { public void testErrorThrownWithoutErrorHandlerAsynchronous() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference exception = new AtomicReference(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -1109,7 +1109,7 @@ public void testForEachWithNull() { @Test public void nullOnSubscribe() { - Observable source = Observable.create((OnSubscribe)null); + Observable source = Observable.unsafeCreate((OnSubscribe)null); try { source.subscribe(); @@ -1147,7 +1147,7 @@ public void nullSubscriber() { @Test public void testCacheHint() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { diff --git a/src/test/java/rx/SubscriberTest.java b/src/test/java/rx/SubscriberTest.java index 5180966a1a..a57f2b0229 100644 --- a/src/test/java/rx/SubscriberTest.java +++ b/src/test/java/rx/SubscriberTest.java @@ -229,7 +229,7 @@ public void testRequestToObservable() { TestSubscriber ts = new TestSubscriber(); ts.request(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -252,7 +252,7 @@ public void testRequestThroughMap() { TestSubscriber ts = new TestSubscriber(); ts.request(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -282,7 +282,7 @@ public void testRequestThroughTakeThatReducesRequest() { TestSubscriber ts = new TestSubscriber(); ts.request(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -305,7 +305,7 @@ public void testRequestThroughTakeWhereRequestIsSmallerThanTake() { TestSubscriber ts = new TestSubscriber(); ts.request(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/exceptions/ExceptionsTest.java b/src/test/java/rx/exceptions/ExceptionsTest.java index 5fe0f18d69..07bcb644a8 100644 --- a/src/test/java/rx/exceptions/ExceptionsTest.java +++ b/src/test/java/rx/exceptions/ExceptionsTest.java @@ -254,10 +254,10 @@ public void onNext(Integer integer) { @Test(expected = OnErrorFailedException.class) public void testOnErrorExceptionIsThrownFromSubscribe() { - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s1) { - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s2) { throw new IllegalArgumentException("original exception"); @@ -270,10 +270,10 @@ public void call(Subscriber s2) { @Test(expected = OnErrorFailedException.class) public void testOnErrorExceptionIsThrownFromUnsafeSubscribe() { - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s1) { - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s2) { throw new IllegalArgumentException("original exception"); diff --git a/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java b/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java index 45a109e885..4cff913cea 100644 --- a/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java +++ b/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java @@ -239,7 +239,7 @@ public void testNoBufferingOrBlockingOfSequence() throws Throwable { final CountDownLatch timeHasPassed = new CountDownLatch(COUNT); final AtomicBoolean running = new AtomicBoolean(true); final AtomicInteger count = new AtomicInteger(0); - final Observable obs = Observable.create(new Observable.OnSubscribe() { + final Observable obs = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber o) { diff --git a/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java b/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java index 97d8cdb250..81f54dcdca 100644 --- a/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java +++ b/src/test/java/rx/internal/operators/BlockingOperatorToFutureTest.java @@ -65,7 +65,7 @@ public void testExceptionWithMoreThanOneElement() throws Throwable { @Test public void testToFutureWithException() { - Observable obs = Observable.create(new OnSubscribe() { + Observable obs = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { @@ -85,7 +85,7 @@ public void call(Subscriber observer) { @Test(expected = CancellationException.class) public void testGetAfterCancel() throws Exception { - Observable obs = Observable.create(new OperationNeverComplete()); + Observable obs = Observable.unsafeCreate(new OperationNeverComplete()); Future f = toFuture(obs); boolean cancelled = f.cancel(true); assertTrue(cancelled); // because OperationNeverComplete never does @@ -94,7 +94,7 @@ public void testGetAfterCancel() throws Exception { @Test(expected = CancellationException.class) public void testGetWithTimeoutAfterCancel() throws Exception { - Observable obs = Observable.create(new OperationNeverComplete()); + Observable obs = Observable.unsafeCreate(new OperationNeverComplete()); Future f = toFuture(obs); boolean cancelled = f.cancel(true); assertTrue(cancelled); // because OperationNeverComplete never does diff --git a/src/test/java/rx/internal/operators/BlockingOperatorToIteratorTest.java b/src/test/java/rx/internal/operators/BlockingOperatorToIteratorTest.java index e641227f01..91902b2c77 100644 --- a/src/test/java/rx/internal/operators/BlockingOperatorToIteratorTest.java +++ b/src/test/java/rx/internal/operators/BlockingOperatorToIteratorTest.java @@ -55,7 +55,7 @@ public void testToIterator() { @Test(expected = TestException.class) public void testToIteratorWithException() { - Observable obs = Observable.create(new OnSubscribe() { + Observable obs = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { @@ -75,7 +75,7 @@ public void call(Subscriber observer) { @Test(expected = TestException.class) public void testExceptionThrownFromOnSubscribe() { - Iterable strings = Observable.create(new Observable.OnSubscribe() { + Iterable strings = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber subscriber) { throw new TestException("intentional"); diff --git a/src/test/java/rx/internal/operators/CachedObservableTest.java b/src/test/java/rx/internal/operators/CachedObservableTest.java index a642d80b03..40fe2e56de 100644 --- a/src/test/java/rx/internal/operators/CachedObservableTest.java +++ b/src/test/java/rx/internal/operators/CachedObservableTest.java @@ -85,7 +85,7 @@ public void testColdReplayBackpressure() { @Test public void testCache() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - Observable o = Observable.create(new Observable.OnSubscribe() { + Observable o = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -220,7 +220,7 @@ public void testAsyncComeAndGo() { @Test public void testNoMissingBackpressureException() { final int m = 4 * 1000 * 1000; - Observable firehose = Observable.create(new OnSubscribe() { + Observable firehose = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { for (int i = 0; i < m; i++) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeAmbTest.java b/src/test/java/rx/internal/operators/OnSubscribeAmbTest.java index c3e7480fa7..7f9bf0ff49 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeAmbTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeAmbTest.java @@ -51,7 +51,7 @@ public void setUp() { private Observable createObservable(final String[] values, final long interval, final Throwable e) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber subscriber) { @@ -90,7 +90,7 @@ public void testAmb() { Observable observable3 = createObservable(new String[] { "3", "33", "333", "3333" }, 3000, null); - Observable o = Observable.create(amb(observable1, + Observable o = Observable.unsafeCreate(amb(observable1, observable2, observable3)); @SuppressWarnings("unchecked") @@ -119,7 +119,7 @@ public void testAmb2() { Observable observable3 = createObservable(new String[] {}, 3000, new IOException("fake exception")); - Observable o = Observable.create(amb(observable1, + Observable o = Observable.unsafeCreate(amb(observable1, observable2, observable3)); @SuppressWarnings("unchecked") @@ -146,7 +146,7 @@ public void testAmb3() { Observable observable3 = createObservable(new String[] { "3" }, 3000, null); - Observable o = Observable.create(amb(observable1, + Observable o = Observable.unsafeCreate(amb(observable1, observable2, observable3)); @SuppressWarnings("unchecked") @@ -165,7 +165,7 @@ public void testProducerRequestThroughAmb() { ts.requestMore(3); final AtomicLong requested1 = new AtomicLong(); final AtomicLong requested2 = new AtomicLong(); - Observable o1 = Observable.create(new OnSubscribe() { + Observable o1 = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -181,7 +181,7 @@ public void request(long n) { } }); - Observable o2 = Observable.create(new OnSubscribe() { + Observable o2 = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeCollectTest.java b/src/test/java/rx/internal/operators/OnSubscribeCollectTest.java index 859ecd63c9..75d6b51954 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeCollectTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeCollectTest.java @@ -130,7 +130,7 @@ public void call(Throwable t) { final RuntimeException e1 = new RuntimeException(); final RuntimeException e2 = new RuntimeException(); TestSubscriber> ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -171,7 +171,7 @@ public void call(List t1, Integer t2) { public void testCollectorFailureDoesNotResultInErrorAndCompletedEmissions() { final RuntimeException e1 = new RuntimeException(); TestSubscriber> ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -209,7 +209,7 @@ public void testCollectorFailureDoesNotResultInErrorAndOnNextEmissions() { final RuntimeException e1 = new RuntimeException(); TestSubscriber> ts = TestSubscriber.create(); final AtomicBoolean added = new AtomicBoolean(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeFromEmitterTest.java b/src/test/java/rx/internal/operators/OnSubscribeCreateTest.java similarity index 80% rename from src/test/java/rx/internal/operators/OnSubscribeFromEmitterTest.java rename to src/test/java/rx/internal/operators/OnSubscribeCreateTest.java index 8298625a9b..2d8e5f843c 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeFromEmitterTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeCreateTest.java @@ -32,7 +32,7 @@ import rx.plugins.RxJavaHooks; import rx.subjects.PublishSubject; -public class OnSubscribeFromEmitterTest { +public class OnSubscribeCreateTest { PublishEmitter source; @@ -49,7 +49,7 @@ public void before() { @Test public void normalBuffered() { - Observable.fromEmitter(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); source.onNext(1); source.onNext(2); @@ -70,7 +70,7 @@ public void normalBuffered() { @Test public void normalDrop() { - Observable.fromEmitter(source, Emitter.BackpressureMode.DROP).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.DROP).subscribe(ts); source.onNext(1); @@ -86,7 +86,7 @@ public void normalDrop() { @Test public void normalLatest() { - Observable.fromEmitter(source, Emitter.BackpressureMode.LATEST).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.LATEST).subscribe(ts); source.onNext(1); @@ -102,7 +102,7 @@ public void normalLatest() { @Test public void normalNone() { - Observable.fromEmitter(source, Emitter.BackpressureMode.NONE).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.NONE).subscribe(ts); source.onNext(1); source.onNext(2); @@ -115,7 +115,7 @@ public void normalNone() { @Test public void normalNoneRequested() { - Observable.fromEmitter(source, Emitter.BackpressureMode.NONE).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.NONE).subscribe(ts); ts.requestMore(2); source.onNext(1); @@ -130,7 +130,7 @@ public void normalNoneRequested() { @Test public void normalError() { - Observable.fromEmitter(source, Emitter.BackpressureMode.ERROR).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.ERROR).subscribe(ts); source.onNext(1); source.onNext(2); @@ -140,7 +140,7 @@ public void normalError() { ts.assertError(MissingBackpressureException.class); ts.assertNotCompleted(); - Assert.assertEquals("fromEmitter: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); + Assert.assertEquals("create: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); } @Test @@ -153,13 +153,13 @@ public void call(Emitter emitter) { //don't check for unsubscription emitter.onNext(2); }}; - Observable.fromEmitter(source, Emitter.BackpressureMode.ERROR).unsafeSubscribe(ts); + Observable.create(source, Emitter.BackpressureMode.ERROR).unsafeSubscribe(ts); ts.assertNoValues(); ts.assertError(MissingBackpressureException.class); ts.assertNotCompleted(); - Assert.assertEquals("fromEmitter: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); + Assert.assertEquals("create: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); } @Test @@ -172,13 +172,13 @@ public void call(Emitter emitter) { //don't check for unsubscription emitter.onCompleted(); }}; - Observable.fromEmitter(source, Emitter.BackpressureMode.ERROR).unsafeSubscribe(ts); + Observable.create(source, Emitter.BackpressureMode.ERROR).unsafeSubscribe(ts); ts.assertNoValues(); ts.assertError(MissingBackpressureException.class); ts.assertNotCompleted(); - Assert.assertEquals("fromEmitter: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); + Assert.assertEquals("create: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); } @Test @@ -199,13 +199,13 @@ public void call(Emitter emitter) { //don't check for unsubscription emitter.onError(e); }}; - Observable.fromEmitter(source, Emitter.BackpressureMode.ERROR).unsafeSubscribe(ts); + Observable.create(source, Emitter.BackpressureMode.ERROR).unsafeSubscribe(ts); ts.assertNoValues(); ts.assertError(MissingBackpressureException.class); ts.assertNotCompleted(); - Assert.assertEquals("fromEmitter: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); + Assert.assertEquals("create: could not emit value due to lack of requests", ts.getOnErrorEvents().get(0).getMessage()); assertEquals(Arrays.asList(e), list); } finally { RxJavaHooks.reset(); @@ -214,7 +214,7 @@ public void call(Emitter emitter) { @Test public void errorBuffered() { - Observable.fromEmitter(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); source.onNext(1); source.onNext(2); @@ -233,7 +233,7 @@ public void errorBuffered() { @Test public void errorLatest() { - Observable.fromEmitter(source, Emitter.BackpressureMode.LATEST).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.LATEST).subscribe(ts); source.onNext(1); source.onNext(2); @@ -248,7 +248,7 @@ public void errorLatest() { @Test public void errorNone() { - Observable.fromEmitter(source, Emitter.BackpressureMode.NONE).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.NONE).subscribe(ts); source.onNext(1); source.onNext(2); @@ -263,7 +263,7 @@ public void errorNone() { @Test public void unsubscribedBuffer() { - Observable.fromEmitter(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); ts.unsubscribe(); source.onNext(1); @@ -279,7 +279,7 @@ public void unsubscribedBuffer() { @Test public void unsubscribedLatest() { - Observable.fromEmitter(source, Emitter.BackpressureMode.LATEST).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.LATEST).subscribe(ts); ts.unsubscribe(); source.onNext(1); @@ -295,7 +295,7 @@ public void unsubscribedLatest() { @Test public void unsubscribedError() { - Observable.fromEmitter(source, Emitter.BackpressureMode.ERROR).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.ERROR).subscribe(ts); ts.unsubscribe(); source.onNext(1); @@ -311,7 +311,7 @@ public void unsubscribedError() { @Test public void unsubscribedDrop() { - Observable.fromEmitter(source, Emitter.BackpressureMode.DROP).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.DROP).subscribe(ts); ts.unsubscribe(); source.onNext(1); @@ -327,7 +327,7 @@ public void unsubscribedDrop() { @Test public void unsubscribedNone() { - Observable.fromEmitter(source, Emitter.BackpressureMode.NONE).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.NONE).subscribe(ts); ts.unsubscribe(); source.onNext(1); @@ -343,7 +343,7 @@ public void unsubscribedNone() { @Test public void unsubscribedNoCancelBuffer() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); ts.unsubscribe(); sourceNoCancel.onNext(1); @@ -359,7 +359,7 @@ public void unsubscribedNoCancelBuffer() { @Test public void unsubscribedNoCancelLatest() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); ts.unsubscribe(); sourceNoCancel.onNext(1); @@ -375,7 +375,7 @@ public void unsubscribedNoCancelLatest() { @Test public void unsubscribedNoCancelError() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.ERROR).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.ERROR).subscribe(ts); ts.unsubscribe(); sourceNoCancel.onNext(1); @@ -391,7 +391,7 @@ public void unsubscribedNoCancelError() { @Test public void unsubscribedNoCancelDrop() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.DROP).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.DROP).subscribe(ts); ts.unsubscribe(); sourceNoCancel.onNext(1); @@ -407,7 +407,7 @@ public void unsubscribedNoCancelDrop() { @Test public void unsubscribedNoCancelNone() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.NONE).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.NONE).subscribe(ts); ts.unsubscribe(); sourceNoCancel.onNext(1); @@ -423,7 +423,7 @@ public void unsubscribedNoCancelNone() { @Test public void deferredRequest() { - Observable.fromEmitter(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); source.onNext(1); source.onNext(2); @@ -438,7 +438,7 @@ public void deferredRequest() { @Test public void take() { - Observable.fromEmitter(source, Emitter.BackpressureMode.BUFFER).take(2).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.BUFFER).take(2).subscribe(ts); source.onNext(1); source.onNext(2); @@ -453,7 +453,7 @@ public void take() { @Test public void takeOne() { - Observable.fromEmitter(source, Emitter.BackpressureMode.BUFFER).take(1).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.BUFFER).take(1).subscribe(ts); ts.requestMore(2); source.onNext(1); @@ -467,7 +467,7 @@ public void takeOne() { @Test public void requestExact() { - Observable.fromEmitter(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(source, Emitter.BackpressureMode.BUFFER).subscribe(ts); ts.requestMore(2); source.onNext(1); @@ -481,7 +481,7 @@ public void requestExact() { @Test public void takeNoCancel() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).take(2).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).take(2).subscribe(ts); sourceNoCancel.onNext(1); sourceNoCancel.onNext(2); @@ -496,7 +496,7 @@ public void takeNoCancel() { @Test public void takeOneNoCancel() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).take(1).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).take(1).subscribe(ts); ts.requestMore(2); sourceNoCancel.onNext(1); @@ -510,7 +510,7 @@ public void takeOneNoCancel() { @Test public void unsubscribeNoCancel() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); ts.requestMore(2); sourceNoCancel.onNext(1); @@ -535,7 +535,7 @@ public void onNext(Integer t) { } }; - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts1); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts1); sourceNoCancel.onNext(1); @@ -546,7 +546,7 @@ public void onNext(Integer t) { @Test public void completeInline() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); sourceNoCancel.onNext(1); sourceNoCancel.onCompleted(); @@ -560,7 +560,7 @@ public void completeInline() { @Test public void errorInline() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts); sourceNoCancel.onNext(1); sourceNoCancel.onError(new TestException()); @@ -582,7 +582,7 @@ public void onNext(Integer t) { } }; - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts1); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.BUFFER).subscribe(ts1); sourceNoCancel.onNext(1); sourceNoCancel.onNext(2); @@ -602,7 +602,7 @@ public void onNext(Integer t) { } }; - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts1); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts1); sourceNoCancel.onNext(1); @@ -621,7 +621,7 @@ public void onNext(Integer t) { } }; - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts1); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts1); sourceNoCancel.onNext(1); @@ -632,7 +632,7 @@ public void onNext(Integer t) { @Test public void completeInlineLatest() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); sourceNoCancel.onNext(1); sourceNoCancel.onCompleted(); @@ -646,7 +646,7 @@ public void completeInlineLatest() { @Test public void completeInlineExactLatest() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); sourceNoCancel.onNext(1); sourceNoCancel.onCompleted(); @@ -660,7 +660,7 @@ public void completeInlineExactLatest() { @Test public void errorInlineLatest() { - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts); sourceNoCancel.onNext(1); sourceNoCancel.onError(new TestException()); @@ -682,7 +682,7 @@ public void onNext(Integer t) { } }; - Observable.fromEmitter(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts1); + Observable.create(sourceNoCancel, Emitter.BackpressureMode.LATEST).subscribe(ts1); sourceNoCancel.onNext(1); sourceNoCancel.onNext(2); diff --git a/src/test/java/rx/internal/operators/OnSubscribeDetachTest.java b/src/test/java/rx/internal/operators/OnSubscribeDetachTest.java index 6d06019425..7d435bff79 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeDetachTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeDetachTest.java @@ -138,7 +138,7 @@ public void deferredUpstreamProducer() { TestSubscriber ts = new TestSubscriber(0); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { subscriber.set(t); diff --git a/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java b/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java index 8cf5bdd2cc..bec5c4daab 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeDoOnEachTest.java @@ -178,7 +178,7 @@ public void testFatalError() { .flatMap(new Func1>() { @Override public Observable call(Integer integer) { - return Observable.create(new Observable.OnSubscribe() { + return Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber o) { throw new NullPointerException("Test NPE"); @@ -229,7 +229,7 @@ public void call(Throwable e) { public void testIfOnNextActionFailsEmitsErrorAndDoesNotFollowWithCompleted() { TestSubscriber ts = TestSubscriber.create(); final RuntimeException e1 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber subscriber) { @@ -259,7 +259,7 @@ public void call(Integer t) { public void testIfOnNextActionFailsEmitsErrorAndDoesNotFollowWithOnNext() { TestSubscriber ts = TestSubscriber.create(); final RuntimeException e1 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber subscriber) { @@ -298,7 +298,7 @@ public void call(Throwable e) { TestSubscriber ts = TestSubscriber.create(); final RuntimeException e1 = new RuntimeException(); final RuntimeException e2 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber subscriber) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeFromArrayTest.java b/src/test/java/rx/internal/operators/OnSubscribeFromArrayTest.java index cd117169d2..1d5368f097 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeFromArrayTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeFromArrayTest.java @@ -29,7 +29,7 @@ Observable create(int n) { for (int i = 0; i < n; i++) { array[i] = i; } - return Observable.create(new OnSubscribeFromArray(array)); + return Observable.unsafeCreate(new OnSubscribeFromArray(array)); } @Test public void simple() { diff --git a/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java b/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java index 43993ca137..0464ed8dc0 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java @@ -38,12 +38,12 @@ public class OnSubscribeFromIterableTest { @Test(expected = NullPointerException.class) public void testNull() { - Observable.create(new OnSubscribeFromIterable(null)); + Observable.unsafeCreate(new OnSubscribeFromIterable(null)); } @Test public void testListIterable() { - Observable observable = Observable.create(new OnSubscribeFromIterable(Arrays. asList("one", "two", "three"))); + Observable observable = Observable.unsafeCreate(new OnSubscribeFromIterable(Arrays. asList("one", "two", "three"))); @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); @@ -86,7 +86,7 @@ public void remove() { } }; - Observable observable = Observable.create(new OnSubscribeFromIterable(it)); + Observable observable = Observable.unsafeCreate(new OnSubscribeFromIterable(it)); @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); diff --git a/src/test/java/rx/internal/operators/OnSubscribeMapTest.java b/src/test/java/rx/internal/operators/OnSubscribeMapTest.java index 6477bdbdc5..12c24cb303 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeMapTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeMapTest.java @@ -299,7 +299,7 @@ public void call(Object object) { }; try { - Observable.create(creator).flatMap(manyMapper).map(mapper).subscribe(onNext); + Observable.unsafeCreate(creator).flatMap(manyMapper).map(mapper).subscribe(onNext); } catch (RuntimeException e) { e.printStackTrace(); throw e; diff --git a/src/test/java/rx/internal/operators/OnSubscribeReduceTest.java b/src/test/java/rx/internal/operators/OnSubscribeReduceTest.java index 9ae07b6112..7d0f1a6cc3 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeReduceTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeReduceTest.java @@ -145,7 +145,7 @@ public void testBackpressureWithInitialValue() throws InterruptedException { @Test public void testNoInitialValueDoesNotEmitMultipleTerminalEvents() { TestSubscriber ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -176,7 +176,7 @@ public Integer call(Integer a, Integer b) { @Test public void testNoInitialValueUpstreamEmitsMoreOnNextDespiteUnsubscription() { TestSubscriber ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -226,7 +226,7 @@ public void call(Throwable t) { TestSubscriber ts = TestSubscriber.create(); final RuntimeException e1 = new RuntimeException("e1"); final Throwable e2 = new RuntimeException("e2"); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java b/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java index e0761a576a..a64f808e78 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java @@ -322,7 +322,7 @@ public void call() { } private Observable synchronousInterval() { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber subscriber) { @@ -341,7 +341,7 @@ public void call(Subscriber subscriber) { public void onlyFirstShouldSubscribeAndLastUnsubscribe() { final AtomicInteger subscriptionCount = new AtomicInteger(); final AtomicInteger unsubscriptionCount = new AtomicInteger(); - Observable observable = Observable.create(new OnSubscribe() { + Observable observable = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { subscriptionCount.incrementAndGet(); diff --git a/src/test/java/rx/internal/operators/OnSubscribeToMapTest.java b/src/test/java/rx/internal/operators/OnSubscribeToMapTest.java index 1ed6a542a8..97b7f33673 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeToMapTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeToMapTest.java @@ -301,7 +301,7 @@ public Map call() { public void testFactoryFailureDoesNotAllowErrorAndCompletedEmissions() { TestSubscriber> ts = TestSubscriber.create(0); final RuntimeException e = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -342,7 +342,7 @@ public void call(Throwable t) { TestSubscriber> ts = TestSubscriber.create(0); final RuntimeException e1 = new RuntimeException(); final RuntimeException e2 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -377,7 +377,7 @@ public Integer call(Integer t) { public void testFactoryFailureDoesNotAllowErrorThenOnNextEmissions() { TestSubscriber> ts = TestSubscriber.create(0); final RuntimeException e = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeToMultimapTest.java b/src/test/java/rx/internal/operators/OnSubscribeToMultimapTest.java index 91fb03c0be..a27c2ae662 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeToMultimapTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeToMultimapTest.java @@ -395,7 +395,7 @@ public Collection call(Integer k) { public void testKeySelectorFailureDoesNotAllowErrorAndCompletedEmissions() { TestSubscriber>> ts = TestSubscriber.create(0); final RuntimeException e = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -436,7 +436,7 @@ public void call(Throwable t) { TestSubscriber>> ts = TestSubscriber.create(0); final RuntimeException e1 = new RuntimeException(); final RuntimeException e2 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -471,7 +471,7 @@ public Integer call(Integer t) { public void testFactoryFailureDoesNotAllowErrorThenOnNextEmissions() { TestSubscriber>> ts = TestSubscriber.create(0); final RuntimeException e = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java b/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java index e169cbb68e..3a93d4cc8f 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeUsingTest.java @@ -254,7 +254,7 @@ public Subscription call() { Func1> observableFactory = new Func1>() { @Override public Observable call(Subscription subscription) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { throw new TestException(); diff --git a/src/test/java/rx/internal/operators/OperatorAllTest.java b/src/test/java/rx/internal/operators/OperatorAllTest.java index 0ca615d515..5ac74526fa 100644 --- a/src/test/java/rx/internal/operators/OperatorAllTest.java +++ b/src/test/java/rx/internal/operators/OperatorAllTest.java @@ -186,7 +186,7 @@ public Boolean call(Object object) { @Test public void testDoesNotEmitMultipleTerminalEvents() { TestSubscriber ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -216,7 +216,7 @@ public Boolean call(Integer t) { @Test public void testUpstreamEmitsOnNextAfterFailureWithoutCheckingSubscription() { TestSubscriber ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -263,7 +263,7 @@ public void call(Throwable t) { TestSubscriber ts = TestSubscriber.create(); final RuntimeException e1 = new RuntimeException(); final Throwable e2 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OperatorAnyTest.java b/src/test/java/rx/internal/operators/OperatorAnyTest.java index 776d6e8f72..0eaf6b07ec 100644 --- a/src/test/java/rx/internal/operators/OperatorAnyTest.java +++ b/src/test/java/rx/internal/operators/OperatorAnyTest.java @@ -278,7 +278,7 @@ public Boolean call(Object object) { @Test public void testUpstreamEmitsOnNextAfterFailureWithoutCheckingSubscription() { TestSubscriber ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -314,7 +314,7 @@ public Boolean call(Integer t) { @Test public void testUpstreamEmitsOnNextWithoutCheckingSubscription() { TestSubscriber ts = TestSubscriber.create(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -356,7 +356,7 @@ public void call(Throwable t) { TestSubscriber ts = TestSubscriber.create(); final RuntimeException e1 = new RuntimeException(); final Throwable e2 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OperatorBufferTest.java b/src/test/java/rx/internal/operators/OperatorBufferTest.java index 99f4cf5c0f..5cd3b2fa96 100644 --- a/src/test/java/rx/internal/operators/OperatorBufferTest.java +++ b/src/test/java/rx/internal/operators/OperatorBufferTest.java @@ -52,7 +52,7 @@ public void before() { @Test public void testComplete() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { observer.onCompleted(); @@ -69,7 +69,7 @@ public void call(Subscriber observer) { @Test public void testSkipAndCountOverlappingBuffers() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { observer.onNext("one"); @@ -94,7 +94,7 @@ public void call(Subscriber observer) { @Test public void testSkipAndCountGaplessBuffers() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { observer.onNext("one"); @@ -119,7 +119,7 @@ public void call(Subscriber observer) { @Test public void testSkipAndCountBuffersWithGaps() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { observer.onNext("one"); @@ -144,7 +144,7 @@ public void call(Subscriber observer) { @Test public void testTimedAndCount() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 10); @@ -175,7 +175,7 @@ public void call(Subscriber observer) { @Test public void testTimed() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 97); @@ -208,7 +208,7 @@ public void call(Subscriber observer) { @Test public void testObservableBasedOpenerAndCloser() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 10); @@ -220,7 +220,7 @@ public void call(Subscriber observer) { } }); - Observable openings = Observable.create(new Observable.OnSubscribe() { + Observable openings = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, new Object(), 50); @@ -232,7 +232,7 @@ public void call(Subscriber observer) { Func1> closer = new Func1>() { @Override public Observable call(Object opening) { - return Observable.create(new Observable.OnSubscribe() { + return Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, new Object(), 100); @@ -256,7 +256,7 @@ public void call(Subscriber observer) { @Test public void testObservableBasedCloser() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 10); @@ -271,7 +271,7 @@ public void call(Subscriber observer) { Func0> closer = new Func0>() { @Override public Observable call() { - return Observable.create(new Observable.OnSubscribe() { + return Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, new Object(), 100); @@ -786,7 +786,7 @@ public void testProducerRequestThroughBufferWithSize1() { TestSubscriber> ts = new TestSubscriber>(); ts.requestMore(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s) { @@ -811,7 +811,7 @@ public void request(long n) { public void testProducerRequestThroughBufferWithSize2() { TestSubscriber> ts = new TestSubscriber>(); final AtomicLong requested = new AtomicLong(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s) { @@ -834,7 +834,7 @@ public void testProducerRequestThroughBufferWithSize3() { TestSubscriber> ts = new TestSubscriber>(); ts.requestMore(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s) { @@ -858,7 +858,7 @@ public void request(long n) { public void testProducerRequestThroughBufferWithSize4() { TestSubscriber> ts = new TestSubscriber>(); final AtomicLong requested = new AtomicLong(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s) { @@ -882,7 +882,7 @@ public void testProducerRequestOverflowThroughBufferWithSize1() { TestSubscriber> ts = new TestSubscriber>(); ts.requestMore(Long.MAX_VALUE / 2); final AtomicLong requested = new AtomicLong(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s) { @@ -905,7 +905,7 @@ public void testProducerRequestOverflowThroughBufferWithSize2() { TestSubscriber> ts = new TestSubscriber>(); ts.requestMore(Long.MAX_VALUE / 2); final AtomicLong requested = new AtomicLong(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber s) { @@ -926,7 +926,7 @@ public void request(long n) { @Test public void testProducerRequestOverflowThroughBufferWithSize3() { final AtomicLong requested = new AtomicLong(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OperatorConcatTest.java b/src/test/java/rx/internal/operators/OperatorConcatTest.java index 564eb9e709..1e818accda 100644 --- a/src/test/java/rx/internal/operators/OperatorConcatTest.java +++ b/src/test/java/rx/internal/operators/OperatorConcatTest.java @@ -115,7 +115,7 @@ public void testConcatObservableOfObservables() { final Observable odds = Observable.from(o); final Observable even = Observable.from(e); - Observable> observableOfObservables = Observable.create(new Observable.OnSubscribe>() { + Observable> observableOfObservables = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { @@ -144,7 +144,7 @@ public void testSimpleAsyncConcat() { TestObservable o1 = new TestObservable("one", "two", "three"); TestObservable o2 = new TestObservable("four", "five", "six"); - Observable.concat(Observable.create(o1), Observable.create(o2)).subscribe(observer); + Observable.concat(Observable.unsafeCreate(o1), Observable.unsafeCreate(o2)).subscribe(observer); try { // wait for async observables to complete @@ -179,7 +179,7 @@ public void testNestedAsyncConcat() throws Throwable { final AtomicReference parent = new AtomicReference(); final CountDownLatch parentHasStarted = new CountDownLatch(1); - Observable> observableOfObservables = Observable.create(new Observable.OnSubscribe>() { + Observable> observableOfObservables = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(final Subscriber> observer) { @@ -193,12 +193,12 @@ public void run() { // emit first if (!s.isUnsubscribed()) { System.out.println("Emit o1"); - observer.onNext(Observable.create(o1)); + observer.onNext(Observable.unsafeCreate(o1)); } // emit second if (!s.isUnsubscribed()) { System.out.println("Emit o2"); - observer.onNext(Observable.create(o2)); + observer.onNext(Observable.unsafeCreate(o2)); } // wait until sometime later and emit third @@ -209,7 +209,7 @@ public void run() { } if (!s.isUnsubscribed()) { System.out.println("Emit o3"); - observer.onNext(Observable.create(o3)); + observer.onNext(Observable.unsafeCreate(o3)); } } catch (Throwable e) { @@ -285,7 +285,7 @@ public void testBlockedObservableOfObservables() { final CountDownLatch callOnce = new CountDownLatch(1); final CountDownLatch okToContinue = new CountDownLatch(1); TestObservable> observableOfObservables = new TestObservable>(callOnce, okToContinue, odds, even); - Observable concatF = Observable.concat(Observable.create(observableOfObservables)); + Observable concatF = Observable.concat(Observable.unsafeCreate(observableOfObservables)); concatF.subscribe(observer); try { //Block main thread to allow observables to serve up o1. @@ -323,8 +323,8 @@ public void testConcatConcurrentWithInfinity() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); @SuppressWarnings("unchecked") - TestObservable> observableOfObservables = new TestObservable>(Observable.create(w1), Observable.create(w2)); - Observable concatF = Observable.concat(Observable.create(observableOfObservables)); + TestObservable> observableOfObservables = new TestObservable>(Observable.unsafeCreate(w1), Observable.unsafeCreate(w2)); + Observable concatF = Observable.concat(Observable.unsafeCreate(observableOfObservables)); concatF.take(50).subscribe(observer); @@ -357,13 +357,13 @@ public void testConcatNonBlockingObservables() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable> observableOfObservables = Observable.create(new Observable.OnSubscribe>() { + Observable> observableOfObservables = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { // simulate what would happen in an observable - observer.onNext(Observable.create(w1)); - observer.onNext(Observable.create(w2)); + observer.onNext(Observable.unsafeCreate(w1)); + observer.onNext(Observable.unsafeCreate(w2)); observer.onCompleted(); } @@ -408,7 +408,7 @@ public void testConcatUnsubscribe() { @SuppressWarnings("unchecked") final Observer observer = mock(Observer.class); - final Observable concat = Observable.concat(Observable.create(w1), Observable.create(w2)); + final Observable concat = Observable.concat(Observable.unsafeCreate(w1), Observable.unsafeCreate(w2)); try { // Subscribe @@ -450,8 +450,8 @@ public void testConcatUnsubscribeConcurrent() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); @SuppressWarnings("unchecked") - TestObservable> observableOfObservables = new TestObservable>(Observable.create(w1), Observable.create(w2)); - Observable concatF = Observable.concat(Observable.create(observableOfObservables)); + TestObservable> observableOfObservables = new TestObservable>(Observable.unsafeCreate(w1), Observable.unsafeCreate(w2)); + Observable concatF = Observable.concat(Observable.unsafeCreate(observableOfObservables)); Subscription s1 = concatF.subscribe(observer); @@ -618,7 +618,7 @@ public void testMultipleObservers() { @Test public void concatVeryLongObservableOfObservables() { final int n = 10000; - Observable> source = Observable.create(new OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new OnSubscribe>() { @Override public void call(Subscriber> s) { for (int i = 0; i < n; i++) { @@ -650,7 +650,7 @@ public void call(Subscriber> s) { @Test public void concatVeryLongObservableOfObservablesTakeHalf() { final int n = 10000; - Observable> source = Observable.create(new OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new OnSubscribe>() { @Override public void call(Subscriber> s) { for (int i = 0; i < n; i++) { @@ -724,7 +724,7 @@ public void testInnerBackpressureWithoutAlignedBoundaries() { // https://github.com/ReactiveX/RxJava/issues/1818 @Test public void testConcatWithNonCompliantSourceDoubleOnComplete() { - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OperatorDebounceTest.java b/src/test/java/rx/internal/operators/OperatorDebounceTest.java index ae509c743d..bf3cad52d5 100644 --- a/src/test/java/rx/internal/operators/OperatorDebounceTest.java +++ b/src/test/java/rx/internal/operators/OperatorDebounceTest.java @@ -57,7 +57,7 @@ public void before() { @Test public void testDebounceWithCompleted() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 100, "one"); // Should be skipped since "two" will arrive before the timeout expires. @@ -82,7 +82,7 @@ public void call(Subscriber observer) { @Test public void testDebounceNeverEmits() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { // all should be skipped since they are happening faster than the 200ms timeout @@ -111,7 +111,7 @@ public void call(Subscriber observer) { @Test public void testDebounceWithError() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { Exception error = new TestException(); diff --git a/src/test/java/rx/internal/operators/OperatorDoOnRequestTest.java b/src/test/java/rx/internal/operators/OperatorDoOnRequestTest.java index e471376e93..d1ddd22c85 100644 --- a/src/test/java/rx/internal/operators/OperatorDoOnRequestTest.java +++ b/src/test/java/rx/internal/operators/OperatorDoOnRequestTest.java @@ -99,7 +99,7 @@ public void dontRequestIfDownstreamRequestsLate() { final AtomicReference producer = new AtomicReference(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { t.setProducer(new Producer() { diff --git a/src/test/java/rx/internal/operators/OperatorDoOnSubscribeTest.java b/src/test/java/rx/internal/operators/OperatorDoOnSubscribeTest.java index 4765a5dfe3..2f60a9e8c5 100644 --- a/src/test/java/rx/internal/operators/OperatorDoOnSubscribeTest.java +++ b/src/test/java/rx/internal/operators/OperatorDoOnSubscribeTest.java @@ -76,7 +76,7 @@ public void testDoOnUnSubscribeWorksWithRefCount() throws Exception { final AtomicInteger countBefore = new AtomicInteger(); final AtomicInteger countAfter = new AtomicInteger(); final AtomicReference> sref = new AtomicReference>(); - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OperatorGroupByTest.java b/src/test/java/rx/internal/operators/OperatorGroupByTest.java index 1cad5330c3..5d035bcd82 100644 --- a/src/test/java/rx/internal/operators/OperatorGroupByTest.java +++ b/src/test/java/rx/internal/operators/OperatorGroupByTest.java @@ -189,7 +189,7 @@ public void testGroupedEventStream() throws Throwable { final int count = 100; final int groupCount = 2; - Observable es = Observable.create(new Observable.OnSubscribe() { + Observable es = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -602,7 +602,7 @@ public void call(String s) { public void testFirstGroupsCompleteAndParentSlowToThenEmitFinalGroupsAndThenComplete() throws InterruptedException { final CountDownLatch first = new CountDownLatch(2); // there are two groups to first complete final ArrayList results = new ArrayList(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber sub) { @@ -680,7 +680,7 @@ public void testFirstGroupsCompleteAndParentSlowToThenEmitFinalGroupsWhichThenSu System.err.println("----------------------------------------------------------------------------------------------"); final CountDownLatch first = new CountDownLatch(2); // there are two groups to first complete final ArrayList results = new ArrayList(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber sub) { @@ -771,7 +771,7 @@ public void call(String s) { public void testFirstGroupsCompleteAndParentSlowToThenEmitFinalGroupsWhichThenObservesOnAndDelaysAndThenCompletes() throws InterruptedException { final CountDownLatch first = new CountDownLatch(2); // there are two groups to first complete final ArrayList results = new ArrayList(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber sub) { @@ -847,7 +847,7 @@ public void call(String s) { @Test public void testGroupsWithNestedSubscribeOn() throws InterruptedException { final ArrayList results = new ArrayList(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber sub) { @@ -903,7 +903,7 @@ public void call(String s) { @Test public void testGroupsWithNestedObserveOn() throws InterruptedException { final ArrayList results = new ArrayList(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber sub) { @@ -963,7 +963,7 @@ Observable ASYNC_INFINITE_OBSERVABLE_OF_EVENT(final int numGroups, final } Observable SYNC_INFINITE_OBSERVABLE_OF_EVENT(final int numGroups, final AtomicInteger subscribeCounter, final AtomicInteger sentEventCounter) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber op) { @@ -1375,7 +1375,7 @@ public void call(String s) { @Test public void testGroupByUnsubscribe() { final Subscription s = mock(Subscription.class); - Observable o = Observable.create( + Observable o = Observable.unsafeCreate( new OnSubscribe() { @Override public void call(Subscriber subscriber) { @@ -1419,7 +1419,7 @@ public void onNext(GroupedObservable o) { } } }); - Observable.create( + Observable.unsafeCreate( new OnSubscribe() { @Override public void call(Subscriber subscriber) { diff --git a/src/test/java/rx/internal/operators/OperatorMaterializeTest.java b/src/test/java/rx/internal/operators/OperatorMaterializeTest.java index af090b4379..437593d313 100644 --- a/src/test/java/rx/internal/operators/OperatorMaterializeTest.java +++ b/src/test/java/rx/internal/operators/OperatorMaterializeTest.java @@ -43,7 +43,7 @@ public void testMaterialize1() { "three"); TestObserver Observer = new TestObserver(); - Observable> m = Observable.create(o1).materialize(); + Observable> m = Observable.unsafeCreate(o1).materialize(); m.subscribe(Observer); try { @@ -69,7 +69,7 @@ public void testMaterialize2() { final TestAsyncErrorObservable o1 = new TestAsyncErrorObservable("one", "two", "three"); TestObserver Observer = new TestObserver(); - Observable> m = Observable.create(o1).materialize(); + Observable> m = Observable.unsafeCreate(o1).materialize(); m.subscribe(Observer); try { @@ -94,7 +94,7 @@ public void testMaterialize2() { public void testMultipleSubscribes() throws InterruptedException, ExecutionException { final TestAsyncErrorObservable o = new TestAsyncErrorObservable("one", "two", null, "three"); - Observable> m = Observable.create(o).materialize(); + Observable> m = Observable.unsafeCreate(o).materialize(); assertEquals(3, m.toList().toBlocking().toFuture().get().size()); assertEquals(3, m.toList().toBlocking().toFuture().get().size()); diff --git a/src/test/java/rx/internal/operators/OperatorMergeDelayErrorTest.java b/src/test/java/rx/internal/operators/OperatorMergeDelayErrorTest.java index 7943e30dee..05326cf75a 100644 --- a/src/test/java/rx/internal/operators/OperatorMergeDelayErrorTest.java +++ b/src/test/java/rx/internal/operators/OperatorMergeDelayErrorTest.java @@ -55,8 +55,8 @@ public void before() { @Test public void testErrorDelayed1() { - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", "three")); + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("one", "two", "three")); Observable m = Observable.mergeDelayError(o1, o2); m.subscribe(stringObserver); @@ -76,10 +76,10 @@ public void testErrorDelayed1() { @Test public void testErrorDelayed2() { - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null)); - final Observable o4 = Observable.create(new TestErrorObservable("nine")); + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o3 = Observable.unsafeCreate(new TestErrorObservable("seven", "eight", null)); + final Observable o4 = Observable.unsafeCreate(new TestErrorObservable("nine")); Observable m = Observable.mergeDelayError(o1, o2, o3, o4); m.subscribe(stringObserver); @@ -101,10 +101,10 @@ public void testErrorDelayed2() { @Test public void testErrorDelayed3() { - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", "five", "six")); - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null)); - final Observable o4 = Observable.create(new TestErrorObservable("nine")); + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("four", "five", "six")); + final Observable o3 = Observable.unsafeCreate(new TestErrorObservable("seven", "eight", null)); + final Observable o4 = Observable.unsafeCreate(new TestErrorObservable("nine")); Observable m = Observable.mergeDelayError(o1, o2, o3, o4); m.subscribe(stringObserver); @@ -124,10 +124,10 @@ public void testErrorDelayed3() { @Test public void testErrorDelayed4() { - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", "five", "six")); - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight")); - final Observable o4 = Observable.create(new TestErrorObservable("nine", null)); + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("four", "five", "six")); + final Observable o3 = Observable.unsafeCreate(new TestErrorObservable("seven", "eight")); + final Observable o4 = Observable.unsafeCreate(new TestErrorObservable("nine", null)); Observable m = Observable.mergeDelayError(o1, o2, o3, o4); m.subscribe(stringObserver); @@ -153,7 +153,7 @@ public void testErrorDelayed4WithThreading() { // throw the error at the very end so no onComplete will be called after it final TestAsyncErrorObservable o4 = new TestAsyncErrorObservable("nine", null); - Observable m = Observable.mergeDelayError(Observable.create(o1), Observable.create(o2), Observable.create(o3), Observable.create(o4)); + Observable m = Observable.mergeDelayError(Observable.unsafeCreate(o1), Observable.unsafeCreate(o2), Observable.unsafeCreate(o3), Observable.unsafeCreate(o4)); m.subscribe(stringObserver); try { @@ -180,8 +180,8 @@ public void testErrorDelayed4WithThreading() { @Test public void testCompositeErrorDelayed1() { - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", null)); + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("one", "two", null)); Observable m = Observable.mergeDelayError(o1, o2); m.subscribe(stringObserver); @@ -200,8 +200,8 @@ public void testCompositeErrorDelayed1() { @Test public void testCompositeErrorDelayed2() { - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", null)); + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("four", null, "six")); // we expect to lose "six" from the source (and it should never be sent by the source since onError was called + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("one", "two", null)); Observable m = Observable.mergeDelayError(o1, o2); CaptureObserver w = new CaptureObserver(); @@ -223,10 +223,10 @@ public void testCompositeErrorDelayed2() { @Test public void testMergeObservableOfObservables() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); + final Observable o1 = Observable.unsafeCreate(new TestSynchronousObservable()); + final Observable o2 = Observable.unsafeCreate(new TestSynchronousObservable()); - Observable> observableOfObservables = Observable.create(new Observable.OnSubscribe>() { + Observable> observableOfObservables = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { @@ -247,8 +247,8 @@ public void call(Subscriber> observer) { @Test public void testMergeArray() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); + final Observable o1 = Observable.unsafeCreate(new TestSynchronousObservable()); + final Observable o2 = Observable.unsafeCreate(new TestSynchronousObservable()); Observable m = Observable.mergeDelayError(o1, o2); m.subscribe(stringObserver); @@ -260,8 +260,8 @@ public void testMergeArray() { @Test public void testMergeList() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); + final Observable o1 = Observable.unsafeCreate(new TestSynchronousObservable()); + final Observable o2 = Observable.unsafeCreate(new TestSynchronousObservable()); List> listOfObservables = new ArrayList>(); listOfObservables.add(o1); listOfObservables.add(o2); @@ -277,8 +277,8 @@ public void testMergeList() { // This is pretty much a clone of testMergeList but with the overloaded MergeDelayError for Iterables @Test public void mergeIterable() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); + final Observable o1 = Observable.unsafeCreate(new TestSynchronousObservable()); + final Observable o2 = Observable.unsafeCreate(new TestSynchronousObservable()); List> listOfObservables = new ArrayList>(); listOfObservables.add(o1); listOfObservables.add(o2); @@ -296,7 +296,7 @@ public void testMergeArrayWithThreading() { final TestASynchronousObservable o1 = new TestASynchronousObservable(); final TestASynchronousObservable o2 = new TestASynchronousObservable(); - Observable m = Observable.mergeDelayError(Observable.create(o1), Observable.create(o2)); + Observable m = Observable.mergeDelayError(Observable.unsafeCreate(o1), Observable.unsafeCreate(o2)); m.subscribe(stringObserver); try { @@ -455,7 +455,7 @@ public void onNext(String args) { } @Test public void testMergeSourceWhichDoesntPropagateExceptionBack() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { try { @@ -527,11 +527,11 @@ public void testErrorInParentObservableDelayed() throws Exception { for (int i = 0; i < 50; i++) { final TestASynchronous1sDelayedObservable o1 = new TestASynchronous1sDelayedObservable(); final TestASynchronous1sDelayedObservable o2 = new TestASynchronous1sDelayedObservable(); - Observable> parentObservable = Observable.create(new Observable.OnSubscribe>() { + Observable> parentObservable = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> op) { - op.onNext(Observable.create(o1)); - op.onNext(Observable.create(o2)); + op.onNext(Observable.unsafeCreate(o1)); + op.onNext(Observable.unsafeCreate(o2)); op.onError(new NullPointerException("throwing exception in parent")); } }); diff --git a/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java b/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java index 56685b1630..21ce364b34 100644 --- a/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java +++ b/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java @@ -72,7 +72,7 @@ public void testMaxConcurrent() { for (int i = 0; i < observableCount; i++) { SubscriptionCheckObservable sco = new SubscriptionCheckObservable(subscriptionCount, maxConcurrent); scos.add(sco); - os.add(Observable.create(sco)); + os.add(Observable.unsafeCreate(sco)); } Iterator iter = Observable.merge(os, maxConcurrent).toBlocking().toIterable().iterator(); diff --git a/src/test/java/rx/internal/operators/OperatorMergeTest.java b/src/test/java/rx/internal/operators/OperatorMergeTest.java index d79649667d..7528cb88d8 100644 --- a/src/test/java/rx/internal/operators/OperatorMergeTest.java +++ b/src/test/java/rx/internal/operators/OperatorMergeTest.java @@ -53,10 +53,10 @@ public void before() { @Test public void testMergeObservableOfObservables() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); + final Observable o1 = Observable.unsafeCreate(new TestSynchronousObservable()); + final Observable o2 = Observable.unsafeCreate(new TestSynchronousObservable()); - Observable> observableOfObservables = Observable.create(new Observable.OnSubscribe>() { + Observable> observableOfObservables = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { @@ -77,8 +77,8 @@ public void call(Subscriber> observer) { @Test public void testMergeArray() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); + final Observable o1 = Observable.unsafeCreate(new TestSynchronousObservable()); + final Observable o2 = Observable.unsafeCreate(new TestSynchronousObservable()); Observable m = Observable.merge(o1, o2); m.subscribe(stringObserver); @@ -90,8 +90,8 @@ public void testMergeArray() { @Test public void testMergeList() { - final Observable o1 = Observable.create(new TestSynchronousObservable()); - final Observable o2 = Observable.create(new TestSynchronousObservable()); + final Observable o1 = Observable.unsafeCreate(new TestSynchronousObservable()); + final Observable o2 = Observable.unsafeCreate(new TestSynchronousObservable()); List> listOfObservables = new ArrayList>(); listOfObservables.add(o1); listOfObservables.add(o2); @@ -110,7 +110,7 @@ public void testUnSubscribeObservableOfObservables() throws InterruptedException final AtomicBoolean unsubscribed = new AtomicBoolean(); final CountDownLatch latch = new CountDownLatch(1); - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(final Subscriber> observer) { @@ -172,7 +172,7 @@ public void testMergeArrayWithThreading() { final TestASynchronousObservable o1 = new TestASynchronousObservable(); final TestASynchronousObservable o2 = new TestASynchronousObservable(); - Observable m = Observable.merge(Observable.create(o1), Observable.create(o2)); + Observable m = Observable.merge(Observable.unsafeCreate(o1), Observable.unsafeCreate(o2)); TestSubscriber ts = new TestSubscriber(stringObserver); m.subscribe(ts); @@ -195,7 +195,7 @@ public void testSynchronizationOfMultipleSequences() throws Throwable { final AtomicInteger concurrentCounter = new AtomicInteger(); final AtomicInteger totalCounter = new AtomicInteger(); - Observable m = Observable.merge(Observable.create(o1), Observable.create(o2)); + Observable m = Observable.merge(Observable.unsafeCreate(o1), Observable.unsafeCreate(o2)); m.subscribe(new Subscriber() { @Override @@ -262,8 +262,8 @@ public void onNext(String v) { @Test public void testError1() { // we are using synchronous execution to test this exactly rather than non-deterministic concurrent behavior - final Observable o1 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" - final Observable o2 = Observable.create(new TestErrorObservable("one", "two", "three")); // we expect to lose all of these since o1 is done first and fails + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("four", null, "six")); // we expect to lose "six" + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("one", "two", "three")); // we expect to lose all of these since o1 is done first and fails Observable m = Observable.merge(o1, o2); m.subscribe(stringObserver); @@ -284,10 +284,10 @@ public void testError1() { @Test public void testError2() { // we are using synchronous execution to test this exactly rather than non-deterministic concurrent behavior - final Observable o1 = Observable.create(new TestErrorObservable("one", "two", "three")); - final Observable o2 = Observable.create(new TestErrorObservable("four", null, "six")); // we expect to lose "six" - final Observable o3 = Observable.create(new TestErrorObservable("seven", "eight", null));// we expect to lose all of these since o2 is done first and fails - final Observable o4 = Observable.create(new TestErrorObservable("nine"));// we expect to lose all of these since o2 is done first and fails + final Observable o1 = Observable.unsafeCreate(new TestErrorObservable("one", "two", "three")); + final Observable o2 = Observable.unsafeCreate(new TestErrorObservable("four", null, "six")); // we expect to lose "six" + final Observable o3 = Observable.unsafeCreate(new TestErrorObservable("seven", "eight", null));// we expect to lose all of these since o2 is done first and fails + final Observable o4 = Observable.unsafeCreate(new TestErrorObservable("nine"));// we expect to lose all of these since o2 is done first and fails Observable m = Observable.merge(o1, o2, o3, o4); m.subscribe(stringObserver); @@ -308,7 +308,7 @@ public void testError2() { @Test public void testThrownErrorHandling() { TestSubscriber ts = new TestSubscriber(); - Observable o1 = Observable.create(new OnSubscribe() { + Observable o1 = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -460,7 +460,7 @@ public void testEarlyUnsubscribe() { } private Observable createObservableOf5IntervalsOf1SecondIncrementsWithSubscriptionHook(final Scheduler scheduler, final AtomicBoolean unsubscribed) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -499,7 +499,7 @@ public void testConcurrency() { @Test public void testConcurrencyWithSleeping() { - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber s) { @@ -543,7 +543,7 @@ public void call() { @Test public void testConcurrencyWithBrokenOnCompleteContract() { - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber s) { @@ -807,7 +807,7 @@ public void mergeWithNullValues() { public void mergeWithTerminalEventAfterUnsubscribe() { System.out.println("mergeWithTerminalEventAfterUnsubscribe"); TestSubscriber ts = new TestSubscriber(); - Observable bad = Observable.create(new OnSubscribe() { + Observable bad = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -984,7 +984,7 @@ public void mergeManyAsyncSingle() { @Override public Observable call(final Integer i) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OperatorObserveOnTest.java b/src/test/java/rx/internal/operators/OperatorObserveOnTest.java index c5a29e04a2..df2e21e5c8 100644 --- a/src/test/java/rx/internal/operators/OperatorObserveOnTest.java +++ b/src/test/java/rx/internal/operators/OperatorObserveOnTest.java @@ -526,7 +526,7 @@ public boolean hasNext() { @Test public void testQueueFullEmitsError() { final CountDownLatch latch = new CountDownLatch(1); - Observable observable = Observable.create(new OnSubscribe() { + Observable observable = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber o) { diff --git a/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java b/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java index ea48f2847e..b76405b12c 100644 --- a/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnBackpressureBufferTest.java @@ -227,7 +227,7 @@ public void onNext(T t) { }); } - static final Observable infinite = Observable.create(new OnSubscribe() { + static final Observable infinite = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java b/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java index 87d748e2ea..07174570b5 100644 --- a/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnBackpressureDropTest.java @@ -151,7 +151,7 @@ public void testOnDropMethodIsCalled() { final List list = new ArrayList(); // request 0 TestSubscriber ts = TestSubscriber.create(0); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -180,7 +180,7 @@ public void call(Integer t) { public void testUpstreamEmitsOnCompletedAfterFailureWithoutCheckingSubscription() { TestSubscriber ts = TestSubscriber.create(0); final RuntimeException e = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -221,7 +221,7 @@ public void call(Throwable t) { TestSubscriber ts = TestSubscriber.create(0); final RuntimeException e1 = new RuntimeException(); final RuntimeException e2 = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -255,7 +255,7 @@ public void call(Integer t) { public void testUpstreamEmitsOnNextAfterFailureWithoutCheckingSubscription() { TestSubscriber ts = TestSubscriber.create(0); final RuntimeException e = new RuntimeException(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber sub) { @@ -291,7 +291,7 @@ public void call(Long n) { } }; - static final Observable infinite = Observable.create(new OnSubscribe() { + static final Observable infinite = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -304,7 +304,7 @@ public void call(Subscriber s) { }); private static final Observable range(final long n) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java index 9076e2f542..e127334588 100644 --- a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaFunctionTest.java @@ -44,7 +44,7 @@ public class OperatorOnErrorResumeNextViaFunctionTest { @Test public void testResumeNextWithSynchronousExecution() { final AtomicReference receivedException = new AtomicReference(); - Observable w = Observable.create(new Observable.OnSubscribe() { + Observable w = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { @@ -94,7 +94,7 @@ public Observable call(Throwable t1) { } }; - Observable observable = Observable.create(w).onErrorResumeNext(resume); + Observable observable = Observable.unsafeCreate(w).onErrorResumeNext(resume); @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); @@ -131,7 +131,7 @@ public Observable call(Throwable t1) { } }; - Observable observable = Observable.create(w).onErrorResumeNext(resume); + Observable observable = Observable.unsafeCreate(w).onErrorResumeNext(resume); @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); diff --git a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java index a7315a9158..41f910c2fc 100644 --- a/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnErrorResumeNextViaObservableTest.java @@ -42,7 +42,7 @@ public void testResumeNext() { Subscription s = mock(Subscription.class); // Trigger failure on second element TestObservable f = new TestObservable(s, "one", "fail", "two", "three"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); Observable resume = Observable.just("twoResume", "threeResume"); Observable observable = w.onErrorResumeNext(resume); @@ -72,7 +72,7 @@ public void testMapResumeAsyncNext() { Observable w = Observable.just("one", "fail", "two", "three", "fail"); // Resume Observable is async TestObservable f = new TestObservable(sr, "twoResume", "threeResume"); - Observable resume = Observable.create(f); + Observable resume = Observable.unsafeCreate(f); // Introduce map function that fails intermittently (Map does not prevent this when the observer is a // rx.operator incl onErrorResumeNextViaObservable) @@ -110,7 +110,7 @@ public String call(String s) { @Test public void testResumeNextWithFailedOnSubscribe() { - Observable testObservable = Observable.create(new OnSubscribe() { + Observable testObservable = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { @@ -132,7 +132,7 @@ public void call(Subscriber t1) { @Test public void testResumeNextWithFailedOnSubscribeAsync() { - Observable testObservable = Observable.create(new OnSubscribe() { + Observable testObservable = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { diff --git a/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java b/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java index 57a16e7829..196d5d49ce 100644 --- a/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnErrorReturnTest.java @@ -41,7 +41,7 @@ public class OperatorOnErrorReturnTest { @Test public void testResumeNext() { TestObservable f = new TestObservable("one"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); final AtomicReference capturedException = new AtomicReference(); Observable observable = w.onErrorReturn(new Func1() { @@ -77,7 +77,7 @@ public String call(Throwable e) { @Test public void testFunctionThrowsError() { TestObservable f = new TestObservable("one"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); final AtomicReference capturedException = new AtomicReference(); Observable observable = w.onErrorReturn(new Func1() { diff --git a/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java b/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java index 3b403f90e1..b54c7d4c46 100644 --- a/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java +++ b/src/test/java/rx/internal/operators/OperatorOnExceptionResumeNextViaObservableTest.java @@ -35,7 +35,7 @@ public class OperatorOnExceptionResumeNextViaObservableTest { public void testResumeNextWithException() { // Trigger failure on second element TestObservable f = new TestObservable("one", "EXCEPTION", "two", "three"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); Observable resume = Observable.just("twoResume", "threeResume"); Observable observable = w.onExceptionResumeNext(resume); @@ -63,7 +63,7 @@ public void testResumeNextWithException() { public void testResumeNextWithRuntimeException() { // Trigger failure on second element TestObservable f = new TestObservable("one", "RUNTIMEEXCEPTION", "two", "three"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); Observable resume = Observable.just("twoResume", "threeResume"); Observable observable = w.onExceptionResumeNext(resume); @@ -91,7 +91,7 @@ public void testResumeNextWithRuntimeException() { public void testThrowablePassesThru() { // Trigger failure on second element TestObservable f = new TestObservable("one", "THROWABLE", "two", "three"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); Observable resume = Observable.just("twoResume", "threeResume"); Observable observable = w.onExceptionResumeNext(resume); @@ -119,7 +119,7 @@ public void testThrowablePassesThru() { public void testErrorPassesThru() { // Trigger failure on second element TestObservable f = new TestObservable("one", "ON_OVERFLOW_ERROR", "two", "three"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); Observable resume = Observable.just("twoResume", "threeResume"); Observable observable = w.onExceptionResumeNext(resume); @@ -149,7 +149,7 @@ public void testMapResumeAsyncNext() { Observable w = Observable.just("one", "fail", "two", "three", "fail"); // Resume Observable is async TestObservable f = new TestObservable("twoResume", "threeResume"); - Observable resume = Observable.create(f); + Observable resume = Observable.unsafeCreate(f); // Introduce map function that fails intermittently (Map does not prevent this when the observer is a // rx.operator incl onErrorResumeNextViaObservable) diff --git a/src/test/java/rx/internal/operators/OperatorPublishTest.java b/src/test/java/rx/internal/operators/OperatorPublishTest.java index d0f524159f..9855143447 100644 --- a/src/test/java/rx/internal/operators/OperatorPublishTest.java +++ b/src/test/java/rx/internal/operators/OperatorPublishTest.java @@ -37,7 +37,7 @@ public class OperatorPublishTest { @Test public void testPublish() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - ConnectableObservable o = Observable.create(new OnSubscribe() { + ConnectableObservable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -368,7 +368,7 @@ public void onStart() { @Test public void testConnectIsIdempotent() { final AtomicInteger calls = new AtomicInteger(); - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { calls.getAndIncrement(); diff --git a/src/test/java/rx/internal/operators/OperatorRepeatTest.java b/src/test/java/rx/internal/operators/OperatorRepeatTest.java index c736b2ef3f..1a37f23c05 100644 --- a/src/test/java/rx/internal/operators/OperatorRepeatTest.java +++ b/src/test/java/rx/internal/operators/OperatorRepeatTest.java @@ -40,7 +40,7 @@ public class OperatorRepeatTest { public void testRepetition() { int NUM = 10; final AtomicInteger count = new AtomicInteger(); - int value = Observable.create(new OnSubscribe() { + int value = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber o) { @@ -68,7 +68,7 @@ public void testNoStackOverFlow() { public void testRepeatTakeWithSubscribeOn() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - Observable oi = Observable.create(new OnSubscribe() { + Observable oi = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OperatorReplayTest.java b/src/test/java/rx/internal/operators/OperatorReplayTest.java index e98c542cd8..e4734c30a6 100644 --- a/src/test/java/rx/internal/operators/OperatorReplayTest.java +++ b/src/test/java/rx/internal/operators/OperatorReplayTest.java @@ -915,7 +915,7 @@ public void testColdReplayBackpressure() { @Test public void testCache() throws InterruptedException { final AtomicInteger counter = new AtomicInteger(); - Observable o = Observable.create(new Observable.OnSubscribe() { + Observable o = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -1055,7 +1055,7 @@ public void testNoMissingBackpressureException() { m = 4 * 1000 * 1000; } - Observable firehose = Observable.create(new OnSubscribe() { + Observable firehose = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { for (int i = 0; i < m; i++) { diff --git a/src/test/java/rx/internal/operators/OperatorRetryTest.java b/src/test/java/rx/internal/operators/OperatorRetryTest.java index 7937f8945f..d4cf161dc5 100644 --- a/src/test/java/rx/internal/operators/OperatorRetryTest.java +++ b/src/test/java/rx/internal/operators/OperatorRetryTest.java @@ -45,7 +45,7 @@ public class OperatorRetryTest { public void iterativeBackoff() { @SuppressWarnings("unchecked") Observer consumer = mock(Observer.class); - Observable producer = Observable.create(new OnSubscribe() { + Observable producer = Observable.unsafeCreate(new OnSubscribe() { private AtomicInteger count = new AtomicInteger(4); long last = System.currentTimeMillis(); @@ -116,7 +116,7 @@ public void testRetryIndefinitely() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); int NUM_RETRIES = 20; - Observable origin = Observable.create(new FuncWithErrors(NUM_RETRIES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_RETRIES)); origin.retry().unsafeSubscribe(new TestSubscriber(observer)); InOrder inOrder = inOrder(observer); @@ -136,7 +136,7 @@ public void testSchedulingNotificationHandler() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); int NUM_RETRIES = 2; - Observable origin = Observable.create(new FuncWithErrors(NUM_RETRIES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_RETRIES)); TestSubscriber subscriber = new TestSubscriber(observer); origin.retryWhen(new Func1, Observable>() { @Override @@ -168,7 +168,7 @@ public void testOnNextFromNotificationHandler() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); int NUM_RETRIES = 2; - Observable origin = Observable.create(new FuncWithErrors(NUM_RETRIES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_RETRIES)); origin.retryWhen(new Func1, Observable>() { @Override public Observable call(Observable t1) { @@ -198,7 +198,7 @@ public Void call(Throwable t1) { public void testOnCompletedFromNotificationHandler() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(1)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(1)); TestSubscriber subscriber = new TestSubscriber(observer); origin.retryWhen(new Func1, Observable>() { @Override @@ -219,7 +219,7 @@ public Observable call(Observable t1) { public void testOnErrorFromNotificationHandler() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(2)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(2)); origin.retryWhen(new Func1, Observable>() { @Override public Observable call(Observable t1) { @@ -247,7 +247,7 @@ public void call(Subscriber subscriber) { } }; - int first = Observable.create(onSubscribe) + int first = Observable.unsafeCreate(onSubscribe) .retryWhen(new Func1, Observable>() { @Override public Observable call(Observable attempt) { @@ -270,7 +270,7 @@ public Void call(Throwable o, Integer integer) { public void testOriginFails() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(1)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(1)); origin.subscribe(observer); InOrder inOrder = inOrder(observer); @@ -286,7 +286,7 @@ public void testRetryFail() { int NUM_FAILURES = 2; @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_FAILURES)); origin.retry(NUM_RETRIES).subscribe(observer); InOrder inOrder = inOrder(observer); @@ -305,7 +305,7 @@ public void testRetrySuccess() { int NUM_FAILURES = 1; @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_FAILURES)); origin.retry(3).subscribe(observer); InOrder inOrder = inOrder(observer); @@ -325,7 +325,7 @@ public void testInfiniteRetry() { int NUM_FAILURES = 20; @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(NUM_FAILURES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_FAILURES)); origin.retry().subscribe(observer); InOrder inOrder = inOrder(observer); @@ -478,7 +478,7 @@ public boolean isUnsubscribed() { }); } }; - Observable stream = Observable.create(onSubscribe); + Observable stream = Observable.unsafeCreate(onSubscribe); Observable streamWithRetry = stream.retry(); Subscription sub = streamWithRetry.subscribe(); assertEquals(1, subsCount.get()); @@ -512,7 +512,7 @@ public void call(Subscriber s) { } }; - Observable.create(onSubscribe).retry(3).subscribe(ts); + Observable.unsafeCreate(onSubscribe).retry(3).subscribe(ts); assertEquals(4, subsCount.get()); // 1 + 3 retries } @@ -530,7 +530,7 @@ public void call(Subscriber s) { } }; - Observable.create(onSubscribe).retry(1).subscribe(ts); + Observable.unsafeCreate(onSubscribe).retry(1).subscribe(ts); assertEquals(2, subsCount.get()); } @@ -548,7 +548,7 @@ public void call(Subscriber s) { } }; - Observable.create(onSubscribe).retry(0).subscribe(ts); + Observable.unsafeCreate(onSubscribe).retry(0).subscribe(ts); assertEquals(1, subsCount.get()); } @@ -651,7 +651,7 @@ public void testUnsubscribeAfterError() { // Observable that always fails after 100ms SlowObservable so = new SlowObservable(100, 0); - Observable o = Observable.create(so).retry(5); + Observable o = Observable.unsafeCreate(so).retry(5); AsyncObserver async = new AsyncObserver(observer); @@ -676,7 +676,7 @@ public void testTimeoutWithRetry() { // Observable that sends every 100ms (timeout fails instead) SlowObservable so = new SlowObservable(100, 10); - Observable o = Observable.create(so).timeout(80, TimeUnit.MILLISECONDS).retry(5); + Observable o = Observable.unsafeCreate(so).timeout(80, TimeUnit.MILLISECONDS).retry(5); AsyncObserver async = new AsyncObserver(observer); @@ -700,7 +700,7 @@ public void testRetryWithBackpressure() throws InterruptedException { for (int i = 0; i < 400; i++) { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable origin = Observable.create(new FuncWithErrors(NUM_RETRIES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_RETRIES)); TestSubscriber ts = new TestSubscriber(observer); origin.retry().observeOn(Schedulers.computation()).unsafeSubscribe(ts); ts.awaitTerminalEvent(5, TimeUnit.SECONDS); @@ -743,7 +743,7 @@ public void testRetryWithBackpressureParallel() throws InterruptedException { public void run() { final AtomicInteger nexts = new AtomicInteger(); try { - Observable origin = Observable.create(new FuncWithErrors(NUM_RETRIES)); + Observable origin = Observable.unsafeCreate(new FuncWithErrors(NUM_RETRIES)); TestSubscriber ts = new TestSubscriber(); origin.retry() .observeOn(Schedulers.computation()).unsafeSubscribe(ts); @@ -866,7 +866,7 @@ public void testIssue1900SourceNotSupportingBackpressure() { final int NUM_MSG = 1034; final AtomicInteger count = new AtomicInteger(); - Observable origin = Observable.create(new Observable.OnSubscribe() { + Observable origin = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber o) { diff --git a/src/test/java/rx/internal/operators/OperatorRetryWithPredicateTest.java b/src/test/java/rx/internal/operators/OperatorRetryWithPredicateTest.java index f526d327f6..dab59e9f0d 100644 --- a/src/test/java/rx/internal/operators/OperatorRetryWithPredicateTest.java +++ b/src/test/java/rx/internal/operators/OperatorRetryWithPredicateTest.java @@ -81,7 +81,7 @@ public void testWithNothingToRetry() { } @Test public void testRetryTwice() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { int count; @Override public void call(Subscriber t1) { @@ -116,7 +116,7 @@ public void call(Subscriber t1) { } @Test public void testRetryTwiceAndGiveUp() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { t1.onNext(0); @@ -143,7 +143,7 @@ public void call(Subscriber t1) { } @Test public void testRetryOnSpecificException() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { int count; @Override public void call(Subscriber t1) { @@ -179,7 +179,7 @@ public void call(Subscriber t1) { public void testRetryOnSpecificExceptionAndNotOther() { final IOException ioe = new IOException(); final TestException te = new TestException(); - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { int count; @Override public void call(Subscriber t1) { @@ -238,7 +238,7 @@ public void testUnsubscribeAfterError() { // Observable that always fails after 100ms OperatorRetryTest.SlowObservable so = new OperatorRetryTest.SlowObservable(100, 0); Observable o = Observable - .create(so) + .unsafeCreate(so) .retry(retry5); OperatorRetryTest.AsyncObserver async = new OperatorRetryTest.AsyncObserver(observer); @@ -265,7 +265,7 @@ public void testTimeoutWithRetry() { // Observable that sends every 100ms (timeout fails instead) OperatorRetryTest.SlowObservable so = new OperatorRetryTest.SlowObservable(100, 10); Observable o = Observable - .create(so) + .unsafeCreate(so) .timeout(80, TimeUnit.MILLISECONDS) .retry(retry5); diff --git a/src/test/java/rx/internal/operators/OperatorSampleTest.java b/src/test/java/rx/internal/operators/OperatorSampleTest.java index 04000973ec..20d59d8523 100644 --- a/src/test/java/rx/internal/operators/OperatorSampleTest.java +++ b/src/test/java/rx/internal/operators/OperatorSampleTest.java @@ -50,7 +50,7 @@ public void before() { @Test public void testSample() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer1) { innerScheduler.schedule(new Action0() { @@ -111,7 +111,7 @@ public void call() { @Test public void sampleWithTimeEmitAndTerminate() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer1) { innerScheduler.schedule(new Action0() { @@ -303,7 +303,7 @@ public void sampleWithSamplerThrows() { @Test public void testSampleUnsubscribe() { final Subscription s = mock(Subscription.class); - Observable o = Observable.create( + Observable o = Observable.unsafeCreate( new OnSubscribe() { @Override public void call(Subscriber subscriber) { @@ -387,7 +387,7 @@ public void dontUnsubscribeChild2() { @Test public void neverSetProducer() { - Observable neverBackpressure = Observable.create(new OnSubscribe() { + Observable neverBackpressure = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { t.setProducer(new Producer() { @@ -430,7 +430,7 @@ public void setProducer(Producer p) { public void unsubscribeMainAfterCompleted() { final AtomicBoolean unsubscribed = new AtomicBoolean(); - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { t.add(Subscriptions.create(new Action0() { @@ -467,7 +467,7 @@ public void onCompleted() { public void unsubscribeSamplerAfterCompleted() { final AtomicBoolean unsubscribed = new AtomicBoolean(); - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { t.add(Subscriptions.create(new Action0() { diff --git a/src/test/java/rx/internal/operators/OperatorScanTest.java b/src/test/java/rx/internal/operators/OperatorScanTest.java index c6bf08b718..e20519ed17 100644 --- a/src/test/java/rx/internal/operators/OperatorScanTest.java +++ b/src/test/java/rx/internal/operators/OperatorScanTest.java @@ -306,7 +306,7 @@ public Integer call(Integer t1, Integer t2) { @Test public void testScanShouldNotRequestZero() { final AtomicReference producer = new AtomicReference(); - Observable o = Observable.create(new Observable.OnSubscribe() { + Observable o = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber subscriber) { Producer p = spy(new Producer() { @@ -371,7 +371,7 @@ public Integer call(Integer t1, Integer t2) { @Test public void testInitialValueEmittedWithProducer() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t) { t.setProducer(new Producer() { diff --git a/src/test/java/rx/internal/operators/OperatorSerializeTest.java b/src/test/java/rx/internal/operators/OperatorSerializeTest.java index 450e2e0185..14d38dd76b 100644 --- a/src/test/java/rx/internal/operators/OperatorSerializeTest.java +++ b/src/test/java/rx/internal/operators/OperatorSerializeTest.java @@ -51,7 +51,7 @@ public void before() { @Test public void testSingleThreadedBasic() { TestSingleThreadedObservable onSubscribe = new TestSingleThreadedObservable("one", "two", "three"); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); w.serialize().subscribe(observer); onSubscribe.waitToFinish(); @@ -69,7 +69,7 @@ public void testSingleThreadedBasic() { @Test public void testMultiThreadedBasic() { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three"); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); BusyObserver busyobserver = new BusyObserver(); @@ -92,7 +92,7 @@ public void testMultiThreadedBasic() { @Test public void testMultiThreadedWithNPE() { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); BusyObserver busyobserver = new BusyObserver(); @@ -123,7 +123,7 @@ public void testMultiThreadedWithNPEinMiddle() { boolean lessThan9 = false; for (int i = 0; i < 3; i++) { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); BusyObserver busyobserver = new BusyObserver(); diff --git a/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java b/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java index 65f1b9870e..6eb4abd8e8 100644 --- a/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java +++ b/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java @@ -50,7 +50,7 @@ public void testIssue813() throws InterruptedException { TestSubscriber observer = new TestSubscriber(); final Subscription subscription = Observable - .create(new Observable.OnSubscribe() { + .unsafeCreate(new Observable.OnSubscribe() { @Override public void call( final Subscriber subscriber) { @@ -85,7 +85,7 @@ public void call( @Test public void testThrownErrorHandling() { TestSubscriber ts = new TestSubscriber(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -100,7 +100,7 @@ public void call(Subscriber s) { @Test public void testOnError() { TestSubscriber ts = new TestSubscriber(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -170,7 +170,7 @@ public Subscription schedule(final Action0 action, final long delayTime, final T public void testUnsubscribeInfiniteStream() throws InterruptedException { TestSubscriber ts = new TestSubscriber(); final AtomicInteger count = new AtomicInteger(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber sub) { diff --git a/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java b/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java index 70225a53eb..5108f4001d 100644 --- a/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java +++ b/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java @@ -58,7 +58,7 @@ public void testSwitchWhenEmpty() throws Exception { @Test public void testSwitchWithProducer() throws Exception { final AtomicBoolean emitted = new AtomicBoolean(false); - Observable withProducer = Observable.create(new Observable.OnSubscribe() { + Observable withProducer = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber subscriber) { subscriber.setProducer(new Producer() { @@ -82,7 +82,7 @@ public void request(long n) { public void testSwitchTriggerUnsubscribe() throws Exception { final Subscription empty = Subscriptions.empty(); - Observable withProducer = Observable.create(new Observable.OnSubscribe() { + Observable withProducer = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber subscriber) { subscriber.add(empty); @@ -121,7 +121,7 @@ public void onNext(Long aLong) { public void testSwitchShouldTriggerUnsubscribe() { final Subscription s = Subscriptions.empty(); - Observable.create(new Observable.OnSubscribe() { + Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber subscriber) { subscriber.add(s); @@ -176,7 +176,7 @@ public void testBackpressureOnFirstObservable() { @Test(timeout = 10000) public void testRequestsNotLost() throws InterruptedException { final TestSubscriber ts = new TestSubscriber(0); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber subscriber) { diff --git a/src/test/java/rx/internal/operators/OperatorSwitchTest.java b/src/test/java/rx/internal/operators/OperatorSwitchTest.java index 1a8732e341..8525c18cd6 100644 --- a/src/test/java/rx/internal/operators/OperatorSwitchTest.java +++ b/src/test/java/rx/internal/operators/OperatorSwitchTest.java @@ -53,10 +53,10 @@ public void before() { @Test public void testSwitchWhenOuterCompleteBeforeInner() { - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { - publishNext(observer, 50, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 50, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 70, "one"); @@ -80,10 +80,10 @@ public void call(Subscriber observer) { @Test public void testSwitchWhenInnerCompleteBeforeOuter() { - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { - publishNext(observer, 10, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 10, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 0, "one"); @@ -92,7 +92,7 @@ public void call(Subscriber observer) { } })); - publishNext(observer, 100, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 100, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 0, "three"); @@ -123,10 +123,10 @@ public void call(Subscriber observer) { @Test public void testSwitchWithComplete() { - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { - publishNext(observer, 50, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 50, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { publishNext(observer, 60, "one"); @@ -134,7 +134,7 @@ public void call(final Subscriber observer) { } })); - publishNext(observer, 200, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 200, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { publishNext(observer, 0, "three"); @@ -179,10 +179,10 @@ public void call(final Subscriber observer) { @Test public void testSwitchWithError() { - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { - publishNext(observer, 50, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 50, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { publishNext(observer, 50, "one"); @@ -190,7 +190,7 @@ public void call(final Subscriber observer) { } })); - publishNext(observer, 200, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 200, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 0, "three"); @@ -235,10 +235,10 @@ public void call(Subscriber observer) { @Test public void testSwitchWithSubsequenceComplete() { - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { - publishNext(observer, 50, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 50, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 50, "one"); @@ -246,14 +246,14 @@ public void call(Subscriber observer) { } })); - publishNext(observer, 130, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 130, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishCompleted(observer, 0); } })); - publishNext(observer, 150, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 150, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 50, "three"); @@ -285,10 +285,10 @@ public void call(Subscriber observer) { @Test public void testSwitchWithSubsequenceError() { - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { - publishNext(observer, 50, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 50, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 50, "one"); @@ -296,14 +296,14 @@ public void call(Subscriber observer) { } })); - publishNext(observer, 130, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 130, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishError(observer, 0, new TestException()); } })); - publishNext(observer, 150, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 150, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 50, "three"); @@ -364,10 +364,10 @@ public void call() { @Test public void testSwitchIssue737() { // https://github.com/ReactiveX/RxJava/issues/737 - Observable> source = Observable.create(new Observable.OnSubscribe>() { + Observable> source = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { - publishNext(observer, 0, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 0, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 10, "1-one"); @@ -377,7 +377,7 @@ public void call(Subscriber observer) { publishCompleted(observer, 40); } })); - publishNext(observer, 25, Observable.create(new Observable.OnSubscribe() { + publishNext(observer, 25, Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 10, "2-one"); @@ -407,7 +407,7 @@ public void call(Subscriber observer) { @Test public void testBackpressure() { - final Observable o1 = Observable.create(new Observable.OnSubscribe() { + final Observable o1 = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { observer.setProducer(new Producer() { @@ -428,7 +428,7 @@ public void request(long n) { }); } }); - final Observable o2 = Observable.create(new Observable.OnSubscribe() { + final Observable o2 = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { observer.setProducer(new Producer() { @@ -449,7 +449,7 @@ public void request(long n) { }); } }); - final Observable o3 = Observable.create(new Observable.OnSubscribe() { + final Observable o3 = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { observer.setProducer(new Producer() { @@ -469,7 +469,7 @@ public void request(long n) { }); } }); - Observable> o = Observable.create(new Observable.OnSubscribe>() { + Observable> o = Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(Subscriber> observer) { publishNext(observer, 10, o1); @@ -519,7 +519,7 @@ public void onNext(String s) { public void testUnsubscribe() { final AtomicBoolean isUnsubscribed = new AtomicBoolean(); Observable.switchOnNext( - Observable.create(new Observable.OnSubscribe>() { + Observable.unsafeCreate(new Observable.OnSubscribe>() { @Override public void call(final Subscriber> subscriber) { subscriber.onNext(Observable.just(1)); diff --git a/src/test/java/rx/internal/operators/OperatorTakeTest.java b/src/test/java/rx/internal/operators/OperatorTakeTest.java index 0dc3dbc8c4..edf17bac10 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeTest.java @@ -112,7 +112,7 @@ public Integer call(Integer t1) { @Test public void testTakeDoesntLeakErrors() { - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { observer.onNext("one"); @@ -136,7 +136,7 @@ public void call(Subscriber observer) { public void testTakeZeroDoesntLeakError() { final AtomicBoolean subscribed = new AtomicBoolean(false); final AtomicBoolean unSubscribed = new AtomicBoolean(false); - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { subscribed.set(true); @@ -173,7 +173,7 @@ public boolean isUnsubscribed() { public void testUnsubscribeAfterTake() { final Subscription s = mock(Subscription.class); TestObservableFunc f = new TestObservableFunc("one", "two", "three"); - Observable w = Observable.create(f); + Observable w = Observable.unsafeCreate(f); @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); @@ -218,7 +218,7 @@ public void call(Long l) { @Test(timeout = 2000) public void testMultiTake() { final AtomicInteger count = new AtomicInteger(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -277,7 +277,7 @@ public void run() { } } - private static Observable INFINITE_OBSERVABLE = Observable.create(new OnSubscribe() { + private static Observable INFINITE_OBSERVABLE = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber op) { @@ -311,7 +311,7 @@ public void testProducerRequestThroughTake() { TestSubscriber ts = new TestSubscriber(); ts.requestMore(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { @@ -334,7 +334,7 @@ public void testProducerRequestThroughTakeIsModified() { TestSubscriber ts = new TestSubscriber(); ts.requestMore(3); final AtomicLong requested = new AtomicLong(); - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java b/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java index 28c0c432ff..5c590c68c5 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeUntilTest.java @@ -40,7 +40,7 @@ public void testTakeUntil() { TestObservable other = new TestObservable(sOther); Observer result = mock(Observer.class); - Observable stringObservable = Observable.create(source).takeUntil(Observable.create(other)); + Observable stringObservable = Observable.unsafeCreate(source).takeUntil(Observable.unsafeCreate(other)); stringObservable.subscribe(result); source.sendOnNext("one"); source.sendOnNext("two"); @@ -67,7 +67,7 @@ public void testTakeUntilSourceCompleted() { TestObservable other = new TestObservable(sOther); Observer result = mock(Observer.class); - Observable stringObservable = Observable.create(source).takeUntil(Observable.create(other)); + Observable stringObservable = Observable.unsafeCreate(source).takeUntil(Observable.unsafeCreate(other)); stringObservable.subscribe(result); source.sendOnNext("one"); source.sendOnNext("two"); @@ -90,7 +90,7 @@ public void testTakeUntilSourceError() { Throwable error = new Throwable(); Observer result = mock(Observer.class); - Observable stringObservable = Observable.create(source).takeUntil(Observable.create(other)); + Observable stringObservable = Observable.unsafeCreate(source).takeUntil(Observable.unsafeCreate(other)); stringObservable.subscribe(result); source.sendOnNext("one"); source.sendOnNext("two"); @@ -116,7 +116,7 @@ public void testTakeUntilOtherError() { Throwable error = new Throwable(); Observer result = mock(Observer.class); - Observable stringObservable = Observable.create(source).takeUntil(Observable.create(other)); + Observable stringObservable = Observable.unsafeCreate(source).takeUntil(Observable.unsafeCreate(other)); stringObservable.subscribe(result); source.sendOnNext("one"); source.sendOnNext("two"); @@ -145,7 +145,7 @@ public void testTakeUntilOtherCompleted() { TestObservable other = new TestObservable(sOther); Observer result = mock(Observer.class); - Observable stringObservable = Observable.create(source).takeUntil(Observable.create(other)); + Observable stringObservable = Observable.unsafeCreate(source).takeUntil(Observable.unsafeCreate(other)); stringObservable.subscribe(result); source.sendOnNext("one"); source.sendOnNext("two"); diff --git a/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java b/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java index 0a3cd3ec94..2537e0e807 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeWhileTest.java @@ -107,7 +107,7 @@ public Boolean call(String input) { @Test public void testTakeWhileDoesntLeakErrors() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { observer.onNext("one"); @@ -130,7 +130,7 @@ public void testTakeWhileProtectsPredicateCall() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable take = Observable.create(source).takeWhile(new Func1() { + Observable take = Observable.unsafeCreate(source).takeWhile(new Func1() { @Override public Boolean call(String s) { throw testException; @@ -157,7 +157,7 @@ public void testUnsubscribeAfterTake() { @SuppressWarnings("unchecked") Observer observer = mock(Observer.class); - Observable take = Observable.create(w).takeWhile(new Func1() { + Observable take = Observable.unsafeCreate(w).takeWhile(new Func1() { int index; @Override diff --git a/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java b/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java index f608cb22c6..4908efc534 100644 --- a/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java +++ b/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java @@ -55,7 +55,7 @@ public void before() { @Test public void testThrottlingWithCompleted() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { publishNext(observer, 100, "one"); // publish as it's first @@ -82,7 +82,7 @@ public void call(Subscriber observer) { @Test public void testThrottlingWithError() { - Observable source = Observable.create(new OnSubscribe() { + Observable source = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { Exception error = new TestException(); diff --git a/src/test/java/rx/internal/operators/OperatorTimeoutTests.java b/src/test/java/rx/internal/operators/OperatorTimeoutTests.java index 3071d78f6d..fba5b1d6c5 100644 --- a/src/test/java/rx/internal/operators/OperatorTimeoutTests.java +++ b/src/test/java/rx/internal/operators/OperatorTimeoutTests.java @@ -234,7 +234,7 @@ public void shouldTimeoutIfSynchronizedObservableEmitFirstOnNextNotWithinTimeout @Override public void run() { - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber subscriber) { @@ -268,7 +268,7 @@ public void shouldUnsubscribeFromUnderlyingSubscriptionOnTimeout() throws Interr // From https://github.com/ReactiveX/RxJava/pull/951 final Subscription s = mock(Subscription.class); - Observable never = Observable.create(new OnSubscribe() { + Observable never = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber subscriber) { subscriber.add(s); @@ -296,7 +296,7 @@ public void shouldUnsubscribeFromUnderlyingSubscriptionOnImmediatelyComplete() { // From https://github.com/ReactiveX/RxJava/pull/951 final Subscription s = mock(Subscription.class); - Observable immediatelyComplete = Observable.create(new OnSubscribe() { + Observable immediatelyComplete = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber subscriber) { subscriber.add(s); @@ -326,7 +326,7 @@ public void shouldUnsubscribeFromUnderlyingSubscriptionOnImmediatelyErrored() th // From https://github.com/ReactiveX/RxJava/pull/951 final Subscription s = mock(Subscription.class); - Observable immediatelyError = Observable.create(new OnSubscribe() { + Observable immediatelyError = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber subscriber) { subscriber.add(s); diff --git a/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java b/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java index d2d0e2e567..50ce9e5865 100644 --- a/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java +++ b/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java @@ -334,7 +334,7 @@ public void testTimeoutSelectorWithTimeoutAndOnNextRaceCondition() throws Interr public Observable call(Integer t1) { if (t1 == 1) { // Force "unsubscribe" run on another thread - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber subscriber) { enteredTimeoutOne.countDown(); diff --git a/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java b/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java index 8e4317af40..fe8d664122 100644 --- a/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java +++ b/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java @@ -39,7 +39,7 @@ public void testUnsubscribeWhenSubscribeOnAndUnsubscribeOnAreOnSameThread() thro try { final ThreadSubscription subscription = new ThreadSubscription(); final AtomicReference subscribeThread = new AtomicReference(); - Observable w = Observable.create(new OnSubscribe() { + Observable w = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { @@ -84,7 +84,7 @@ public void testUnsubscribeWhenSubscribeOnAndUnsubscribeOnAreOnDifferentThreads( try { final ThreadSubscription subscription = new ThreadSubscription(); final AtomicReference subscribeThread = new AtomicReference(); - Observable w = Observable.create(new OnSubscribe() { + Observable w = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber t1) { diff --git a/src/test/java/rx/internal/operators/OperatorWindowWithSizeTest.java b/src/test/java/rx/internal/operators/OperatorWindowWithSizeTest.java index 7f74cd1ee0..2e9b718e67 100644 --- a/src/test/java/rx/internal/operators/OperatorWindowWithSizeTest.java +++ b/src/test/java/rx/internal/operators/OperatorWindowWithSizeTest.java @@ -249,7 +249,7 @@ public void onCompleted() { } public static Observable hotStream() { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { while (!s.isUnsubscribed()) { diff --git a/src/test/java/rx/internal/operators/OperatorWindowWithStartEndObservableTest.java b/src/test/java/rx/internal/operators/OperatorWindowWithStartEndObservableTest.java index 858465a877..eeb47b89be 100644 --- a/src/test/java/rx/internal/operators/OperatorWindowWithStartEndObservableTest.java +++ b/src/test/java/rx/internal/operators/OperatorWindowWithStartEndObservableTest.java @@ -46,7 +46,7 @@ public void testObservableBasedOpenerAndCloser() { final List list = new ArrayList(); final List> lists = new ArrayList>(); - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 10); @@ -58,7 +58,7 @@ public void call(Subscriber observer) { } }); - Observable openings = Observable.create(new Observable.OnSubscribe() { + Observable openings = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, new Object(), 50); @@ -70,7 +70,7 @@ public void call(Subscriber observer) { Func1> closer = new Func1>() { @Override public Observable call(Object opening) { - return Observable.create(new Observable.OnSubscribe() { + return Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, new Object(), 100); @@ -94,7 +94,7 @@ public void testObservableBasedCloser() { final List list = new ArrayList(); final List> lists = new ArrayList>(); - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 10); @@ -110,7 +110,7 @@ public void call(Subscriber observer) { int calls; @Override public Observable call() { - return Observable.create(new Observable.OnSubscribe() { + return Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { int c = calls++; diff --git a/src/test/java/rx/internal/operators/OperatorWindowWithTimeTest.java b/src/test/java/rx/internal/operators/OperatorWindowWithTimeTest.java index 71a59ff510..78500db578 100644 --- a/src/test/java/rx/internal/operators/OperatorWindowWithTimeTest.java +++ b/src/test/java/rx/internal/operators/OperatorWindowWithTimeTest.java @@ -45,7 +45,7 @@ public void testTimedAndCount() { final List list = new ArrayList(); final List> lists = new ArrayList>(); - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 10); @@ -78,7 +78,7 @@ public void testTimed() { final List list = new ArrayList(); final List> lists = new ArrayList>(); - Observable source = Observable.create(new Observable.OnSubscribe() { + Observable source = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { push(observer, "one", 98); diff --git a/src/test/java/rx/internal/operators/OperatorZipTest.java b/src/test/java/rx/internal/operators/OperatorZipTest.java index 908f44a23d..5f4b06bcbe 100644 --- a/src/test/java/rx/internal/operators/OperatorZipTest.java +++ b/src/test/java/rx/internal/operators/OperatorZipTest.java @@ -94,7 +94,7 @@ public void testStartpingDifferentLengthObservableSequences1() { TestObservable w2 = new TestObservable(); TestObservable w3 = new TestObservable(); - Observable zipW = Observable.zip(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsZipr()); + Observable zipW = Observable.zip(Observable.unsafeCreate(w1), Observable.unsafeCreate(w2), Observable.unsafeCreate(w3), getConcat3StringsZipr()); zipW.subscribe(w); /* simulate sending data */ @@ -128,7 +128,7 @@ public void testStartpingDifferentLengthObservableSequences2() { TestObservable w2 = new TestObservable(); TestObservable w3 = new TestObservable(); - Observable zipW = Observable.zip(Observable.create(w1), Observable.create(w2), Observable.create(w3), getConcat3StringsZipr()); + Observable zipW = Observable.zip(Observable.unsafeCreate(w1), Observable.unsafeCreate(w2), Observable.unsafeCreate(w3), getConcat3StringsZipr()); zipW.subscribe(w); /* simulate sending data */ @@ -1212,7 +1212,7 @@ public boolean hasNext() { Observable OBSERVABLE_OF_5_INTEGERS = OBSERVABLE_OF_5_INTEGERS(new AtomicInteger()); Observable OBSERVABLE_OF_5_INTEGERS(final AtomicInteger numEmitted) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber o) { @@ -1231,7 +1231,7 @@ public void call(final Subscriber o) { } Observable ASYNC_OBSERVABLE_OF_INFINITE_INTEGERS(final CountDownLatch latch) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber o) { diff --git a/src/test/java/rx/internal/operators/SafeSubscriberTest.java b/src/test/java/rx/internal/operators/SafeSubscriberTest.java index cf71a8f5d1..57fc3446bc 100644 --- a/src/test/java/rx/internal/operators/SafeSubscriberTest.java +++ b/src/test/java/rx/internal/operators/SafeSubscriberTest.java @@ -38,7 +38,7 @@ public class SafeSubscriberTest { @Test public void testOnNextAfterOnError() { TestObservable t = new TestObservable(); - Observable st = Observable.create(t); + Observable st = Observable.unsafeCreate(t); @SuppressWarnings("unchecked") Observer w = mock(Observer.class); @@ -60,7 +60,7 @@ public void testOnNextAfterOnError() { @Test public void testOnCompletedAfterOnError() { TestObservable t = new TestObservable(); - Observable st = Observable.create(t); + Observable st = Observable.unsafeCreate(t); @SuppressWarnings("unchecked") Observer w = mock(Observer.class); @@ -82,7 +82,7 @@ public void testOnCompletedAfterOnError() { @Test public void testOnNextAfterOnCompleted() { TestObservable t = new TestObservable(); - Observable st = Observable.create(t); + Observable st = Observable.unsafeCreate(t); @SuppressWarnings("unchecked") Observer w = mock(Observer.class); @@ -105,7 +105,7 @@ public void testOnNextAfterOnCompleted() { @Test public void testOnErrorAfterOnCompleted() { TestObservable t = new TestObservable(); - Observable st = Observable.create(t); + Observable st = Observable.unsafeCreate(t); @SuppressWarnings("unchecked") Observer w = mock(Observer.class); diff --git a/src/test/java/rx/internal/producers/ProducersTest.java b/src/test/java/rx/internal/producers/ProducersTest.java index f41fcda71a..46533b8ada 100644 --- a/src/test/java/rx/internal/producers/ProducersTest.java +++ b/src/test/java/rx/internal/producers/ProducersTest.java @@ -365,7 +365,7 @@ public void testObserverArbiterAsync() { .map(plus(40)) ); - Observable source = Observable.create( + Observable source = Observable.unsafeCreate( new SwitchTimer(timers, 550, TimeUnit.MILLISECONDS, test)); diff --git a/src/test/java/rx/observables/AsyncOnSubscribeTest.java b/src/test/java/rx/observables/AsyncOnSubscribeTest.java index a711d92c91..d344532aae 100644 --- a/src/test/java/rx/observables/AsyncOnSubscribeTest.java +++ b/src/test/java/rx/observables/AsyncOnSubscribeTest.java @@ -110,7 +110,7 @@ public void testSubscribedByBufferingOperator() { public void call(Long requested, Observer> observer) { observer.onNext(Observable.range(1, requested.intValue())); }}); - Observable.create(os).observeOn(scheduler).subscribe(subscriber); + Observable.unsafeCreate(os).observeOn(scheduler).subscribe(subscriber); subscriber.requestMore(RxRingBuffer.SIZE); scheduler.advanceTimeBy(10, TimeUnit.DAYS); subscriber.assertNoErrors(); @@ -141,7 +141,7 @@ public Integer call(Integer state, Long requested, Observer> observer) { observer.onCompleted(); }}); - Observable.create(os).subscribe(subscriber); + Observable.unsafeCreate(os).subscribe(subscriber); subscriber.requestMore(1); subscriber.assertNoErrors(); subscriber.assertCompleted(); @@ -174,7 +174,7 @@ public void call(Long requested, Observer> observe observer.onNext(Observable.just(2)); } }); - Observable.create(os).subscribe(subscriber); + Observable.unsafeCreate(os).subscribe(subscriber); subscriber.requestMore(1); subscriber.assertError(IllegalStateException.class); subscriber.assertNotCompleted(); @@ -189,7 +189,7 @@ public void testThrowException() throws InterruptedException { public void call(Long requested, Observer> observer) { throw new TestException(); }}); - Observable.create(os).subscribe(subscriber); + Observable.unsafeCreate(os).subscribe(subscriber); subscriber.requestMore(1); subscriber.assertError(TestException.class); subscriber.assertNotCompleted(); @@ -209,7 +209,7 @@ public Integer call(Integer state, Long requested, Observer obs = BlockingObservable.from(Observable.create(new Observable.OnSubscribe() { + BlockingObservable obs = BlockingObservable.from(Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { @@ -281,7 +281,7 @@ public void call(Subscriber observer) { @Test public void testForEachWithError() { try { - BlockingObservable.from(Observable.create(new Observable.OnSubscribe() { + BlockingObservable.from(Observable.unsafeCreate(new Observable.OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -382,7 +382,7 @@ public Boolean call(String args) { @Test public void testSingleOrDefaultUnsubscribe() throws InterruptedException { final CountDownLatch unsubscribe = new CountDownLatch(1); - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber subscriber) { subscriber.add(Subscriptions.create(new Action0() { diff --git a/src/test/java/rx/observables/SyncOnSubscribeTest.java b/src/test/java/rx/observables/SyncOnSubscribeTest.java index 630561b0a3..a219e1d7b7 100644 --- a/src/test/java/rx/observables/SyncOnSubscribeTest.java +++ b/src/test/java/rx/observables/SyncOnSubscribeTest.java @@ -52,7 +52,7 @@ public void call(Observer subscriber) { TestSubscriber ts = new TestSubscriber(); - Observable.create(os).subscribe(ts); + Observable.unsafeCreate(os).subscribe(ts); ts.assertNoErrors(); ts.assertTerminalEvent(); @@ -82,7 +82,7 @@ public void call(Integer t) { TestSubscriber ts = new TestSubscriber(); - Observable.create(os).subscribe(ts); + Observable.unsafeCreate(os).subscribe(ts); ts.assertNoErrors(); ts.assertTerminalEvent(); @@ -103,7 +103,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, times(1)).onNext(1); verify(o, never()).onNext(2); @@ -124,7 +124,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, times(1)).onNext(1); verify(o, times(1)).onCompleted(); @@ -144,7 +144,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, times(1)).onNext(1); verify(o, times(1)).onCompleted(); @@ -171,7 +171,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, times(1)).onNext(1); verify(o, never()).onCompleted(); @@ -190,7 +190,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, never()).onNext(any(Integer.class)); verify(o, never()).onError(any(Throwable.class)); @@ -206,7 +206,7 @@ public void call(Observer subscriber) { }}); - Observable neverObservable = Observable.create(os).subscribeOn(Schedulers.newThread()); + Observable neverObservable = Observable.unsafeCreate(os).subscribeOn(Schedulers.newThread()); Observable merged = Observable.amb(neverObservable, Observable.timer(100, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread())); Iterator values = merged.toBlocking().toIterable().iterator(); @@ -225,7 +225,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, never()).onNext(any(Integer.class)); verify(o, never()).onCompleted(); @@ -243,7 +243,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, never()).onNext(any(Integer.class)); verify(o, times(1)).onCompleted(); @@ -268,7 +268,7 @@ public void onStart() { } }; - Observable.create(os).subscribe(ts); + Observable.unsafeCreate(os).subscribe(ts); ts.requestMore(1); @@ -288,7 +288,7 @@ public void call(Observer subscriber) { @SuppressWarnings("unchecked") Observer o = mock(Observer.class); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, never()).onNext(any(Integer.class)); verify(o).onError(any(TestException.class)); @@ -319,7 +319,7 @@ public Integer call(Integer state, Observer subscriber) { Observer o = mock(Observer.class); InOrder inOrder = inOrder(o); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, never()).onError(any(TestException.class)); inOrder.verify(o, times(count)).onNext(any(Integer.class)); @@ -357,7 +357,7 @@ public Iterator call(Iterator it, Observer ob Observer o = mock(Observer.class); InOrder inOrder = inOrder(o); - Observable.create(os).subscribe(o); + Observable.unsafeCreate(os).subscribe(o); verify(o, never()).onError(any(TestException.class)); inOrder.verify(o, times(n)).onNext(any()); @@ -385,7 +385,7 @@ public Integer call(Integer state, Observer observer) { Observer o = mock(Observer.class); InOrder inOrder = inOrder(o); - Observable.create(os).take(finalCount).subscribe(o); + Observable.unsafeCreate(os).take(finalCount).subscribe(o); verify(o, never()).onError(any(Throwable.class)); inOrder.verify(o, times(finalCount)).onNext(any()); @@ -416,7 +416,7 @@ public Integer call(Integer state, Observer observer) { onUnSubscribe); TestSubscriber ts = new TestSubscriber(0); - Observable.create(os).subscribe(ts); + Observable.unsafeCreate(os).subscribe(ts); ts.requestMore(finalCount); @@ -451,7 +451,7 @@ public Integer call(Integer state, Observer observer) { TestSubscriber ts = new TestSubscriber(o); - Observable.create(os).take(1).subscribe(ts); + Observable.unsafeCreate(os).take(1).subscribe(ts); verify(o, never()).onError(any(Throwable.class)); verify(onUnSubscribe, times(1)).call(any(Integer.class)); @@ -521,7 +521,7 @@ public Integer call(Integer state, Observer observer) { InOrder inOrder = inOrder(o); final TestSubscriber ts = new TestSubscriber(o); - Observable.create(os).subscribeOn(Schedulers.newThread()).subscribe(ts); + Observable.unsafeCreate(os).subscribeOn(Schedulers.newThread()).subscribe(ts); // wait until the first request has started processing if (!l2.await(2, TimeUnit.SECONDS)) { @@ -569,7 +569,7 @@ public void call() { final CountDownLatch latch = new CountDownLatch(1); final TestSubscriber ts = new TestSubscriber(o); - Observable.create(os).lift(new Operator() { + Observable.unsafeCreate(os).lift(new Operator() { @Override public Subscriber call(final Subscriber subscriber) { return new Subscriber(subscriber) { @@ -634,7 +634,7 @@ public Map call(Map state, Observer source = Observable.create(os); + Observable source = Observable.unsafeCreate(os); for (int i = 0; i < count; i++) { source.subscribe(); } @@ -678,7 +678,7 @@ public void call(Integer t) { subs.add(ts); } TestScheduler scheduler = new TestScheduler(); - Observable o2 = Observable.create(os).subscribeOn(scheduler); + Observable o2 = Observable.unsafeCreate(os).subscribeOn(scheduler); for (Subscriber ts : subs) { o2.subscribe(ts); } @@ -719,7 +719,7 @@ public Integer call(Integer calls, Observer observer) { TestSubscriber ts = new TestSubscriber(); TestScheduler scheduler = new TestScheduler(); - Observable.create(os).observeOn(scheduler).subscribe(ts); + Observable.unsafeCreate(os).observeOn(scheduler).subscribe(ts); scheduler.triggerActions(); ts.awaitTerminalEvent(); @@ -748,7 +748,7 @@ public void call(Observer observer) { }}, onUnSubscribe); final AtomicReference exception = new AtomicReference(); - Observable.create(os).subscribe(new Subscriber() { + Observable.unsafeCreate(os).subscribe(new Subscriber() { @Override public void onCompleted() { diff --git a/src/test/java/rx/observers/SerializedObserverTest.java b/src/test/java/rx/observers/SerializedObserverTest.java index b53ac9fd5d..83f49ecd52 100644 --- a/src/test/java/rx/observers/SerializedObserverTest.java +++ b/src/test/java/rx/observers/SerializedObserverTest.java @@ -50,7 +50,7 @@ private Observer serializedObserver(Observer o) { @Test public void testSingleThreadedBasic() { TestSingleThreadedObservable onSubscribe = new TestSingleThreadedObservable("one", "two", "three"); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); Observer aw = serializedObserver(observer); @@ -70,7 +70,7 @@ public void testSingleThreadedBasic() { @Test public void testMultiThreadedBasic() { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three"); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); BusyObserver busyObserver = new BusyObserver(); Observer aw = serializedObserver(busyObserver); @@ -94,7 +94,7 @@ public void testMultiThreadedBasic() { @Test(timeout = 1000) public void testMultiThreadedWithNPE() throws InterruptedException { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); BusyObserver busyObserver = new BusyObserver(); Observer aw = serializedObserver(busyObserver); @@ -128,7 +128,7 @@ public void testMultiThreadedWithNPEinMiddle() { for (int i = 0; i < n; i++) { TestMultiThreadedObservable onSubscribe = new TestMultiThreadedObservable("one", "two", "three", null, "four", "five", "six", "seven", "eight", "nine"); - Observable w = Observable.create(onSubscribe); + Observable w = Observable.unsafeCreate(onSubscribe); BusyObserver busyObserver = new BusyObserver(); Observer aw = serializedObserver(busyObserver); @@ -391,7 +391,7 @@ private static void waitOnThreads(Future... futures) { } private static Observable infinite(final AtomicInteger produced) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber s) { diff --git a/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java b/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java index a7cec8ab86..1a9541997c 100644 --- a/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java +++ b/src/test/java/rx/schedulers/AbstractSchedulerConcurrencyTests.java @@ -297,7 +297,7 @@ public void testRecursionAndOuterUnsubscribe() throws InterruptedException { final CountDownLatch completionLatch = new CountDownLatch(1); final Worker inner = getScheduler().createWorker(); try { - Observable obs = Observable.create(new OnSubscribe() { + Observable obs = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { inner.schedule(new Action0() { diff --git a/src/test/java/rx/schedulers/AbstractSchedulerTests.java b/src/test/java/rx/schedulers/AbstractSchedulerTests.java index 5875328d70..ff5c94071a 100644 --- a/src/test/java/rx/schedulers/AbstractSchedulerTests.java +++ b/src/test/java/rx/schedulers/AbstractSchedulerTests.java @@ -322,7 +322,7 @@ public void call() { @Test public final void testRecursiveSchedulerInObservable() { - Observable obs = Observable.create(new OnSubscribe() { + Observable obs = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { final Scheduler.Worker inner = getScheduler().createWorker(); @@ -362,7 +362,7 @@ public void call(Integer v) { public final void testConcurrentOnNextFailsValidation() throws InterruptedException { final int count = 10; final CountDownLatch latch = new CountDownLatch(count); - Observable o = Observable.create(new OnSubscribe() { + Observable o = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber observer) { @@ -423,7 +423,7 @@ public final void testSubscribeOnNestedConcurrency() throws InterruptedException @Override public Observable call(final String v) { - return Observable.create(new OnSubscribe() { + return Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber observer) { diff --git a/src/test/java/rx/schedulers/TestSchedulerTest.java b/src/test/java/rx/schedulers/TestSchedulerTest.java index 6c7b76e28e..f26939d5bf 100644 --- a/src/test/java/rx/schedulers/TestSchedulerTest.java +++ b/src/test/java/rx/schedulers/TestSchedulerTest.java @@ -181,7 +181,7 @@ public final void testNestedSchedule() { final Action0 calledOp = mock(Action0.class); Observable poller; - poller = Observable.create(new OnSubscribe() { + poller = Observable.unsafeCreate(new OnSubscribe() { @Override public void call(final Subscriber aSubscriber) { inner.schedule(new Action0() { diff --git a/src/test/java/rx/subjects/ReplaySubjectBoundedConcurrencyTest.java b/src/test/java/rx/subjects/ReplaySubjectBoundedConcurrencyTest.java index 72149ee677..954a9b8950 100644 --- a/src/test/java/rx/subjects/ReplaySubjectBoundedConcurrencyTest.java +++ b/src/test/java/rx/subjects/ReplaySubjectBoundedConcurrencyTest.java @@ -52,7 +52,7 @@ public void testReplaySubjectConcurrentSubscribersDoingReplayDontBlockEachOther( @Override public void run() { - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber o) { diff --git a/src/test/java/rx/subjects/ReplaySubjectConcurrencyTest.java b/src/test/java/rx/subjects/ReplaySubjectConcurrencyTest.java index 5e1c350462..69b4c8cf69 100644 --- a/src/test/java/rx/subjects/ReplaySubjectConcurrencyTest.java +++ b/src/test/java/rx/subjects/ReplaySubjectConcurrencyTest.java @@ -52,7 +52,7 @@ public void testReplaySubjectConcurrentSubscribersDoingReplayDontBlockEachOther( @Override public void run() { - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber o) { @@ -174,7 +174,7 @@ public static void concurrencyTest(final ReplaySubject replay) throws Inte @Override public void run() { - Observable.create(new OnSubscribe() { + Observable.unsafeCreate(new OnSubscribe() { @Override public void call(Subscriber o) { From 828db38e3c895a66dab440652c07427455da226d Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sat, 11 Feb 2017 10:36:18 +0100 Subject: [PATCH 29/74] 1.x: create+subscribeOn avoid same-pool deadlock (#5091) --- src/main/java/rx/Observable.java | 46 ++++++- .../operators/OperatorSubscribeOn.java | 114 +++++++++++------- .../operators/OperatorGroupByTest.java | 4 +- .../operators/OperatorSubscribeOnTest.java | 93 ++++++++++++-- 4 files changed, 199 insertions(+), 58 deletions(-) diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 89e1aea07c..bdc59e33ce 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -10333,11 +10333,15 @@ static Subscription subscribe(Subscriber subscriber, Observable + * If there is a {@link #create(Action1, rx.Emitter.BackpressureMode)} type source up in the + * chain, it is recommended to use {@code subscribeOn(scheduler, false)} instead + * to avoid same-pool deadlock because requests pile up behind a eager/blocking emitter. + *

* *

*
Backpressure:
- *
The operator doesn't interfere with backpressure which is determined by the source {@code Observable}'s backpressure - * behavior.
+ *
The operator doesn't interfere with backpressure amount which is determined by the source {@code Observable}'s backpressure + * behavior. However, the upstream is requested from the given scheduler thread.
*
Scheduler:
*
you specify which {@link Scheduler} this operator will use
*
@@ -10349,12 +10353,48 @@ static Subscription subscribe(Subscriber subscriber, ObservableReactiveX operators documentation: SubscribeOn * @see RxJava Threading Examples * @see #observeOn + * @see #subscribeOn(Scheduler, boolean) */ public final Observable subscribeOn(Scheduler scheduler) { + return subscribeOn(scheduler, !(this.onSubscribe instanceof OnSubscribeCreate)); + } + + /** + * Asynchronously subscribes Observers to this Observable on the specified {@link Scheduler} and + * optionally reroutes requests from other threads to the same {@link Scheduler} thread. + *

+ * If there is a {@link #create(Action1, rx.Emitter.BackpressureMode)} type source up in the + * chain, it is recommended to have {@code requestOn} false to avoid same-pool deadlock + * because requests pile up behind a eager/blocking emitter. + *

+ * + *

+ *
Backpressure:
+ *
The operator doesn't interfere with backpressure amount which is determined by the source {@code Observable}'s backpressure + * behavior. However, the upstream is requested from the given scheduler if requestOn is true.
+ *
Scheduler:
+ *
you specify which {@link Scheduler} this operator will use
+ *
+ * + * @param scheduler + * the {@link Scheduler} to perform subscription actions on + * @param requestOn if true, requests are rerouted to the given Scheduler as well (strong pipelining) + * if false, requests coming from any thread are simply forwarded to + * the upstream on the same thread (weak pipelining) + * @return the source Observable modified so that its subscriptions happen on the + * specified {@link Scheduler} + * @see ReactiveX operators documentation: SubscribeOn + * @see RxJava Threading Examples + * @see #observeOn + * @see #subscribeOn(Scheduler) + * @since 1.2.7 - experimental + */ + @Experimental + public final Observable subscribeOn(Scheduler scheduler, boolean requestOn) { if (this instanceof ScalarSynchronousObservable) { return ((ScalarSynchronousObservable)this).scalarScheduleOn(scheduler); } - return unsafeCreate(new OperatorSubscribeOn(this, scheduler)); + return unsafeCreate(new OperatorSubscribeOn(this, scheduler, requestOn)); } /** diff --git a/src/main/java/rx/internal/operators/OperatorSubscribeOn.java b/src/main/java/rx/internal/operators/OperatorSubscribeOn.java index 9b90cbc26a..0be1b01829 100644 --- a/src/main/java/rx/internal/operators/OperatorSubscribeOn.java +++ b/src/main/java/rx/internal/operators/OperatorSubscribeOn.java @@ -31,68 +31,92 @@ public final class OperatorSubscribeOn implements OnSubscribe { final Scheduler scheduler; final Observable source; + final boolean requestOn; - public OperatorSubscribeOn(Observable source, Scheduler scheduler) { + public OperatorSubscribeOn(Observable source, Scheduler scheduler, boolean requestOn) { this.scheduler = scheduler; this.source = source; + this.requestOn = requestOn; } @Override public void call(final Subscriber subscriber) { final Worker inner = scheduler.createWorker(); + + SubscribeOnSubscriber parent = new SubscribeOnSubscriber(subscriber, requestOn, inner, source); + subscriber.add(parent); subscriber.add(inner); - inner.schedule(new Action0() { - @Override - public void call() { - final Thread t = Thread.currentThread(); + inner.schedule(parent); + } - Subscriber s = new Subscriber(subscriber) { - @Override - public void onNext(T t) { - subscriber.onNext(t); - } + static final class SubscribeOnSubscriber extends Subscriber implements Action0 { - @Override - public void onError(Throwable e) { - try { - subscriber.onError(e); - } finally { - inner.unsubscribe(); - } - } + final Subscriber actual; - @Override - public void onCompleted() { - try { - subscriber.onCompleted(); - } finally { - inner.unsubscribe(); - } - } + final boolean requestOn; + + final Worker worker; + + Observable source; + + Thread t; + + SubscribeOnSubscriber(Subscriber actual, boolean requestOn, Worker worker, Observable source) { + this.actual = actual; + this.requestOn = requestOn; + this.worker = worker; + this.source = source; + } - @Override - public void setProducer(final Producer p) { - subscriber.setProducer(new Producer() { + @Override + public void onNext(T t) { + actual.onNext(t); + } + + @Override + public void onError(Throwable e) { + try { + actual.onError(e); + } finally { + worker.unsubscribe(); + } + } + + @Override + public void onCompleted() { + try { + actual.onCompleted(); + } finally { + worker.unsubscribe(); + } + } + + @Override + public void call() { + Observable src = source; + source = null; + t = Thread.currentThread(); + src.unsafeSubscribe(this); + } + + @Override + public void setProducer(final Producer p) { + actual.setProducer(new Producer() { + @Override + public void request(final long n) { + if (t == Thread.currentThread() || !requestOn) { + p.request(n); + } else { + worker.schedule(new Action0() { @Override - public void request(final long n) { - if (t == Thread.currentThread()) { - p.request(n); - } else { - inner.schedule(new Action0() { - @Override - public void call() { - p.request(n); - } - }); - } + public void call() { + p.request(n); } }); } - }; - - source.unsafeSubscribe(s); - } - }); + } + }); + } } } \ No newline at end of file diff --git a/src/test/java/rx/internal/operators/OperatorGroupByTest.java b/src/test/java/rx/internal/operators/OperatorGroupByTest.java index 5d035bcd82..7fd6ab0a2e 100644 --- a/src/test/java/rx/internal/operators/OperatorGroupByTest.java +++ b/src/test/java/rx/internal/operators/OperatorGroupByTest.java @@ -2017,11 +2017,11 @@ public Map call(Action1 t) { throw exception; }}; } - + @Test public void outerConsumedInABoundedManner() { final int[] counter = { 0 }; - + Observable.range(1, 10000) .doOnRequest(new Action1() { @Override diff --git a/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java b/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java index 6eb4abd8e8..b28b3fc27b 100644 --- a/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java +++ b/src/test/java/rx/internal/operators/OperatorSubscribeOnTest.java @@ -26,16 +26,12 @@ import org.junit.Test; -import rx.Observable; +import rx.*; import rx.Observable.OnSubscribe; import rx.Observable.Operator; -import rx.Observer; -import rx.Producer; -import rx.Scheduler; -import rx.Subscriber; -import rx.Subscription; -import rx.functions.Action0; -import rx.observers.TestSubscriber; +import rx.functions.*; +import rx.internal.util.*; +import rx.observers.*; import rx.schedulers.Schedulers; public class OperatorSubscribeOnTest { @@ -267,4 +263,85 @@ public void onNext(Integer t) { ts.assertNoErrors(); } + @Test + public void noSamepoolDeadlock() { + final int n = 4 * RxRingBuffer.SIZE; + + Observable.create(new Action1>() { + @Override + public void call(Emitter e) { + for (int i = 0; i < n; i++) { + e.onNext(i); + try { + Thread.sleep(1); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + e.onCompleted(); + } + }, Emitter.BackpressureMode.DROP) + .map(UtilityFunctions.identity()) + .subscribeOn(Schedulers.io(), false) + .observeOn(Schedulers.computation()) + .test() + .awaitTerminalEvent(5, TimeUnit.SECONDS) + .assertValueCount(n) + .assertNoErrors() + .assertCompleted(); + } + + @Test + public void noSamepoolDeadlockRequestOn() { + final int n = 4 * RxRingBuffer.SIZE; + + Observable.create(new Action1>() { + @Override + public void call(Emitter e) { + for (int i = 0; i < n; i++) { + e.onNext(i); + try { + Thread.sleep(1); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + e.onCompleted(); + } + }, Emitter.BackpressureMode.DROP) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.computation()) + .test() + .awaitTerminalEvent(5, TimeUnit.SECONDS) + .assertValueCount(n) + .assertNoErrors() + .assertCompleted(); + } + + @Test + public void noSamepoolDeadlockRequestOn2() { + final int n = 4 * RxRingBuffer.SIZE; + + Observable.create(new Action1>() { + @Override + public void call(Emitter e) { + for (int i = 0; i < n; i++) { + e.onNext(i); + try { + Thread.sleep(1); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + e.onCompleted(); + } + }, Emitter.BackpressureMode.DROP) + .subscribeOn(Schedulers.io(), true) + .observeOn(Schedulers.computation()) + .test() + .awaitTerminalEvent(5, TimeUnit.SECONDS) + .assertValueCount(RxRingBuffer.SIZE) + .assertNoErrors() + .assertCompleted(); + } } From 5468972024dbbe5ee7cca080bc09a033b9488f37 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sat, 11 Feb 2017 19:06:24 +0100 Subject: [PATCH 30/74] 1.x: add Single.merge(Obs), Obs.flatMapSingle & flatMapCompletable (#5092) --- src/main/java/rx/Observable.java | 136 +++ src/main/java/rx/Single.java | 91 ++ .../OnSubscribeFlatMapCompletable.java | 214 +++++ .../operators/OnSubscribeFlatMapSingle.java | 333 ++++++++ src/test/java/rx/CompletableTest.java | 4 +- .../OnSubscribeFlatMapCompletableTest.java | 557 +++++++++++++ .../OnSubscribeFlatMapSingleTest.java | 782 ++++++++++++++++++ 7 files changed, 2115 insertions(+), 2 deletions(-) create mode 100644 src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java create mode 100644 src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java create mode 100644 src/test/java/rx/internal/operators/OnSubscribeFlatMapCompletableTest.java create mode 100644 src/test/java/rx/internal/operators/OnSubscribeFlatMapSingleTest.java diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index bdc59e33ce..5978412fc7 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -6973,6 +6973,74 @@ public final Observable flatMap(final Func1(collectionSelector, resultSelector)), maxConcurrent); } + /** + * Maps all upstream values to Completables and runs them together until the upstream + * and all inner Completables complete normally. + *
+ *
Backpressure:
+ *
The operator consumes items from upstream in an unbounded manner and ignores downstream backpressure + * as it doesn't emit items but only terminal event.
+ *
Scheduler:
+ *
{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param mapper the function that receives an upstream value and turns it into a Completable + * to be merged. + * @return the new Observable instance + * @see #flatMapCompletable(Func1, boolean, int) + * @since 1.2.7 - experimental + */ + @Experimental + public final Observable flatMapCompletable(Func1 mapper) { + return flatMapCompletable(mapper, false, Integer.MAX_VALUE); + } + + /** + * Maps all upstream values to Completables and runs them together, optionally delaying any errors, until the upstream + * and all inner Completables terminate. + *
+ *
Backpressure:
+ *
The operator consumes items from upstream in an unbounded manner and ignores downstream backpressure + * as it doesn't emit items but only terminal event.
+ *
Scheduler:
+ *
{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param mapper the function that receives an upstream value and turns it into a Completable + * to be merged. + * @param delayErrors if true, errors from the upstream and from the inner Completables get delayed till + * the all of them terminate. + * @return the new Observable instance + * @since 1.2.7 - experimental + * @see #flatMapCompletable(Func1, boolean, int) + */ + @Experimental + public final Observable flatMapCompletable(Func1 mapper, boolean delayErrors) { + return flatMapCompletable(mapper, delayErrors, Integer.MAX_VALUE); + } + + /** + * Maps upstream values to Completables and runs up to the given number of them together at a time, + * optionally delaying any errors, until the upstream and all inner Completables terminate. + *
+ *
Backpressure:
+ *
The operator consumes at most maxConcurrent items from upstream and one-by-one after as the inner + * Completables terminate. The operator ignores downstream backpressure as it doesn't emit items but + * only the terminal event.
+ *
Scheduler:
+ *
{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param mapper the function that receives an upstream value and turns it into a Completable + * to be merged. + * @param delayErrors if true, errors from the upstream and from the inner Completables get delayed till + * the all of them terminate. + * @param maxConcurrency the maximum number of inner Completables to run at a time + * @return the new Observable instance + * @since 1.2.7 - experimental + */ + @Experimental + public final Observable flatMapCompletable(Func1 mapper, boolean delayErrors, int maxConcurrency) { + return unsafeCreate(new OnSubscribeFlatMapCompletable(this, mapper, delayErrors, maxConcurrency)); + } + /** * Returns an Observable that merges each item emitted by the source Observable with the values in an * Iterable corresponding to that item that is generated by a selector. @@ -7106,6 +7174,74 @@ public final Observable flatMapIterable(Func1)flatMap(OperatorMapPair.convertSelector(collectionSelector), resultSelector, maxConcurrent); } + /** + * Maps all upstream values to Singles and runs them together until the upstream + * and all inner Singles complete normally. + *
+ *
Backpressure:
+ *
The operator consumes items from upstream in an unbounded manner and honors downstream backpressure.
+ *
Scheduler:
+ *
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the inner Singles and the resulting Observable + * @param mapper the function that receives an upstream value and turns it into a Single + * to be merged. + * @return the new Observable instance + * @see #flatMapSingle(Func1, boolean, int) + * @since 1.2.7 - experimental + */ + @Experimental + public final Observable flatMapSingle(Func1> mapper) { + return flatMapSingle(mapper, false, Integer.MAX_VALUE); + } + + /** + * Maps all upstream values to Singles and runs them together, optionally delaying any errors, until the upstream + * and all inner Singles terminate. + *
+ *
Backpressure:
+ *
The operator consumes items from upstream in an unbounded manner and honors downstream backpressure.
+ *
Scheduler:
+ *
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the inner Singles and the resulting Observable + * @param mapper the function that receives an upstream value and turns it into a Single + * to be merged. + * @param delayErrors if true, errors from the upstream and from the inner Singles get delayed till + * the all of them terminate. + * @return the new Observable instance + * @since 1.2.7 - experimental + * @see #flatMapSingle(Func1, boolean, int) + */ + @Experimental + public final Observable flatMapSingle(Func1> mapper, boolean delayErrors) { + return flatMapSingle(mapper, delayErrors, Integer.MAX_VALUE); + } + + /** + * Maps upstream values to Singles and runs up to the given number of them together at a time, + * optionally delaying any errors, until the upstream and all inner Singles terminate. + *
+ *
Backpressure:
+ *
The operator consumes at most maxConcurrent items from upstream and one-by-one after as the inner + * Singles terminate. The operator honors downstream backpressure.
+ *
Scheduler:
+ *
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the inner Singles and the resulting Observable + * @param mapper the function that receives an upstream value and turns it into a Single + * to be merged. + * @param delayErrors if true, errors from the upstream and from the inner Singles get delayed till + * the all of them terminate. + * @param maxConcurrency the maximum number of inner Singles to run at a time + * @return the new Observable instance + * @since 1.2.7 - experimental + */ + @Experimental + public final Observable flatMapSingle(Func1> mapper, boolean delayErrors, int maxConcurrency) { + return unsafeCreate(new OnSubscribeFlatMapSingle(this, mapper, delayErrors, maxConcurrency)); + } + /** * Subscribes to the {@link Observable} and receives notifications for each element. *

diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index 709b709f41..a1614137f6 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -930,6 +930,97 @@ public static Observable merge(Single t1, Single + *

Backpressure:
+ *
The operator consumes items from the Observable in an unbounded manner and honors downstream backpressure.
+ *
Scheduler:
+ *
{@code merge} does not operate by default on a particular {@link Scheduler}.
+ * + * @param the value type of the inner Singles and the resulting Observable + * @param sources the Observable that emits Singles to be merged + * @return the new Observable instance + * @see #merge(Observable, int) + * @see #mergeDelayError(Observable) + * @see #mergeDelayError(Observable, int) + * @since 1.2.7 - experimental + */ + @Experimental + public static Observable merge(Observable> sources) { + return merge(sources, Integer.MAX_VALUE); + } + + /** + * Merges the Singles emitted by the Observable and runs up to the given number of them together at a time, + * until the Observable and all inner Singles terminate. + *
+ *
Backpressure:
+ *
The operator consumes at most maxConcurrent items from the Observable and one-by-one after as the inner + * Singles terminate. The operator ignores downstream backpressure as it doesn't emit items but + * only the terminal event.
+ *
Scheduler:
+ *
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the inner Singles and the resulting Observable + * @param sources the Observable that emits Singles to be merged + * @param maxConcurrency the maximum number of inner Singles to run at a time + * @return the new Observable instance + * @since 1.2.7 - experimental + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Experimental + public static Observable merge(Observable> sources, int maxConcurrency) { + return sources.flatMapSingle((Func1)UtilityFunctions.identity(), false, maxConcurrency); + } + + /** + * Merges all Singles emitted by the Observable and runs them together, + * delaying errors from them and the Observable, until the source + * Observable and all inner Singles complete normally. + *
+ *
Backpressure:
+ *
The operator consumes items from the Observable in an unbounded manner and honors downstream backpressure.
+ *
Scheduler:
+ *
{@code merge} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the inner Singles and the resulting Observable + * @param sources the Observable that emits Singles to be merged + * @return the new Observable instance + * @see #mergeDelayError(Observable, int) + * @see #merge(Observable) + * @see #merge(Observable, int) + * @since 1.2.7 - experimental + */ + @Experimental + public static Observable mergeDelayError(Observable> sources) { + return merge(sources, Integer.MAX_VALUE); + } + + /** + * Merges the Singles emitted by the Observable and runs up to the given number of them together at a time, + * delaying errors from them and the Observable, until the Observable and all inner Singles terminate. + *
+ *
Backpressure:
+ *
The operator consumes at most maxConcurrent items from the Observable and one-by-one after as the inner + * Singles terminate. The operator ignores downstream backpressure as it doesn't emit items but + * only the terminal event.
+ *
Scheduler:
+ *
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the value type of the inner Singles and the resulting Observable + * @param sources the Observable that emits Singles to be merged + * @param maxConcurrency the maximum number of inner Singles to run at a time + * @return the new Observable instance + * @since 1.2.7 - experimental + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Experimental + public static Observable mergeDelayError(Observable> sources, int maxConcurrency) { + return sources.flatMapSingle((Func1)UtilityFunctions.identity(), true, maxConcurrency); + } + /** * Returns a Single that emits the results of a specified combiner function applied to two items emitted by * two other Singles. diff --git a/src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java b/src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java new file mode 100644 index 0000000000..bfb8d6d69a --- /dev/null +++ b/src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java @@ -0,0 +1,214 @@ +/** + * Copyright 2017 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.internal.operators; + +import java.util.concurrent.atomic.*; + +import rx.*; +import rx.exceptions.Exceptions; +import rx.functions.Func1; +import rx.internal.util.ExceptionsUtils; +import rx.plugins.RxJavaHooks; +import rx.subscriptions.CompositeSubscription; + +/** + * Maps upstream values to Completables and merges them, up to a given + * number of them concurrently, optionally delaying errors. + * @param the upstream value type + * @since 1.2.7 - experimental + */ +public final class OnSubscribeFlatMapCompletable implements Observable.OnSubscribe { + + final Observable source; + + final Func1 mapper; + + final boolean delayErrors; + + final int maxConcurrency; + + public OnSubscribeFlatMapCompletable(Observable source, Func1 mapper, + boolean delayErrors, int maxConcurrency) { + if (mapper == null) { + throw new NullPointerException("mapper is null"); + } + if (maxConcurrency <= 0) { + throw new IllegalArgumentException("maxConcurrency > 0 required but it was " + maxConcurrency); + } + this.source = source; + this.mapper = mapper; + this.delayErrors = delayErrors; + this.maxConcurrency = maxConcurrency; + } + + @Override + public void call(Subscriber child) { + FlatMapCompletableSubscriber parent = new FlatMapCompletableSubscriber(child, mapper, delayErrors, maxConcurrency); + child.add(parent); + child.add(parent.set); + source.unsafeSubscribe(parent); + } + + static final class FlatMapCompletableSubscriber extends Subscriber { + + final Subscriber actual; + + final Func1 mapper; + + final boolean delayErrors; + + final int maxConcurrency; + + final AtomicInteger wip; + + final CompositeSubscription set; + + final AtomicReference errors; + + FlatMapCompletableSubscriber(Subscriber actual, Func1 mapper, + boolean delayErrors, int maxConcurrency) { + this.actual = actual; + this.mapper = mapper; + this.delayErrors = delayErrors; + this.maxConcurrency = maxConcurrency; + this.wip = new AtomicInteger(1); + this.errors = new AtomicReference(); + this.set = new CompositeSubscription(); + this.request(maxConcurrency != Integer.MAX_VALUE ? maxConcurrency : Long.MAX_VALUE); + } + + @Override + public void onNext(T t) { + Completable c; + + try { + c = mapper.call(t); + if (c == null) { + throw new NullPointerException("The mapper returned a null Completable"); + } + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + unsubscribe(); + onError(ex); + return; + } + + InnerSubscriber inner = new InnerSubscriber(); + set.add(inner); + wip.getAndIncrement(); + + c.unsafeSubscribe(inner); + } + + @Override + public void onError(Throwable e) { + if (delayErrors) { + ExceptionsUtils.addThrowable(errors, e); + onCompleted(); + } else { + set.unsubscribe(); + if (errors.compareAndSet(null, e)) { + actual.onError(ExceptionsUtils.terminate(errors)); + } else { + RxJavaHooks.onError(e); + } + } + } + + @Override + public void onCompleted() { + done(); + } + + boolean done() { + if (wip.decrementAndGet() == 0) { + Throwable ex = ExceptionsUtils.terminate(errors); + if (ex != null) { + actual.onError(ex); + } else { + actual.onCompleted(); + } + return true; + } + return false; + } + + public void innerError(InnerSubscriber inner, Throwable e) { + set.remove(inner); + if (delayErrors) { + ExceptionsUtils.addThrowable(errors, e); + if (!done() && maxConcurrency != Integer.MAX_VALUE) { + request(1); + } + } else { + set.unsubscribe(); + unsubscribe(); + if (errors.compareAndSet(null, e)) { + actual.onError(ExceptionsUtils.terminate(errors)); + } else { + RxJavaHooks.onError(e); + } + } + } + + public void innerComplete(InnerSubscriber inner) { + set.remove(inner); + if (!done() && maxConcurrency != Integer.MAX_VALUE) { + request(1); + } + } + + final class InnerSubscriber + extends AtomicReference + implements CompletableSubscriber, Subscription { + + private static final long serialVersionUID = -8588259593722659900L; + + @Override + public void unsubscribe() { + Subscription s = getAndSet(this); + if (s != null && s != this) { + s.unsubscribe(); + } + } + + @Override + public boolean isUnsubscribed() { + return get() == this; + } + + @Override + public void onCompleted() { + innerComplete(this); + } + + @Override + public void onError(Throwable e) { + innerError(this, e); + } + + @Override + public void onSubscribe(Subscription d) { + if (!compareAndSet(null, d)) { + d.unsubscribe(); + if (get() != this) { + RxJavaHooks.onError(new IllegalStateException("Subscription already set!")); + } + } + } + } + } +} diff --git a/src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java b/src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java new file mode 100644 index 0000000000..b64a4ef760 --- /dev/null +++ b/src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java @@ -0,0 +1,333 @@ +/** + * Copyright 2017 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.internal.operators; + +import java.util.Queue; +import java.util.concurrent.atomic.*; + +import rx.*; +import rx.exceptions.Exceptions; +import rx.functions.Func1; +import rx.internal.util.ExceptionsUtils; +import rx.internal.util.atomic.MpscLinkedAtomicQueue; +import rx.internal.util.unsafe.*; +import rx.plugins.RxJavaHooks; +import rx.subscriptions.CompositeSubscription; + +/** + * Maps upstream values to Singles and merges them, up to a given + * number of them concurrently, optionally delaying errors. + * @param the upstream value type + * @param the inner Singles and result value type + * @since 1.2.7 - experimental + */ +public final class OnSubscribeFlatMapSingle implements Observable.OnSubscribe { + + final Observable source; + + final Func1> mapper; + + final boolean delayErrors; + + final int maxConcurrency; + + public OnSubscribeFlatMapSingle(Observable source, Func1> mapper, + boolean delayErrors, int maxConcurrency) { + if (mapper == null) { + throw new NullPointerException("mapper is null"); + } + if (maxConcurrency <= 0) { + throw new IllegalArgumentException("maxConcurrency > 0 required but it was " + maxConcurrency); + } + this.source = source; + this.mapper = mapper; + this.delayErrors = delayErrors; + this.maxConcurrency = maxConcurrency; + } + + @Override + public void call(Subscriber child) { + FlatMapSingleSubscriber parent = new FlatMapSingleSubscriber(child, mapper, delayErrors, maxConcurrency); + child.add(parent.set); + child.add(parent.requested); + child.setProducer(parent.requested); + source.unsafeSubscribe(parent); + } + + static final class FlatMapSingleSubscriber extends Subscriber { + + final Subscriber actual; + + final Func1> mapper; + + final boolean delayErrors; + + final int maxConcurrency; + + final AtomicInteger wip; + + final AtomicInteger active; + + final CompositeSubscription set; + + final AtomicReference errors; + + final Queue queue; + + final Requested requested; + + volatile boolean done; + + volatile boolean cancelled; + + FlatMapSingleSubscriber(Subscriber actual, + Func1> mapper, + boolean delayErrors, int maxConcurrency) { + this.actual = actual; + this.mapper = mapper; + this.delayErrors = delayErrors; + this.maxConcurrency = maxConcurrency; + this.wip = new AtomicInteger(); + this.errors = new AtomicReference(); + this.requested = new Requested(); + this.set = new CompositeSubscription(); + this.active = new AtomicInteger(); + if (UnsafeAccess.isUnsafeAvailable()) { + queue = new MpscLinkedQueue(); + } else { + queue = new MpscLinkedAtomicQueue(); + } + this.request(maxConcurrency != Integer.MAX_VALUE ? maxConcurrency : Long.MAX_VALUE); + } + + @Override + public void onNext(T t) { + Single c; + + try { + c = mapper.call(t); + if (c == null) { + throw new NullPointerException("The mapper returned a null Single"); + } + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + unsubscribe(); + onError(ex); + return; + } + + InnerSubscriber inner = new InnerSubscriber(); + set.add(inner); + active.incrementAndGet(); + + c.subscribe(inner); + } + + @Override + public void onError(Throwable e) { + if (delayErrors) { + ExceptionsUtils.addThrowable(errors, e); + } else { + set.unsubscribe(); + if (!errors.compareAndSet(null, e)) { + RxJavaHooks.onError(e); + return; + } + } + done = true; + drain(); + } + + @Override + public void onCompleted() { + done = true; + drain(); + } + + void innerSuccess(InnerSubscriber inner, R value) { + queue.offer(NotificationLite.next(value)); + set.remove(inner); + active.decrementAndGet(); + drain(); + } + + void innerError(InnerSubscriber inner, Throwable e) { + if (delayErrors) { + ExceptionsUtils.addThrowable(errors, e); + set.remove(inner); + if (!done && maxConcurrency != Integer.MAX_VALUE) { + request(1); + } + } else { + set.unsubscribe(); + unsubscribe(); + if (!errors.compareAndSet(null, e)) { + RxJavaHooks.onError(e); + return; + } + done = true; + } + active.decrementAndGet(); + drain(); + } + + void drain() { + if (wip.getAndIncrement() != 0) { + return; + } + + int missed = 1; + Subscriber a = actual; + Queue q = queue; + boolean delayError = this.delayErrors; + AtomicInteger act = active; + + for (;;) { + long r = requested.get(); + long e = 0L; + + while (e != r) { + if (cancelled) { + q.clear(); + return; + } + + boolean d = done; + + if (!delayError && d) { + Throwable ex = errors.get(); + if (ex != null) { + q.clear(); + a.onError(ExceptionsUtils.terminate(errors)); + return; + } + } + + Object o = q.poll(); + + boolean empty = o == null; + + if (d && act.get() == 0 && empty) { + Throwable ex = errors.get(); + if (ex != null) { + a.onError(ExceptionsUtils.terminate(errors)); + } else { + a.onCompleted(); + } + return; + } + + if (empty) { + break; + } + + a.onNext(NotificationLite.getValue(o)); + + e++; + } + + if (e == r) { + if (cancelled) { + q.clear(); + return; + } + + if (done) { + if (delayError) { + if (act.get() == 0 && q.isEmpty()) { + Throwable ex = errors.get(); + if (ex != null) { + a.onError(ExceptionsUtils.terminate(errors)); + } else { + a.onCompleted(); + } + return; + } + } else { + Throwable ex = errors.get(); + if (ex != null) { + q.clear(); + a.onError(ExceptionsUtils.terminate(errors)); + return; + } + else if (act.get() == 0 && q.isEmpty()) { + a.onCompleted(); + return; + } + } + } + } + + if (e != 0L) { + requested.produced(e); + if (!done && maxConcurrency != Integer.MAX_VALUE) { + request(e); + } + } + + missed = wip.addAndGet(-missed); + if (missed == 0) { + break; + } + } + } + + final class Requested extends AtomicLong implements Producer, Subscription { + + private static final long serialVersionUID = -887187595446742742L; + + @Override + public void request(long n) { + if (n > 0L) { + BackpressureUtils.getAndAddRequest(this, n); + drain(); + } + } + + void produced(long e) { + BackpressureUtils.produced(this, e); + } + + @Override + public void unsubscribe() { + cancelled = true; + FlatMapSingleSubscriber.this.unsubscribe(); + if (wip.getAndIncrement() == 0) { + queue.clear(); + } + } + + @Override + public boolean isUnsubscribed() { + return cancelled; + } + } + + final class InnerSubscriber extends SingleSubscriber { + + @Override + public void onSuccess(R t) { + innerSuccess(this, t); + } + + @Override + public void onError(Throwable error) { + innerError(this, error); + } + } + } +} diff --git a/src/test/java/rx/CompletableTest.java b/src/test/java/rx/CompletableTest.java index 23418b60e6..3f34a983ca 100644 --- a/src/test/java/rx/CompletableTest.java +++ b/src/test/java/rx/CompletableTest.java @@ -93,7 +93,7 @@ public void remove() { /** * A class containing a completable instance and counts the number of subscribers. */ - static final class NormalCompletable extends AtomicInteger { + public static final class NormalCompletable extends AtomicInteger { /** */ private static final long serialVersionUID = 7192337844700923752L; @@ -119,7 +119,7 @@ public void assertSubscriptions(int n) { * A class containing a completable instance that emits a TestException and counts * the number of subscribers. */ - static final class ErrorCompletable extends AtomicInteger { + public static final class ErrorCompletable extends AtomicInteger { /** */ private static final long serialVersionUID = 7192337844700923752L; diff --git a/src/test/java/rx/internal/operators/OnSubscribeFlatMapCompletableTest.java b/src/test/java/rx/internal/operators/OnSubscribeFlatMapCompletableTest.java new file mode 100644 index 0000000000..2b88387400 --- /dev/null +++ b/src/test/java/rx/internal/operators/OnSubscribeFlatMapCompletableTest.java @@ -0,0 +1,557 @@ +/** + * Copyright 2017 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.internal.operators; + +import static org.junit.Assert.*; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.*; + +import rx.*; +import rx.CompletableTest.*; +import rx.Observable; +import rx.exceptions.*; +import rx.functions.*; +import rx.internal.util.UtilityFunctions; +import rx.observers.*; +import rx.schedulers.Schedulers; +import rx.subjects.PublishSubject; +import rx.subscriptions.Subscriptions; + +public class OnSubscribeFlatMapCompletableTest implements Action0, Action1 { + + final AtomicInteger calls = new AtomicInteger(); + + /** A normal Completable object. */ + final NormalCompletable normal = new NormalCompletable(); + + /** An error Completable object. */ + final ErrorCompletable error = new ErrorCompletable(); + + final Func1 identity = UtilityFunctions.identity(); + + @Override + public void call() { + calls.getAndIncrement(); + } + + @Override + public void call(Object t) { + calls.getAndIncrement(); + } + + void assertCalls(int n) { + assertEquals(n, calls.get()); + } + + @Test + public void normal() { + Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.complete().doOnCompleted(OnSubscribeFlatMapCompletableTest.this); + } + }) + .test() + .assertResult(); + + assertCalls(10); + } + + @Test + public void normalMaxConcurrent() { + for (int i = 1; i < 10; i++) { + calls.set(0); + + Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.complete() + .observeOn(Schedulers.computation()) + .doOnCompleted(OnSubscribeFlatMapCompletableTest.this); + } + }, false, i) + .test() + .awaitTerminalEvent(5, TimeUnit.SECONDS) + .assertResult(); + + assertCalls(10); + } + } + + @Test + public void error() { + Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.error(new TestException()).doOnError(OnSubscribeFlatMapCompletableTest.this); + } + }) + .test() + .assertFailure(TestException.class); + + assertCalls(1); + } + + @Test + public void errorDelayed() { + AssertableSubscriber as = Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.error(new TestException()).doOnError(OnSubscribeFlatMapCompletableTest.this); + } + }, true) + .test() + .assertFailure(CompositeException.class); + + List onErrorEvents = as.getOnErrorEvents(); + + assertEquals(onErrorEvents.toString(), 1, onErrorEvents.size()); + + onErrorEvents = ((CompositeException)onErrorEvents.get(0)).getExceptions(); + + assertEquals(onErrorEvents.toString(), 10, onErrorEvents.size()); + + for (Throwable ex : onErrorEvents) { + assertTrue(ex.toString(), ex instanceof TestException); + } + + assertCalls(10); + } + + @Test + public void errorDelayedMaxConcurrency() { + AssertableSubscriber as = Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.error(new TestException()).doOnError(OnSubscribeFlatMapCompletableTest.this); + } + }, true, 1) + .test() + .assertFailure(CompositeException.class); + + List onErrorEvents = as.getOnErrorEvents(); + + assertEquals(onErrorEvents.toString(), 1, onErrorEvents.size()); + + onErrorEvents = ((CompositeException)onErrorEvents.get(0)).getExceptions(); + + assertEquals(onErrorEvents.toString(), 10, onErrorEvents.size()); + + for (Throwable ex : onErrorEvents) { + assertTrue(ex.toString(), ex instanceof TestException); + } + + assertCalls(10); + } + + @Test + public void mapperThrows() { + Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void mapperNull() { + Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return null; + } + }) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void paramValidation() { + try { + Observable.range(1, 10) + .flatMapCompletable(null); + fail("Should have thrown"); + } catch (NullPointerException ex) { + assertEquals("mapper is null", ex.getMessage()); + } + + try { + Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.complete(); + } + }, false, 0); + fail("Should have thrown"); + } catch (IllegalArgumentException ex) { + assertEquals("maxConcurrency > 0 required but it was 0", ex.getMessage()); + } + + try { + Observable.range(1, 10) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.complete(); + } + }, true, -99); + fail("Should have thrown"); + } catch (IllegalArgumentException ex) { + assertEquals("maxConcurrency > 0 required but it was -99", ex.getMessage()); + } + } + + @Test + public void mainErrorDelayed() { + Observable.range(1, 10).concatWith(Observable.error(new TestException())) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return Completable.complete().doOnCompleted(OnSubscribeFlatMapCompletableTest.this); + } + }, true) + .test() + .assertFailure(TestException.class); + + assertCalls(10); + } + + @Test + public void innerDoubleOnSubscribe() { + final CompletableSubscriber[] inner = { null }; + + AssertableSubscriber as = Observable.just(1) + .flatMapCompletable(new Func1() { + @Override + public Completable call(Integer t) { + return Completable.create(new Completable.OnSubscribe() { + @Override + public void call(CompletableSubscriber t) { + OnSubscribeFlatMapCompletableTest.this.call(); + Subscription s1 = Subscriptions.empty(); + + t.onSubscribe(s1); + + Subscription s2 = Subscriptions.empty(); + + t.onSubscribe(s2); + + if (s2.isUnsubscribed()) { + OnSubscribeFlatMapCompletableTest.this.call(); + } + + t.onCompleted(); + + inner[0] = t; + } + }); + } + }) + .test() + .assertResult(); + + assertCalls(2); + + inner[0].onError(new TestException()); + + as.assertResult(); + } + + @Test + public void mainErrorUnsubscribes() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(); + + ps0.flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return v == 0 ? ps1.toCompletable() : ps2.toCompletable(); + } + }).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onError(new TestException()); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + + @Test + public void innerErrorUnsubscribes() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(); + + ps0.flatMapCompletable(new Func1() { + @Override + public Completable call(Integer v) { + return v == 0 ? ps1.toCompletable() : ps2.toCompletable(); + } + }).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps1.onError(new TestException()); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + + + @Test(timeout = 5000) + public void mergeObservableEmpty() { + Completable c = Observable.empty().flatMapCompletable(identity).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000, expected = TestException.class) + public void mergeObservableError() { + Completable c = Observable.error(new TestException()).flatMapCompletable(identity).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000) + public void mergeObservableSingle() { + Completable c = Observable.just(normal.completable).flatMapCompletable(identity).toCompletable(); + + c.await(); + + normal.assertSubscriptions(1); + } + + @Test(timeout = 5000, expected = TestException.class) + public void mergeObservableSingleThrows() { + Completable c = Observable.just(error.completable).flatMapCompletable(identity).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000) + public void mergeObservableMany() { + Completable c = Observable.just(normal.completable).repeat(3).flatMapCompletable(identity).toCompletable(); + + c.await(); + + normal.assertSubscriptions(3); + } + + @Test(timeout = 5000, expected = TestException.class) + public void mergeObservableManyOneThrows() { + Completable c = Observable.just(normal.completable, error.completable).flatMapCompletable(identity).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000) + public void mergeObservableMaxConcurrent() { + final List requested = new ArrayList(); + Observable cs = Observable + .just(normal.completable) + .repeat(10) + .doOnRequest(new Action1() { + @Override + public void call(Long v) { + requested.add(v); + } + }); + + Completable c = cs.flatMapCompletable(identity, false, 5).toCompletable(); + + c.await(); + + // FIXME this request pattern looks odd because all 10 completions trigger 1 requests + Assert.assertEquals(Arrays.asList(5L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), requested); + } + + @Test(timeout = 5000) + public void mergeDelayErrorObservableEmpty() { + Completable c = Observable.empty().flatMapCompletable(identity, true).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000, expected = TestException.class) + public void mergeDelayErrorObservableError() { + Completable c = Observable.error(new TestException()).flatMapCompletable(identity, true).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000) + public void mergeDelayErrorObservableSingle() { + Completable c = Observable.just(normal.completable).flatMapCompletable(identity, true).toCompletable(); + + c.await(); + + normal.assertSubscriptions(1); + } + + @Test(timeout = 5000, expected = TestException.class) + public void mergeDelayErrorObservableSingleThrows() { + Completable c = Observable.just(error.completable).flatMapCompletable(identity, true).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000) + public void mergeDelayErrorObservableMany() { + Completable c = Observable.just(normal.completable).repeat(3).flatMapCompletable(identity, true).toCompletable(); + + c.await(); + + normal.assertSubscriptions(3); + } + + @Test(timeout = 5000, expected = TestException.class) + public void mergeDelayErrorObservableManyOneThrows() { + Completable c = Observable.just(normal.completable, error.completable).flatMapCompletable(identity, true).toCompletable(); + + c.await(); + } + + @Test(timeout = 5000) + public void mergeDelayErrorObservableMaxConcurrent() { + final List requested = new ArrayList(); + Observable cs = Observable + .just(normal.completable) + .repeat(10) + .doOnRequest(new Action1() { + @Override + public void call(Long v) { + requested.add(v); + } + }); + + Completable c = cs.flatMapCompletable(identity, true, 5).toCompletable(); + + c.await(); + + // FIXME this request pattern looks odd because all 10 completions trigger 1 requests + Assert.assertEquals(Arrays.asList(5L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), requested); + } + + @Test + public void asyncObservables() { + + final int[] calls = { 0 }; + + Observable.range(1, 5).map(new Func1() { + @Override + public Completable call(final Integer v) { + System.out.println("Mapping " + v); + return Completable.fromAction(new Action0() { + @Override + public void call() { + System.out.println("Processing " + (calls[0] + 1)); + calls[0]++; + } + }) + .subscribeOn(Schedulers.io()) + .doOnCompleted(new Action0() { + @Override + public void call() { + System.out.println("Inner complete " + v); + } + }) + .observeOn(Schedulers.computation()); + } + }).flatMapCompletable(identity, false, 1).toCompletable() + .test() + .awaitTerminalEventAndUnsubscribeOnTimeout(5, TimeUnit.SECONDS) + .assertResult(); + + Assert.assertEquals(5, calls[0]); + } + +} diff --git a/src/test/java/rx/internal/operators/OnSubscribeFlatMapSingleTest.java b/src/test/java/rx/internal/operators/OnSubscribeFlatMapSingleTest.java new file mode 100644 index 0000000000..3da2ac389c --- /dev/null +++ b/src/test/java/rx/internal/operators/OnSubscribeFlatMapSingleTest.java @@ -0,0 +1,782 @@ +/** + * Copyright 2017 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.internal.operators; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.*; +import org.junit.Test; + +import rx.*; +import rx.Observable; +import rx.exceptions.*; +import rx.functions.*; +import rx.observers.*; +import rx.schedulers.Schedulers; +import rx.subjects.PublishSubject; + +public class OnSubscribeFlatMapSingleTest implements Action0, Action1 { + + final AtomicInteger calls = new AtomicInteger(); + + final Action1 errorConsumer = new Action1() { + @Override + public void call(Throwable e) { + OnSubscribeFlatMapSingleTest.this.call(e); + } + }; + + @Override + public void call() { + calls.getAndIncrement(); + } + + @Override + public void call(Object t) { + calls.getAndIncrement(); + } + + void assertCalls(int n) { + assertEquals(n, calls.get()); + } + + @Test + public void normal() { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }) + .test() + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void normalBackpressured() { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }) + .test(0L) + .assertNoValues() + .requestMore(1) + .assertValues(1) + .requestMore(2) + .assertValues(1, 2, 3) + .requestMore(3) + .assertValues(1, 2, 3, 4, 5, 6) + .requestMore(4) + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void normalMaxConcurrencyBackpressured() { + for (int i = 1; i < 16; i++) { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }, false, i) + .test(0L) + .assertNoValues() + .requestMore(1) + .assertValues(1) + .requestMore(2) + .assertValues(1, 2, 3) + .requestMore(3) + .assertValues(1, 2, 3, 4, 5, 6) + .requestMore(4) + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + } + + @Test + public void normalMaxConcurrent() { + for (int i = 1; i < 16; i++) { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }, false, i) + .test() + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + } + + @Test + public void normalMaxConcurrentAsync() { + for (int i = 1; i < 2; i++) { + AssertableSubscriber as = Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v).observeOn(Schedulers.computation()); + } + }, false, i) + .test(); + + as.awaitTerminalEvent(5, TimeUnit.SECONDS) + .assertValueCount(10) + .assertNoErrors() + .assertCompleted(); + + Set set = new HashSet(as.getOnNextEvents()); + + for (int j = 1; j < 11; j++) { + assertTrue("" + set, set.contains(j)); + } + } + } + + @Test + public void justMaxConcurrentAsync() { + AssertableSubscriber as = Observable.just(1) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v).observeOn(Schedulers.computation()); + } + }, false, 1) + .test(); + + as.awaitTerminalEvent(5, TimeUnit.SECONDS) + .assertResult(1); + } + + @Test + public void error() { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.error(new TestException()).doOnError(errorConsumer); + } + }) + .test() + .assertFailure(TestException.class); + + assertCalls(1); + } + + @Test + public void errorDelayed() { + AssertableSubscriber as = Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.error(new TestException()).doOnError(errorConsumer); + } + }, true) + .test() + .assertFailure(CompositeException.class); + + List onErrorEvents = as.getOnErrorEvents(); + + assertEquals(onErrorEvents.toString(), 1, onErrorEvents.size()); + + onErrorEvents = ((CompositeException)onErrorEvents.get(0)).getExceptions(); + + assertEquals(onErrorEvents.toString(), 10, onErrorEvents.size()); + + for (Throwable ex : onErrorEvents) { + assertTrue(ex.toString(), ex instanceof TestException); + } + + assertCalls(10); + } + + @Test + public void errorDelayedMaxConcurrency() { + AssertableSubscriber as = Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.error(new TestException()).doOnError(errorConsumer); + } + }, true, 1) + .test() + .assertFailure(CompositeException.class); + + List onErrorEvents = as.getOnErrorEvents(); + + assertEquals(onErrorEvents.toString(), 1, onErrorEvents.size()); + + onErrorEvents = ((CompositeException)onErrorEvents.get(0)).getExceptions(); + + assertEquals(onErrorEvents.toString(), 10, onErrorEvents.size()); + + for (Throwable ex : onErrorEvents) { + assertTrue(ex.toString(), ex instanceof TestException); + } + + assertCalls(10); + } + + @Test + public void mapperThrows() { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + throw new TestException(); + } + }) + .test() + .assertFailure(TestException.class); + } + + @Test + public void mapperNull() { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return null; + } + }) + .test() + .assertFailure(NullPointerException.class); + } + + @Test + public void paramValidation() { + try { + Observable.range(1, 10) + .flatMapSingle(null); + fail("Should have thrown"); + } catch (NullPointerException ex) { + assertEquals("mapper is null", ex.getMessage()); + } + + try { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }, false, 0); + fail("Should have thrown"); + } catch (IllegalArgumentException ex) { + assertEquals("maxConcurrency > 0 required but it was 0", ex.getMessage()); + } + + try { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }, true, -99); + fail("Should have thrown"); + } catch (IllegalArgumentException ex) { + assertEquals("maxConcurrency > 0 required but it was -99", ex.getMessage()); + } + } + + @Test + public void mainErrorDelayed() { + Observable.range(1, 10).concatWith(Observable.error(new TestException())) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v).doOnSuccess(OnSubscribeFlatMapSingleTest.this); + } + }, true) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + + assertCalls(10); + } + + @Test + public void mainErrorUnsubscribes() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(); + + ps0.flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return v == 0 ? ps1.toSingle() : ps2.toSingle(); + } + }).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onError(new TestException()); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + + @Test + public void innerErrorUnsubscribes() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(); + + ps0.flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return v == 0 ? ps1.toSingle() : ps2.toSingle(); + } + }).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps1.onError(new TestException()); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + + @Test + public void take() { + Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }) + .take(5) + .test() + .assertResult(1, 2, 3, 4, 5); + } + + + @Test + public void unsubscribe() { + AssertableSubscriber as = Observable.range(1, 10) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }) + .test(0) + ; + + as.unsubscribe(); + + as.assertNoValues().assertNoErrors().assertNotCompleted(); + } + + @Test + public void mainErrorUnsubscribesNoRequest() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(0L); + + ps0.flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return v == 0 ? ps1.toSingle() : ps2.toSingle(); + } + }).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onError(new TestException()); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + + @Test + public void innerErrorUnsubscribesNoRequest() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(0L); + + ps0.flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return v == 0 ? ps1.toSingle() : ps2.toSingle(); + } + }).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps1.onError(new TestException()); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + @Test + public void mainErrorUnsubscribesNoRequestDelayError() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(0L); + + ps0.flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return v == 0 ? ps1.toSingle() : ps2.toSingle(); + } + }, true).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onError(new TestException()); + ps1.onNext(3); + ps1.onCompleted(); + ps2.onNext(4); + ps2.onCompleted(); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + + as.requestMore(2); + as.assertValues(3, 4); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + + @Test + public void innerErrorUnsubscribesNoRequestDelayError() { + PublishSubject ps0 = PublishSubject.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + + TestSubscriber as = TestSubscriber.create(0L); + + ps0.flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return v == 0 ? ps1.toSingle() : ps2.toSingle(); + } + }, true).unsafeSubscribe(as); + + assertTrue(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(0); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onNext(1); + + assertTrue(ps0.hasObservers()); + assertTrue(ps1.hasObservers()); + assertTrue(ps2.hasObservers()); + as.assertNoValues(); + as.assertNoErrors(); + as.assertNotCompleted(); + + ps0.onCompleted(); + ps1.onError(new TestException()); + ps2.onNext(4); + ps2.onCompleted(); + + assertFalse(ps0.hasObservers()); + assertFalse(ps1.hasObservers()); + assertFalse(ps2.hasObservers()); + + as.requestMore(1); + as.assertValues(4); + as.assertError(TestException.class); + as.assertNotCompleted(); + } + + @Test + public void justBackpressured() { + Observable.just(1) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }) + .test(1L) + .assertResult(1); + } + + @Test + public void justBackpressuredDelayError() { + Observable.just(1) + .flatMapSingle(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + }, true) + .test(1L) + .assertResult(1); + } + + @Test + public void singleMerge() { + Single.merge(Observable.range(1, 10).map(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + })) + .test() + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void singleMergeMaxConcurrent() { + AssertableSubscriber as = Single.merge(Observable.range(1, 10).map(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v).observeOn(Schedulers.computation()); + } + }), 2) + .test() + .awaitTerminalEvent(5, TimeUnit.SECONDS); + + Set set = new HashSet(as.getOnNextEvents()); + + assertEquals("" + set, 10, set.size()); + for (int j = 1; j < 11; j++) { + assertTrue("" + set, set.contains(j)); + } + } + + @Test + public void singleMergeDelayError() { + Single.mergeDelayError(Observable.range(1, 10).map(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + })) + .test() + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void singleMergeDelayErrorMaxConcurrent() { + AssertableSubscriber as = Single.mergeDelayError(Observable.range(1, 10).map(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v).observeOn(Schedulers.computation()); + } + }), 2) + .test() + .awaitTerminalEvent(5, TimeUnit.SECONDS); + + Set set = new HashSet(as.getOnNextEvents()); + + assertEquals("" + set, 10, set.size()); + for (int j = 1; j < 11; j++) { + assertTrue("" + set, set.contains(j)); + } + } + + @Test + public void singleMergeDelayErrorWithError() { + Single.mergeDelayError(Observable.range(1, 10) + .concatWith(Observable.error(new TestException())) + .map(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v); + } + })) + .test() + .assertFailure(TestException.class, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } + + @Test + public void singleMergeDelayMaxConcurrentErrorWithError() { + AssertableSubscriber as = Single.mergeDelayError(Observable.range(1, 10) + .concatWith(Observable.error(new TestException())) + .map(new Func1>() { + @Override + public Single call(Integer v) { + return Single.just(v).observeOn(Schedulers.computation()); + } + }), 2) + .test() + .awaitTerminalEvent(5, TimeUnit.SECONDS); + + Set set = new HashSet(as.getOnNextEvents()); + + assertEquals("" + set, 10, set.size()); + for (int j = 1; j < 11; j++) { + assertTrue("" + set, set.contains(j)); + } + } +} From bc061759f96a03b4810a641208684b40c47a1fca Mon Sep 17 00:00:00 2001 From: David Karnok Date: Tue, 21 Feb 2017 17:45:19 +0100 Subject: [PATCH 31/74] 1.x: reduce stack depth with switchIfEmpty (#5125) * 1.x: reduce stack depth with switchIfEmpty * Use source as the indication of first/second phase --- src/main/java/rx/Observable.java | 2 +- ...pty.java => OnSubscribeSwitchIfEmpty.java} | 51 +++++++++++++++---- .../operators/OperatorSwitchIfEmptyTest.java | 30 +++++++++-- 3 files changed, 69 insertions(+), 14 deletions(-) rename src/main/java/rx/internal/operators/{OperatorSwitchIfEmpty.java => OnSubscribeSwitchIfEmpty.java} (70%) diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 5978412fc7..6df23ff316 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -5481,7 +5481,7 @@ public final Observable switchIfEmpty(Observable alternate) { if (alternate == null) { throw new NullPointerException("alternate is null"); } - return lift(new OperatorSwitchIfEmpty(alternate)); + return unsafeCreate(new OnSubscribeSwitchIfEmpty(this, alternate)); } /** diff --git a/src/main/java/rx/internal/operators/OperatorSwitchIfEmpty.java b/src/main/java/rx/internal/operators/OnSubscribeSwitchIfEmpty.java similarity index 70% rename from src/main/java/rx/internal/operators/OperatorSwitchIfEmpty.java rename to src/main/java/rx/internal/operators/OnSubscribeSwitchIfEmpty.java index f3ead2c604..db02dfbff9 100644 --- a/src/main/java/rx/internal/operators/OperatorSwitchIfEmpty.java +++ b/src/main/java/rx/internal/operators/OnSubscribeSwitchIfEmpty.java @@ -16,6 +16,8 @@ package rx.internal.operators; +import java.util.concurrent.atomic.AtomicInteger; + import rx.*; import rx.internal.producers.ProducerArbiter; import rx.subscriptions.SerialSubscription; @@ -26,22 +28,28 @@ * empty, the results of the given Observable will be emitted. * @param the value type */ -public final class OperatorSwitchIfEmpty implements Observable.Operator { - private final Observable alternate; +public final class OnSubscribeSwitchIfEmpty implements Observable.OnSubscribe { + + final Observable source; - public OperatorSwitchIfEmpty(Observable alternate) { + final Observable alternate; + + public OnSubscribeSwitchIfEmpty(Observable source, Observable alternate) { + this.source = source; this.alternate = alternate; } @Override - public Subscriber call(Subscriber child) { + public void call(Subscriber child) { final SerialSubscription serial = new SerialSubscription(); ProducerArbiter arbiter = new ProducerArbiter(); final ParentSubscriber parent = new ParentSubscriber(child, serial, arbiter, alternate); + serial.set(parent); child.add(serial); child.setProducer(arbiter); - return parent; + + parent.subscribe(source); } static final class ParentSubscriber extends Subscriber { @@ -52,11 +60,15 @@ static final class ParentSubscriber extends Subscriber { private final ProducerArbiter arbiter; private final Observable alternate; + final AtomicInteger wip; + volatile boolean active; + ParentSubscriber(Subscriber child, final SerialSubscription serial, ProducerArbiter arbiter, Observable alternate) { this.child = child; this.serial = serial; this.arbiter = arbiter; this.alternate = alternate; + this.wip = new AtomicInteger(); } @Override @@ -69,14 +81,33 @@ public void onCompleted() { if (!empty) { child.onCompleted(); } else if (!child.isUnsubscribed()) { - subscribeToAlternate(); + active = false; + subscribe(null); } } - private void subscribeToAlternate() { - AlternateSubscriber as = new AlternateSubscriber(child, arbiter); - serial.set(as); - alternate.unsafeSubscribe(as); + void subscribe(Observable source) { + if (wip.getAndIncrement() == 0) { + do { + if (child.isUnsubscribed()) { + break; + } + + if (!active) { + if (source == null) { + AlternateSubscriber as = new AlternateSubscriber(child, arbiter); + serial.set(as); + active = true; + alternate.unsafeSubscribe(as); + } else { + active = true; + source.unsafeSubscribe(this); + source = null; + } + } + + } while (wip.decrementAndGet() != 0); + } } @Override diff --git a/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java b/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java index 5108f4001d..235cac495b 100644 --- a/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java +++ b/src/test/java/rx/internal/operators/OperatorSwitchIfEmptyTest.java @@ -17,16 +17,15 @@ import static org.junit.Assert.*; -import java.util.*; +import java.util.Arrays; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import rx.*; -import rx.Observable; import rx.Observable.OnSubscribe; -import rx.functions.Action0; +import rx.functions.*; import rx.observers.TestSubscriber; import rx.schedulers.Schedulers; import rx.subscriptions.Subscriptions; @@ -212,4 +211,29 @@ public void call() { public void testAlternateNull() { Observable.just(1).switchIfEmpty(null); } + + Observable recursiveSwitch(final int level) { + if (level == 100) { + return Observable.just(Thread.currentThread().getStackTrace()); + } + return Observable.empty().switchIfEmpty(Observable.defer(new Func0>() { + @Override + public Observable call() { + return recursiveSwitch(level + 1); + } + })); + } + + @Test + public void stackDepth() { + StackTraceElement[] trace = recursiveSwitch(0) + .toBlocking().last(); + + if (trace.length > 1000 || trace.length < 100) { + for (StackTraceElement ste : trace) { + System.out.println(ste); + } + fail("Stack too deep: " + trace.length); + } + } } \ No newline at end of file From e8b603535cd3f7a4bdbca6ba38d9d0c53c99e67a Mon Sep 17 00:00:00 2001 From: David Karnok Date: Wed, 22 Feb 2017 10:59:43 +0100 Subject: [PATCH 32/74] 1.x: throttleFirst detecting clock-drift backwards to open the gate (#5123) --- .../operators/OperatorThrottleFirst.java | 2 +- .../operators/OperatorThrottleFirstTest.java | 40 +++++++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/main/java/rx/internal/operators/OperatorThrottleFirst.java b/src/main/java/rx/internal/operators/OperatorThrottleFirst.java index fbd3c64d7d..f9093efa39 100644 --- a/src/main/java/rx/internal/operators/OperatorThrottleFirst.java +++ b/src/main/java/rx/internal/operators/OperatorThrottleFirst.java @@ -48,7 +48,7 @@ public void onStart() { @Override public void onNext(T v) { long now = scheduler.now(); - if (lastOnNext == -1 || now - lastOnNext >= timeInMilliseconds) { + if (lastOnNext == -1 || now < lastOnNext || now - lastOnNext >= timeInMilliseconds) { lastOnNext = now; subscriber.onNext(v); } diff --git a/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java b/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java index 4908efc534..f0fc6527a6 100644 --- a/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java +++ b/src/test/java/rx/internal/operators/OperatorThrottleFirstTest.java @@ -16,26 +16,18 @@ package rx.internal.operators; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.*; import java.util.concurrent.TimeUnit; -import org.junit.Before; -import org.junit.Test; +import org.junit.*; import org.mockito.InOrder; -import rx.Observable; +import rx.*; import rx.Observable.OnSubscribe; -import rx.Observer; -import rx.Scheduler; -import rx.Subscriber; import rx.exceptions.TestException; import rx.functions.Action0; -import rx.observers.TestSubscriber; +import rx.observers.*; import rx.schedulers.TestScheduler; import rx.subjects.PublishSubject; @@ -214,4 +206,28 @@ public void throttleWithTestSchedulerTimeOfZero() { verify(observer).onCompleted(); verifyNoMoreInteractions(observer); } + + @Test + public void nowDrift() { + TestScheduler s = new TestScheduler(); + s.advanceTimeBy(2, TimeUnit.SECONDS); + + PublishSubject o = PublishSubject.create(); + + AssertableSubscriber as = o.throttleFirst(500, TimeUnit.MILLISECONDS, s) + .test(); + + o.onNext(1); + s.advanceTimeBy(100, TimeUnit.MILLISECONDS); + o.onNext(2); + s.advanceTimeBy(100, TimeUnit.MILLISECONDS); + o.onNext(3); + s.advanceTimeBy(-1000, TimeUnit.MILLISECONDS); + o.onNext(4); + s.advanceTimeBy(100, TimeUnit.MILLISECONDS); + o.onNext(5); + o.onCompleted(); + + as.assertResult(1, 4); + } } From ccc2b2cdf4289238af2352d37339db52936e9841 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 24 Feb 2017 09:31:17 +0100 Subject: [PATCH 33/74] Release 1.2.7 --- CHANGES.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index c20f538c36..f47d459578 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,40 @@ # RxJava Releases # +### Version 1.2.7 - February 24, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.7%7C)) + +#### Deprecation of `create(OnSubscribe)` + +The method started out in RxJava 0.x as a simple and direct way for implementing custom operators because 0.x had a much simpler protocol requirements. Over the years, as the `Observable` protocol evolved and `create` became a powerful and complicated extension point of RxJava that required users to implement the `Observable` protocol, including cancellation and backpressure manually. + +Unfortunately, guides, blogs, StackOverflow answers and mere typical user behavior still leads to this `create` method and lots of confusion, unstoppable sequences and `MissingBackpressureException`. We tried remedying the situation by introducing `fromEmitter` with limited discoverability success. + +**Therefore, as of 1.2.7 the `create()` method is now deprecated** (but won't be removed due to binary compatibility requirements). In addition `fromEmitter` has been deprecate-renamed to `create(Action1, BackpressureMode)` and the experimental-marked `fromEmitter` itself will be removed in 1.3.0. + +Since the functionality of `create()` was useful for writing (custom) operators inside and outside of RxJava, the new `unsafeCreate(OnSubscribe)` method was introduced as the replacement. + +The new `create()` and `unsafeCreate()` methods will be fast-tracked to become standard in 1.3.0. + +#### API enhancements + +- [Pull 5086](https://github.com/ReactiveX/RxJava/pull/5086): Deprecate `create()`, add alternatives +- [Pull 5092](https://github.com/ReactiveX/RxJava/pull/5092): Add `Single.merge(Observable>)`, `Observable.flatMapSingle()` & `Observable.flatMapCompletable`. +- [Pull 5091](https://github.com/ReactiveX/RxJava/pull/5091): Add `subscribeOn(Scheduler, boolean)` avoid same-pool deadlock. + +#### API deprecations + +- [Pull 5086](https://github.com/ReactiveX/RxJava/pull/5086): + - Deprecate `Observable.create(OnSubscribe)`, + - Deprecate `fromEmitter` in favor of `Observable.create(Action1, BackpressureMode)`. + +#### Bugfixes + +- [Pull 5091](https://github.com/ReactiveX/RxJava/pull/5091): `create(Action1, BackpressureMode)`+`subscribeOn` avoid same-pool deadlock. +- [Pull 5123](https://github.com/ReactiveX/RxJava/pull/5123): `throttleFirst` detecting clock-drift backwards to open the gate + +#### Other + +- [Pull 5125](https://github.com/ReactiveX/RxJava/pull/5125): reduce stack depth with `switchIfEmpty` + ### Version 1.2.6 - February 3, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.6%7C)) #### Documentation From 2a0427b895f523b3ccdd7bc58eeef3a0b2e3c322 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Mon, 27 Feb 2017 19:25:53 +0100 Subject: [PATCH 34/74] 1.x: fix timed replay() not terminating when all items timeout (#5141) --- .../rx/internal/operators/OperatorReplay.java | 15 ++++++++++++--- .../internal/operators/OperatorReplayTest.java | 16 ++++++++++++++++ .../java/rx/subjects/ReplaySubjectTest.java | 18 ++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/main/java/rx/internal/operators/OperatorReplay.java b/src/main/java/rx/internal/operators/OperatorReplay.java index 045eae96af..a89ac32bd7 100644 --- a/src/main/java/rx/internal/operators/OperatorReplay.java +++ b/src/main/java/rx/internal/operators/OperatorReplay.java @@ -1239,9 +1239,18 @@ Node getInitialHead() { Node prev = get(); Node next = prev.get(); - while (next != null && ((Timestamped)next.value).getTimestampMillis() <= timeLimit) { - prev = next; - next = next.get(); + while (next != null) { + Object o = next.value; + Object v = leaveTransform(o); + if (NotificationLite.isCompleted(v) || NotificationLite.isError(v)) { + break; + } + if (((Timestamped)o).getTimestampMillis() <= timeLimit) { + prev = next; + next = next.get(); + } else { + break; + } } return prev; diff --git a/src/test/java/rx/internal/operators/OperatorReplayTest.java b/src/test/java/rx/internal/operators/OperatorReplayTest.java index e4734c30a6..999e343b8e 100644 --- a/src/test/java/rx/internal/operators/OperatorReplayTest.java +++ b/src/test/java/rx/internal/operators/OperatorReplayTest.java @@ -1577,4 +1577,20 @@ public ConnectableObservable call(Observable o) { }); } + @Test + public void noOldEntries() { + TestScheduler scheduler = new TestScheduler(); + + Observable source = Observable.just(1) + .replay(2, TimeUnit.SECONDS, scheduler) + .autoConnect(); + + source.test().assertResult(1); + + source.test().assertResult(1); + + scheduler.advanceTimeBy(3, TimeUnit.SECONDS); + + source.test().assertResult(); + } } \ No newline at end of file diff --git a/src/test/java/rx/subjects/ReplaySubjectTest.java b/src/test/java/rx/subjects/ReplaySubjectTest.java index 8464cf1b3f..dc624367f3 100644 --- a/src/test/java/rx/subjects/ReplaySubjectTest.java +++ b/src/test/java/rx/subjects/ReplaySubjectTest.java @@ -1175,4 +1175,22 @@ public Boolean call(Integer v) { ts2.assertValues(1, 2, 3, 6, 7); } + @Test + public void noOldEntries() { + TestScheduler scheduler = new TestScheduler(); + + ReplaySubject source = ReplaySubject.createWithTime(2, TimeUnit.SECONDS, scheduler); + + source.onNext(1); + source.onCompleted(); + + source.test().assertResult(1); + + source.test().assertResult(1); + + scheduler.advanceTimeBy(3, TimeUnit.SECONDS); + + source.test().assertResult(); + } + } From c8e22d87e0f1f68cc12af5def0f821e07c2d54c8 Mon Sep 17 00:00:00 2001 From: Yasuhiro Shimizu Date: Sun, 12 Mar 2017 20:53:46 +0900 Subject: [PATCH 35/74] add unsubscribeOn to Single type (#5138) (#5146) --- src/main/java/rx/Single.java | 44 +++++++++++++++++++++++ src/test/java/rx/SingleTest.java | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index a1614137f6..a92c2a9caa 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -2808,6 +2808,50 @@ public final Single delaySubscription(Observable other) { return create(new SingleOnSubscribeDelaySubscriptionOther(this, other)); } + /** + * Returns a Single which makes sure when a subscriber cancels the subscription, + * the dispose is called on the specified scheduler + * @param scheduler the target scheduler where to execute the cancellation + * @return the new Single instance + */ + public final Single unsubscribeOn(final Scheduler scheduler) { + return create(new OnSubscribe() { + @Override + public void call(final SingleSubscriber t) { + final SingleSubscriber single = new SingleSubscriber() { + @Override + public void onSuccess(T value) { + t.onSuccess(value); + } + + @Override + public void onError(Throwable error) { + t.onError(error); + } + }; + + t.add(Subscriptions.create(new Action0() { + @Override + public void call() { + final Scheduler.Worker w = scheduler.createWorker(); + w.schedule(new Action0() { + @Override + public void call() { + try { + single.unsubscribe(); + } finally { + w.unsubscribe(); + } + } + }); + } + })); + + Single.this.subscribe(single); + } + }); + } + // ------------------------------------------------------------------------- // Fluent test support, super handy and reduces test preparation boilerplate // ------------------------------------------------------------------------- diff --git a/src/test/java/rx/SingleTest.java b/src/test/java/rx/SingleTest.java index eefcde2699..f07e6d9216 100644 --- a/src/test/java/rx/SingleTest.java +++ b/src/test/java/rx/SingleTest.java @@ -28,6 +28,7 @@ import rx.Single.OnSubscribe; import rx.exceptions.*; import rx.functions.*; +import rx.internal.util.RxThreadFactory; import rx.observers.*; import rx.plugins.RxJavaHooks; import rx.schedulers.*; @@ -2230,4 +2231,65 @@ public void call(Throwable t) { assertEquals(1, calls[0]); } + + @Test + public void unsubscribeOnSuccess() throws InterruptedException { + final AtomicReference name = new AtomicReference(); + + final CountDownLatch cdl = new CountDownLatch(1); + + TestSubscriber ts = TestSubscriber.create(); + + Single.fromCallable(new Callable() { + @Override + public Integer call() throws Exception { + return 1; + } + }) + .doOnUnsubscribe(new Action0() { + @Override + public void call() { + name.set(Thread.currentThread().getName()); + cdl.countDown(); + } + }) + .subscribeOn(Schedulers.io()) + .unsubscribeOn(Schedulers.computation()) + .subscribe(ts); + + cdl.await(); + + ts.awaitTerminalEvent(); + ts.assertReceivedOnNext(Arrays.asList(1)); + + assertTrue(name.get().startsWith("RxComputation")); + } + + @Test + public void unsubscribeOnError() throws InterruptedException { + final AtomicReference name = new AtomicReference(); + + final CountDownLatch cdl = new CountDownLatch(1); + + TestSubscriber ts = TestSubscriber.create(); + + Single.error(new RuntimeException()) + .doOnUnsubscribe(new Action0() { + @Override + public void call() { + name.set(Thread.currentThread().getName()); + cdl.countDown(); + } + }) + .subscribeOn(Schedulers.io()) + .unsubscribeOn(Schedulers.computation()) + .subscribe(ts); + + cdl.await(); + + ts.awaitTerminalEvent(); + ts.assertError(RuntimeException.class); + + assertTrue(name.get().startsWith("RxComputation")); + } } From 881183178e5f0d163052a4dd86569fbac1fb8bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Karnok?= Date: Sun, 12 Mar 2017 12:56:22 +0100 Subject: [PATCH 36/74] 1.x add missing @Experimental tag to unsubscribeOn --- src/main/java/rx/Single.java | 2 ++ src/test/java/rx/SingleTest.java | 1 - src/test/java/rx/internal/operators/OperatorReplayTest.java | 2 +- src/test/java/rx/subjects/ReplaySubjectTest.java | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index a92c2a9caa..6edb80ab15 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -2813,7 +2813,9 @@ public final Single delaySubscription(Observable other) { * the dispose is called on the specified scheduler * @param scheduler the target scheduler where to execute the cancellation * @return the new Single instance + * @since 1.2.8 - experimental */ + @Experimental public final Single unsubscribeOn(final Scheduler scheduler) { return create(new OnSubscribe() { @Override diff --git a/src/test/java/rx/SingleTest.java b/src/test/java/rx/SingleTest.java index f07e6d9216..9ae7fa0f90 100644 --- a/src/test/java/rx/SingleTest.java +++ b/src/test/java/rx/SingleTest.java @@ -28,7 +28,6 @@ import rx.Single.OnSubscribe; import rx.exceptions.*; import rx.functions.*; -import rx.internal.util.RxThreadFactory; import rx.observers.*; import rx.plugins.RxJavaHooks; import rx.schedulers.*; diff --git a/src/test/java/rx/internal/operators/OperatorReplayTest.java b/src/test/java/rx/internal/operators/OperatorReplayTest.java index 999e343b8e..fbe256ef01 100644 --- a/src/test/java/rx/internal/operators/OperatorReplayTest.java +++ b/src/test/java/rx/internal/operators/OperatorReplayTest.java @@ -1584,7 +1584,7 @@ public void noOldEntries() { Observable source = Observable.just(1) .replay(2, TimeUnit.SECONDS, scheduler) .autoConnect(); - + source.test().assertResult(1); source.test().assertResult(1); diff --git a/src/test/java/rx/subjects/ReplaySubjectTest.java b/src/test/java/rx/subjects/ReplaySubjectTest.java index dc624367f3..63b63ea16c 100644 --- a/src/test/java/rx/subjects/ReplaySubjectTest.java +++ b/src/test/java/rx/subjects/ReplaySubjectTest.java @@ -1183,7 +1183,7 @@ public void noOldEntries() { source.onNext(1); source.onCompleted(); - + source.test().assertResult(1); source.test().assertResult(1); From 0f1542d7d5d2ce2e89118a5701a6d6fd7d5684b0 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Wed, 15 Mar 2017 17:31:08 +0100 Subject: [PATCH 37/74] 1.x: replay().refCount() avoid leaking items between connections (#5181) * 1.x: replay().refCount() avoid leaking items between connections * Improve coverage of changes. --- .../operators/OnSubscribeRefCount.java | 12 ++ .../rx/internal/operators/OperatorReplay.java | 13 +- .../operators/OnSubscribeRefCountTest.java | 153 ++++++++++++++++++ 3 files changed, 177 insertions(+), 1 deletion(-) diff --git a/src/main/java/rx/internal/operators/OnSubscribeRefCount.java b/src/main/java/rx/internal/operators/OnSubscribeRefCount.java index c5898ac1b6..4a34663fbb 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeRefCount.java +++ b/src/main/java/rx/internal/operators/OnSubscribeRefCount.java @@ -129,7 +129,13 @@ void cleanup() { // and set the subscriptionCount to 0 lock.lock(); try { + if (baseSubscription == currentBase) { + // backdoor into the ConnectableObservable to cleanup and reset its state + if (source instanceof Subscription) { + ((Subscription)source).unsubscribe(); + } + baseSubscription.unsubscribe(); baseSubscription = new CompositeSubscription(); subscriptionCount.set(0); @@ -148,7 +154,13 @@ public void call() { lock.lock(); try { if (baseSubscription == current) { + if (subscriptionCount.decrementAndGet() == 0) { + // backdoor into the ConnectableObservable to cleanup and reset its state + if (source instanceof Subscription) { + ((Subscription)source).unsubscribe(); + } + baseSubscription.unsubscribe(); // need a new baseSubscription because once // unsubscribed stays that way diff --git a/src/main/java/rx/internal/operators/OperatorReplay.java b/src/main/java/rx/internal/operators/OperatorReplay.java index a89ac32bd7..6447b2c737 100644 --- a/src/main/java/rx/internal/operators/OperatorReplay.java +++ b/src/main/java/rx/internal/operators/OperatorReplay.java @@ -28,7 +28,7 @@ import rx.schedulers.Timestamped; import rx.subscriptions.Subscriptions; -public final class OperatorReplay extends ConnectableObservable { +public final class OperatorReplay extends ConnectableObservable implements Subscription { /** The source observable. */ final Observable source; /** Holds the current subscriber that is, will be or just was subscribed to the source observable. */ @@ -254,6 +254,17 @@ private OperatorReplay(OnSubscribe onSubscribe, Observable sourc this.bufferFactory = bufferFactory; } + @Override + public void unsubscribe() { + current.lazySet(null); + } + + @Override + public boolean isUnsubscribed() { + ReplaySubscriber ps = current.get(); + return ps == null || ps.isUnsubscribed(); + } + @Override public void connect(Action1 connection) { boolean doConnect; diff --git a/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java b/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java index a64f808e78..a824f3191b 100644 --- a/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java +++ b/src/test/java/rx/internal/operators/OnSubscribeRefCountTest.java @@ -19,6 +19,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; +import java.lang.management.ManagementFactory; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -31,6 +32,7 @@ import rx.Observable.OnSubscribe; import rx.Observer; import rx.functions.*; +import rx.observables.ConnectableObservable; import rx.observers.*; import rx.schedulers.*; import rx.subjects.ReplaySubject; @@ -611,4 +613,155 @@ public void call(Throwable t) { assertNotNull("First subscriber didn't get the error", err1); assertNotNull("Second subscriber didn't get the error", err2); } + + Observable source; + + @Test + public void replayNoLeak() throws Exception { + System.gc(); + Thread.sleep(100); + + long start = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = Observable.fromCallable(new Callable() { + @Override + public Object call() throws Exception { + return new byte[100 * 1000 * 1000]; + } + }) + .replay(1) + .refCount(); + + source.subscribe(); + + System.gc(); + Thread.sleep(100); + + long after = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = null; + assertTrue(String.format("%,3d -> %,3d%n", start, after), start + 20 * 1000 * 1000 > after); + } + + @Test + public void replayNoLeak2() throws Exception { + System.gc(); + Thread.sleep(100); + + long start = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = Observable.fromCallable(new Callable() { + @Override + public Object call() throws Exception { + return new byte[100 * 1000 * 1000]; + } + }).concatWith(Observable.never()) + .replay(1) + .refCount(); + + Subscription s1 = source.subscribe(); + Subscription s2 = source.subscribe(); + + s1.unsubscribe(); + s2.unsubscribe(); + + s1 = null; + s2 = null; + + System.gc(); + Thread.sleep(100); + + long after = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = null; + assertTrue(String.format("%,3d -> %,3d%n", start, after), start + 20 * 1000 * 1000 > after); + } + + static final class ExceptionData extends Exception { + private static final long serialVersionUID = -6763898015338136119L; + + public final Object data; + + public ExceptionData(Object data) { + this.data = data; + } + } + + @Test + public void publishNoLeak() throws Exception { + System.gc(); + Thread.sleep(100); + + long start = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = Observable.fromCallable(new Callable() { + @Override + public Object call() throws Exception { + throw new ExceptionData(new byte[100 * 1000 * 1000]); + } + }) + .publish() + .refCount(); + + Action1 err = Actions.empty(); + source.subscribe(Actions.empty(), err); + + System.gc(); + Thread.sleep(100); + + long after = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = null; + assertTrue(String.format("%,3d -> %,3d%n", start, after), start + 20 * 1000 * 1000 > after); + } + + @Test + public void publishNoLeak2() throws Exception { + System.gc(); + Thread.sleep(100); + + long start = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = Observable.fromCallable(new Callable() { + @Override + public Object call() throws Exception { + return new byte[100 * 1000 * 1000]; + } + }).concatWith(Observable.never()) + .publish() + .refCount(); + + Subscription s1 = source.test(0); + Subscription s2 = source.test(0); + + s1.unsubscribe(); + s2.unsubscribe(); + + s1 = null; + s2 = null; + + System.gc(); + Thread.sleep(100); + + long after = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed(); + + source = null; + assertTrue(String.format("%,3d -> %,3d%n", start, after), start + 20 * 1000 * 1000 > after); + } + + @Test + public void replayIsUnsubscribed() { + ConnectableObservable co = Observable.just(1) + .replay(); + + assertTrue(((Subscription)co).isUnsubscribed()); + + Subscription s = co.connect(); + + assertFalse(((Subscription)co).isUnsubscribed()); + + s.unsubscribe(); + + assertTrue(((Subscription)co).isUnsubscribed()); + } } From e6824c1ab2b649654bebabc3cedb5a15f7605141 Mon Sep 17 00:00:00 2001 From: Maksym Ostroverkhov Date: Sat, 18 Mar 2017 18:47:14 +0200 Subject: [PATCH 38/74] 1.X: UnicastSubject fail-fast and delay-error behavior (#5195) * 1.X: unicastSubject does not replay onNext calls made prior to subscription if onError is also called prior to subscription. * cache delayError field in local variable --- src/main/java/rx/subjects/UnicastSubject.java | 62 +++++++++-- .../java/rx/subjects/UnicastSubjectTest.java | 101 ++++++++++++++++++ 2 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 src/test/java/rx/subjects/UnicastSubjectTest.java diff --git a/src/main/java/rx/subjects/UnicastSubject.java b/src/main/java/rx/subjects/UnicastSubject.java index c1c69f9e36..74bdf3d539 100644 --- a/src/main/java/rx/subjects/UnicastSubject.java +++ b/src/main/java/rx/subjects/UnicastSubject.java @@ -49,6 +49,7 @@ public final class UnicastSubject extends Subject { public static UnicastSubject create() { return create(16); } + /** * Constructs an empty UnicastSubject instance with a capacity hint. *

The capacity hint determines the internal queue's island size: the larger @@ -59,7 +60,18 @@ public static UnicastSubject create() { * @return the created BufferUntilSubscriber instance */ public static UnicastSubject create(int capacityHint) { - State state = new State(capacityHint, null); + State state = new State(capacityHint, false, null); + return new UnicastSubject(state); + } + + /** + * Constructs an empty UnicastSubject instance with the default capacity hint of 16 elements. + * + * @param delayError deliver pending next events before error. + * @return the created UnicastSubject instance + */ + public static UnicastSubject create(boolean delayError) { + State state = new State(16, delayError, null); return new UnicastSubject(state); } @@ -78,7 +90,28 @@ public static UnicastSubject create(int capacityHint) { * @return the created BufferUntilSubscriber instance */ public static UnicastSubject create(int capacityHint, Action0 onTerminated) { - State state = new State(capacityHint, onTerminated); + State state = new State(capacityHint, false, onTerminated); + return new UnicastSubject(state); + } + + /** + * Constructs an empty UnicastSubject instance with a capacity hint, delay error + * flag and Action0 instance to call if the subject reaches its terminal state + * or the single Subscriber unsubscribes mid-sequence. + *

The capacity hint determines the internal queue's island size: the larger + * it is the less frequent allocation will happen if there is no subscriber + * or the subscriber hasn't caught up. + * @param the input and output value type + * @param capacityHint the capacity hint for the internal queue + * @param onTerminated the optional callback to call when subject reaches its terminal state + * or the single Subscriber unsubscribes mid-sequence. It will be called + * at most once. + * @param delayError flag indicating whether to deliver pending next events before error. + * @return the created BufferUntilSubscriber instance + */ + public static UnicastSubject create(int capacityHint, + Action0 onTerminated, boolean delayError) { + State state = new State(capacityHint, delayError, onTerminated); return new UnicastSubject(state); } @@ -119,6 +152,8 @@ static final class State extends AtomicLong implements Producer, Observer, final AtomicReference> subscriber; /** The queue holding values until the subscriber arrives and catches up. */ final Queue queue; + /** Deliver pending next events before error. */ + final boolean delayError; /** Atomically set to true on terminal condition. */ final AtomicReference terminateOnce; /** In case the source emitted an error. */ @@ -137,10 +172,12 @@ static final class State extends AtomicLong implements Producer, Observer, * reduce allocation frequency * @param onTerminated the action to call when the subject reaches its terminal state or * the single subscriber unsubscribes. + * @param delayError deliver pending next events before error. */ - public State(int capacityHint, Action0 onTerminated) { + public State(int capacityHint, boolean delayError, Action0 onTerminated) { this.subscriber = new AtomicReference>(); this.terminateOnce = onTerminated != null ? new AtomicReference(onTerminated) : null; + this.delayError = delayError; Queue q; if (capacityHint > 1) { @@ -266,14 +303,14 @@ void replay() { emitting = true; } Queue q = queue; + boolean delayError = this.delayError; for (;;) { Subscriber s = subscriber.get(); boolean unlimited = false; if (s != null) { boolean d = done; boolean empty = q.isEmpty(); - - if (checkTerminated(d, empty, s)) { + if (checkTerminated(d, empty, delayError, s)) { return; } long r = get(); @@ -284,7 +321,7 @@ void replay() { d = done; Object v = q.poll(); empty = v == null; - if (checkTerminated(d, empty, s)) { + if (checkTerminated(d, empty, delayError, s)) { return; } if (empty) { @@ -348,23 +385,28 @@ public boolean isUnsubscribed() { * an error happened or the source terminated and the queue is empty * @param done indicates the source has called onCompleted * @param empty indicates if there are no more source values in the queue + * @param delayError indicates whether to deliver pending next events before error * @param s the target Subscriber to emit events to * @return true if this Subject reached a terminal state and the drain loop should quit */ - boolean checkTerminated(boolean done, boolean empty, Subscriber s) { + boolean checkTerminated(boolean done, boolean empty, boolean delayError, Subscriber s) { if (s.isUnsubscribed()) { queue.clear(); return true; } if (done) { Throwable e = error; - if (e != null) { + if (e != null && !delayError) { queue.clear(); s.onError(e); return true; - } else + } if (empty) { - s.onCompleted(); + if (e != null) { + s.onError(e); + } else { + s.onCompleted(); + } return true; } } diff --git a/src/test/java/rx/subjects/UnicastSubjectTest.java b/src/test/java/rx/subjects/UnicastSubjectTest.java new file mode 100644 index 0000000000..af9ef33468 --- /dev/null +++ b/src/test/java/rx/subjects/UnicastSubjectTest.java @@ -0,0 +1,101 @@ +package rx.subjects; + +import org.junit.Test; +import rx.functions.Action0; +import rx.observers.TestSubscriber; + +public class UnicastSubjectTest { + + @Test + public void testOneArgFactoryDelayError() throws Exception { + TestSubscriber subscriber = TestSubscriber.create(); + UnicastSubject s = UnicastSubject.create(true); + s.onNext(1L); + s.onNext(2L); + s.onError(new RuntimeException()); + s.subscribe(subscriber); + subscriber.assertValueCount(2); + subscriber.assertError(RuntimeException.class); + } + + @Test + public void testOneArgFactoryNoDelayError() throws Exception { + TestSubscriber subscriber = TestSubscriber.create(); + UnicastSubject s = UnicastSubject.create(false); + s.onNext(1L); + s.onNext(2L); + s.onError(new RuntimeException()); + s.subscribe(subscriber); + subscriber.assertValueCount(0); + subscriber.assertError(RuntimeException.class); + } + + @Test + public void testThreeArgsFactoryDelayError() throws Exception { + TestSubscriber subscriber = TestSubscriber.create(); + UnicastSubject s = UnicastSubject.create(16, new NoopAction0(), true); + s.onNext(1L); + s.onNext(2L); + s.onError(new RuntimeException()); + s.subscribe(subscriber); + subscriber.assertValueCount(2); + subscriber.assertError(RuntimeException.class); + } + + @Test + public void testThreeArgsFactoryNoDelayError() throws Exception { + TestSubscriber subscriber = TestSubscriber.create(); + UnicastSubject s = UnicastSubject.create(16, new NoopAction0(), false); + s.onNext(1L); + s.onNext(2L); + s.onError(new RuntimeException()); + s.subscribe(subscriber); + subscriber.assertValueCount(0); + subscriber.assertError(RuntimeException.class); + } + + @Test + public void testZeroArgsFactory() throws Exception { + TestSubscriber subscriber = TestSubscriber.create(); + UnicastSubject s = UnicastSubject.create(); + s.onNext(1L); + s.onNext(2L); + s.onError(new RuntimeException()); + s.subscribe(subscriber); + subscriber.assertValueCount(0); + subscriber.assertError(RuntimeException.class); + } + + @Test + public void testOneArgFactory() throws Exception { + TestSubscriber subscriber = TestSubscriber.create(); + UnicastSubject s = UnicastSubject.create(16); + s.onNext(1L); + s.onNext(2L); + s.onError(new RuntimeException()); + s.subscribe(subscriber); + subscriber.assertValueCount(0); + subscriber.assertError(RuntimeException.class); + } + + @Test + public void testTwoArgsFactory() throws Exception { + TestSubscriber subscriber = TestSubscriber.create(); + UnicastSubject s = UnicastSubject.create(16, new NoopAction0()); + s.onNext(1L); + s.onNext(2L); + s.onError(new RuntimeException()); + s.subscribe(subscriber); + subscriber.assertValueCount(0); + subscriber.assertError(RuntimeException.class); + } + + + + private static final class NoopAction0 implements Action0 { + + @Override + public void call() { + } + } +} From d1f20a16c50600097130a60ee7e710a7e7453607 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Tue, 21 Mar 2017 23:14:01 +0100 Subject: [PATCH 39/74] 1.x: add marble diagram to UnicastSubject, fix javadoc (#5209) --- src/main/java/rx/subjects/UnicastSubject.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/rx/subjects/UnicastSubject.java b/src/main/java/rx/subjects/UnicastSubject.java index 74bdf3d539..1c51fe48bb 100644 --- a/src/main/java/rx/subjects/UnicastSubject.java +++ b/src/main/java/rx/subjects/UnicastSubject.java @@ -32,7 +32,8 @@ * amount. In this case, the buffered values are no longer retained. If the Subscriber * requests a limited amount, queueing is involved and only those values are retained which * weren't requested by the Subscriber at that time. - * + *

+ * * @param the input and output value type */ @Experimental @@ -68,6 +69,7 @@ public static UnicastSubject create(int capacityHint) { * Constructs an empty UnicastSubject instance with the default capacity hint of 16 elements. * * @param delayError deliver pending next events before error. + * @param the input and output value type * @return the created UnicastSubject instance */ public static UnicastSubject create(boolean delayError) { From 72a6dee2d2b15b05d8448f83dfab98ab3d6c900f Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 24 Mar 2017 09:31:33 +0100 Subject: [PATCH 40/74] Release 1.2.8 --- CHANGES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f47d459578..9bb7651edb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,16 @@ # RxJava Releases # +### Version 1.2.8 - March 24, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.8%7C)) + +#### API enhancements +- [Pull 5146](https://github.com/ReactiveX/RxJava/pull/5146): Add `Single.unsubscribeOn`. +- [Pull 5195](https://github.com/ReactiveX/RxJava/pull/5195): Enhance `UnicastSubject` with optional delay error behavior. + +#### Bugfixes + +- [Pull 5141](https://github.com/ReactiveX/RxJava/pull/5141): Fix timed `replay()` not terminating when all items timeout. +- [Pull 5181](https://github.com/ReactiveX/RxJava/pull/5181): `replay().refCount()` avoid leaking items between connections. + ### Version 1.2.7 - February 24, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.7%7C)) #### Deprecation of `create(OnSubscribe)` From 1d7edee0a60cbf185157555483db430e1afd6702 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 24 Mar 2017 10:48:10 +0100 Subject: [PATCH 41/74] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9bb7651edb..c0380e97dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ # RxJava Releases # -### Version 1.2.8 - March 24, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.8%7C)) +### Version 1.2.9 - March 24, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.9%7C)) #### API enhancements - [Pull 5146](https://github.com/ReactiveX/RxJava/pull/5146): Add `Single.unsubscribeOn`. From e37d1a75771f5abf8ffe1b1c330df34ed3bbac82 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 24 Mar 2017 20:39:31 +0100 Subject: [PATCH 42/74] 1.x: fix Completable.onErrorResumeNext unsubscribe not propagated (#5225) --- src/main/java/rx/Completable.java | 1 + .../operators/CompletableOnErrorXTest.java | 63 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/test/java/rx/internal/operators/CompletableOnErrorXTest.java diff --git a/src/main/java/rx/Completable.java b/src/main/java/rx/Completable.java index 536509b39a..1fb6ad1f49 100644 --- a/src/main/java/rx/Completable.java +++ b/src/main/java/rx/Completable.java @@ -1729,6 +1729,7 @@ public final Completable onErrorResumeNext(final Func1 ps = PublishSubject.create(); + + AssertableSubscriber as = ps.toCompletable() + .onErrorResumeNext(new Func1() { + @Override + public Completable call(Throwable e) { + return Completable.complete(); + } + }) + .test(); + + assertTrue(ps.hasObservers()); + + as.unsubscribe(); + + assertFalse("Still subscribed!", ps.hasObservers()); + } + + @Test + public void completeUnsubscribe() { + PublishSubject ps = PublishSubject.create(); + + AssertableSubscriber as = ps.toCompletable() + .onErrorComplete() + .test(); + + assertTrue(ps.hasObservers()); + + as.unsubscribe(); + + assertFalse("Still subscribed!", ps.hasObservers()); + } +} From bc40a84ffd66852ffcc320f2a2430ef52c903f61 Mon Sep 17 00:00:00 2001 From: Dan Hendry Date: Sun, 2 Apr 2017 04:48:06 -0400 Subject: [PATCH 43/74] Defer creation of the TimeoutException when using the Single.timeout() operator (#5250) * Defer creation of the TimeoutException when using the Single.timeout() operator * Fix formatting --- src/main/java/rx/Single.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index 6edb80ab15..0b39b6f24f 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -2254,7 +2254,15 @@ public final Single timeout(long timeout, TimeUnit timeUnit, Single timeout(long timeout, TimeUnit timeUnit, Single other, Scheduler scheduler) { if (other == null) { - other = Single. error(new TimeoutException()); + // Use a defer instead of simply other = Single.error(new TimeoutException()) + // since instantiating an exception will cause the current stack trace to be inspected + // and we only want to incur that overhead when a timeout actually happens. + other = Single.defer(new Func0>() { + @Override + public Single call() { + return Single.error(new TimeoutException()); + } + }); } return create(new SingleTimeout(onSubscribe, timeout, timeUnit, scheduler, other.onSubscribe)); } From 2162d6d35a8e162f408e1bfd4083924c0987751b Mon Sep 17 00:00:00 2001 From: Marko Tiidla Date: Sun, 2 Apr 2017 12:42:10 +0200 Subject: [PATCH 44/74] 1.x Use IntelliJ IDE friendly assertion failure message (#5258) * Test Intellij formatting fix * Fix test subscriber test case --- src/main/java/rx/observers/TestSubscriber.java | 4 ++-- src/test/java/rx/observers/TestSubscriberTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/rx/observers/TestSubscriber.java b/src/main/java/rx/observers/TestSubscriber.java index cfa1f74ef9..bb76878ba6 100644 --- a/src/main/java/rx/observers/TestSubscriber.java +++ b/src/main/java/rx/observers/TestSubscriber.java @@ -337,11 +337,11 @@ private void assertItem(T expected, int i) { if (expected == null) { // check for null equality if (actual != null) { - assertionError("Value at index: " + i + " expected to be [null] but was: [" + actual + "]\n"); + assertionError("Value at index: " + i + " expected: [null] but was: [" + actual + "]\n"); } } else if (!expected.equals(actual)) { assertionError("Value at index: " + i - + " expected to be [" + expected + "] (" + expected.getClass().getSimpleName() + + " expected: [" + expected + "] (" + expected.getClass().getSimpleName() + ") but was: [" + actual + "] (" + (actual != null ? actual.getClass().getSimpleName() : "null") + ")\n"); } diff --git a/src/test/java/rx/observers/TestSubscriberTest.java b/src/test/java/rx/observers/TestSubscriberTest.java index ee94f12297..5e2c8edc07 100644 --- a/src/test/java/rx/observers/TestSubscriberTest.java +++ b/src/test/java/rx/observers/TestSubscriberTest.java @@ -72,7 +72,7 @@ public void testAssertNotMatchValue() { oi.subscribe(o); thrown.expect(AssertionError.class); - thrown.expectMessage("Value at index: 1 expected to be [3] (Integer) but was: [2] (Integer)"); + thrown.expectMessage("Value at index: 1 expected: [3] (Integer) but was: [2] (Integer)"); o.assertReceivedOnNext(Arrays.asList(1, 3)); From 95afbd0f1cc194a6273515f9b81f2a78b885ba32 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Wed, 26 Apr 2017 09:36:45 +0200 Subject: [PATCH 45/74] Release 1.2.10 --- CHANGES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index c0380e97dd..b02e08b281 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,16 @@ # RxJava Releases # +### Version 1.2.10 - April 26, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.10%7C)) + +#### Bugfixes + +- [Pull 5225](https://github.com/ReactiveX/RxJava/pull/5225): Fix `Completable.onErrorResumeNext` unsubscribe not propagated. + +#### Other + +- [Pull 5250](https://github.com/ReactiveX/RxJava/pull/5250): Defer creation of the `TimeoutException` when using the `Single.timeout()` operator. +- [Pull 5258](https://github.com/ReactiveX/RxJava/pull/5258): Use IntelliJ IDE friendly assertion failure message. + ### Version 1.2.9 - March 24, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.9%7C)) #### API enhancements From 8119e786f2f61b1a762588e2edfb0d161a63ad40 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 27 Apr 2017 17:57:51 +0200 Subject: [PATCH 46/74] 1.x: apply API promotions for 1.3 (#5318) * 1.x: apply API promotions for 1.3 * Fix typos --- src/main/java/rx/BackpressureOverflow.java | 4 +- src/main/java/rx/Completable.java | 13 +- src/main/java/rx/CompletableEmitter.java | 4 +- src/main/java/rx/CompletableSubscriber.java | 4 +- src/main/java/rx/Emitter.java | 4 +- src/main/java/rx/Observable.java | 269 +++++------------- src/main/java/rx/Scheduler.java | 3 +- src/main/java/rx/Single.java | 83 +++--- src/main/java/rx/SingleEmitter.java | 6 +- .../AssemblyStackTraceException.java | 3 +- .../rx/exceptions/CompositeException.java | 4 +- src/main/java/rx/exceptions/Exceptions.java | 13 +- src/main/java/rx/functions/Cancellable.java | 4 +- .../AssertableSubscriberObservable.java | 3 +- .../OnSubscribeFlatMapCompletable.java | 3 +- .../operators/OnSubscribeFlatMapSingle.java | 3 +- .../rx/internal/schedulers/SchedulerWhen.java | 3 +- .../util/BackpressureDrainManager.java | 6 +- .../java/rx/internal/util/BlockingUtils.java | 4 +- .../java/rx/observables/AsyncOnSubscribe.java | 11 +- .../rx/observables/BlockingObservable.java | 19 +- .../java/rx/observables/SyncOnSubscribe.java | 13 +- .../rx/observers/AssertableSubscriber.java | 5 +- .../observers/AsyncCompletableSubscriber.java | 4 +- .../observers/SafeCompletableSubscriber.java | 4 +- .../java/rx/observers/TestSubscriber.java | 10 +- .../RxJavaCompletableExecutionHook.java | 4 +- .../java/rx/plugins/RxJavaErrorHandler.java | 9 +- src/main/java/rx/plugins/RxJavaHooks.java | 3 +- src/main/java/rx/plugins/RxJavaPlugins.java | 11 +- .../java/rx/plugins/RxJavaSchedulersHook.java | 13 +- src/main/java/rx/schedulers/Schedulers.java | 3 +- src/main/java/rx/singles/BlockingSingle.java | 4 +- src/main/java/rx/subjects/UnicastSubject.java | 3 +- 34 files changed, 176 insertions(+), 376 deletions(-) diff --git a/src/main/java/rx/BackpressureOverflow.java b/src/main/java/rx/BackpressureOverflow.java index 39948d8804..6603a6d220 100644 --- a/src/main/java/rx/BackpressureOverflow.java +++ b/src/main/java/rx/BackpressureOverflow.java @@ -15,15 +15,13 @@ */ package rx; -import rx.annotations.Beta; import rx.exceptions.MissingBackpressureException; /** * Generic strategy and default implementations to deal with backpressure buffer overflows. * - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ -@Beta public final class BackpressureOverflow { private BackpressureOverflow() { diff --git a/src/main/java/rx/Completable.java b/src/main/java/rx/Completable.java index 1fb6ad1f49..1ecc1e1993 100644 --- a/src/main/java/rx/Completable.java +++ b/src/main/java/rx/Completable.java @@ -20,7 +20,6 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; -import rx.annotations.*; import rx.exceptions.*; import rx.functions.*; import rx.internal.observers.AssertableSubscriberObservable; @@ -35,10 +34,9 @@ * Represents a deferred computation without any value but only indication for completion or exception. * * The class follows a similar event pattern as Reactive-Streams: onSubscribe (onError|onComplete)? - * - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * + * @since 1.3 */ -@Beta public class Completable { /** The actual subscription action. */ private final OnSubscribe onSubscribe; @@ -539,9 +537,8 @@ public void call(rx.CompletableSubscriber s) { * Completable's protocol are held. * @param producer the callback invoked for each incoming CompletableSubscriber * @return the new Completable instance - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public static Completable fromEmitter(Action1 producer) { return create(new CompletableFromEmitter(producer)); } @@ -2385,10 +2382,10 @@ public void call() { *

Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.3 - experimental * @return the new AssertableSubscriber instance - * @since 1.2.3 + * @since 1.3 */ - @Experimental public final AssertableSubscriber test() { AssertableSubscriberObservable ts = AssertableSubscriberObservable.create(Long.MAX_VALUE); subscribe(ts); diff --git a/src/main/java/rx/CompletableEmitter.java b/src/main/java/rx/CompletableEmitter.java index 09f51e0262..dc5f83efaa 100644 --- a/src/main/java/rx/CompletableEmitter.java +++ b/src/main/java/rx/CompletableEmitter.java @@ -15,7 +15,6 @@ */ package rx; -import rx.annotations.Experimental; import rx.functions.Cancellable; /** @@ -24,9 +23,8 @@ *

* All methods are thread-safe; calling onCompleted or onError twice or one after the other has * no effect. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ -@Experimental public interface CompletableEmitter { /** diff --git a/src/main/java/rx/CompletableSubscriber.java b/src/main/java/rx/CompletableSubscriber.java index 2aef783769..054a97474e 100644 --- a/src/main/java/rx/CompletableSubscriber.java +++ b/src/main/java/rx/CompletableSubscriber.java @@ -15,12 +15,10 @@ */ package rx; -import rx.annotations.Experimental; - /** * Represents the subscription API callbacks when subscribing to a Completable instance. + * @since 1.3 */ -@Experimental public interface CompletableSubscriber { /** * Called once the deferred computation completes normally. diff --git a/src/main/java/rx/Emitter.java b/src/main/java/rx/Emitter.java index 5ed8697b71..3a81d7f01e 100644 --- a/src/main/java/rx/Emitter.java +++ b/src/main/java/rx/Emitter.java @@ -16,7 +16,6 @@ package rx; -import rx.annotations.Experimental; import rx.functions.Cancellable; /** @@ -29,9 +28,8 @@ * other methods are thread-safe. * * @param the value type to emit - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ -@Experimental public interface Emitter extends Observer { /** diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 6df23ff316..6c4b599bb6 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -110,7 +110,7 @@ public static Observable create(OnSubscribe f) { *

* You should call the Emitter's onNext, onError and onCompleted methods in a serialized fashion. The * rest of its methods are thread-safe. - * + *

History: 1.2.7 - experimental * @param the element type * @param emitter the emitter that is called when a Subscriber subscribes to the returned {@code Observable} * @param backpressure the backpressure mode to apply if the downstream Subscriber doesn't request (fast) enough @@ -118,9 +118,8 @@ public static Observable create(OnSubscribe f) { * @see Emitter * @see Emitter.BackpressureMode * @see rx.functions.Cancellable - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public static Observable create(Action1> emitter, Emitter.BackpressureMode backpressure) { return unsafeCreate(new OnSubscribeCreate(emitter, backpressure)); } @@ -148,7 +147,7 @@ public static Observable create(Action1> emitter, Emitter.Back *

Scheduler:
*
{@code unsafeCreate} does not operate by default on a particular {@link Scheduler}.
* - * + *

History: 1.2.7 - experimental * @param * the type of the items that this Observable emits * @param f @@ -157,9 +156,8 @@ public static Observable create(Action1> emitter, Emitter.Back * @return an Observable that, when a {@link Subscriber} subscribes to it, will execute the specified * function * @see ReactiveX operators documentation: Create - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public static Observable unsafeCreate(OnSubscribe f) { return new Observable(RxJavaHooks.onCreate(f)); } @@ -243,9 +241,9 @@ public static Observable create(SyncOnSubscribe syncOnSubscribe) * @see AsyncOnSubscribe#createStateless(Action2) * @see AsyncOnSubscribe#createStateless(Action2, Action0) * @see ReactiveX operators documentation: Create - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 - beta */ - @Experimental + @Beta public static Observable create(AsyncOnSubscribe asyncOnSubscribe) { return unsafeCreate(asyncOnSubscribe); } @@ -350,8 +348,8 @@ public interface Transformer extends Func1, Observable> { * @param the resulting object type * @param converter the function that receives the current Observable instance and returns a value * @return the value returned by the function + * @since 1.3 */ - @Experimental public final R to(Func1, R> converter) { return converter.call(this); } @@ -402,10 +400,8 @@ public Single toSingle() { * calls onCompleted * @see ReactiveX documentation: * Completable - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical - * with the release number) + * @since 1.3 */ - @Beta public Completable toCompletable() { return Completable.fromObservable(this); } @@ -1494,10 +1490,9 @@ public static Observable concat(Observable t1, Observable the common element base type * @param sources the Observable sequence of Observables * @return the new Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ @SuppressWarnings({ "rawtypes", "unchecked" }) - @Beta public static Observable concatDelayError(Observable> sources) { return sources.concatMapDelayError((Func1)UtilityFunctions.identity()); } @@ -1519,9 +1514,8 @@ public static Observable concatDelayError(Observable the common element base type * @param sources the Iterable sequence of Observables * @return the new Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Iterable> sources) { return concatDelayError(from(sources)); } @@ -1546,9 +1540,8 @@ public static Observable concatDelayError(Iterable Observable concatDelayError(Observable t1, Observable t2) { return concatDelayError(just(t1, t2)); } @@ -1575,9 +1568,8 @@ public static Observable concatDelayError(Observable t1, Obs * @param t3 * an Observable to be concatenated * @return an Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Observable t1, Observable t2,Observable t3 ) { return concatDelayError(just(t1, t2, t3)); } @@ -1606,9 +1598,8 @@ public static Observable concatDelayError(Observable t1, Obs * @param t4 * an Observable to be concatenated * @return an Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Observable t1, Observable t2, Observable t3, Observable t4) { return concatDelayError(just(t1, t2, t3, t4)); } @@ -1639,9 +1630,8 @@ public static Observable concatDelayError(Observable t1, Obs * @param t5 * an Observable to be concatenated * @return an Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Observable t1, Observable t2, Observable t3, Observable t4, Observable t5) { return concatDelayError(just(t1, t2, t3, t4, t5)); } @@ -1674,9 +1664,8 @@ public static Observable concatDelayError(Observable t1, Obs * @param t6 * an Observable to be concatenated * @return an Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Observable t1, Observable t2, Observable t3, Observable t4, Observable t5, Observable t6) { return concatDelayError(just(t1, t2, t3, t4, t5, t6)); } @@ -1711,9 +1700,8 @@ public static Observable concatDelayError(Observable t1, Obs * @param t7 * an Observable to be concatenated * @return an Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Observable t1, Observable t2, Observable t3, Observable t4, Observable t5, Observable t6, Observable t7) { return concatDelayError(just(t1, t2, t3, t4, t5, t6, t7)); } @@ -1750,9 +1738,8 @@ public static Observable concatDelayError(Observable t1, Obs * @param t8 * an Observable to be concatenated * @return an Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Observable t1, Observable t2, Observable t3, Observable t4, Observable t5, Observable t6, Observable t7, Observable t8) { return concatDelayError(just(t1, t2, t3, t4, t5, t6, t7, t8)); } @@ -1791,9 +1778,8 @@ public static Observable concatDelayError(Observable t1, Obs * @param t9 * an Observable to be concatenated * @return an Observable with the concatenating behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable concatDelayError(Observable t1, Observable t2, Observable t3, Observable t4, Observable t5, Observable t6, Observable t7, Observable t8, Observable t9) { return concatDelayError(just(t1, t2, t3, t4, t5, t6, t7, t8, t9)); } @@ -2026,54 +2012,6 @@ public static Observable from(T[] array) { return unsafeCreate(new OnSubscribeFromArray(array)); } - /** - * Provides an API (via a cold Observable) that bridges the reactive world with the callback-style, - * generally non-backpressured world. - *

- * Example: - *


-     * Observable.<Event>fromEmitter(emitter -> {
-     *     Callback listener = new Callback() {
-     *         @Override
-     *         public void onEvent(Event e) {
-     *             emitter.onNext(e);
-     *             if (e.isLast()) {
-     *                 emitter.onCompleted();
-     *             }
-     *         }
-     *
-     *         @Override
-     *         public void onFailure(Exception e) {
-     *             emitter.onError(e);
-     *         }
-     *     };
-     *
-     *     AutoCloseable c = api.someMethod(listener);
-     *
-     *     emitter.setCancellation(c::close);
-     *
-     * }, BackpressureMode.BUFFER);
-     * 
- *

- * You should call the Emitter's onNext, onError and onCompleted methods in a serialized fashion. The - * rest of its methods are thread-safe. - * - * @param the element type - * @param emitter the emitter that is called when a Subscriber subscribes to the returned {@code Observable} - * @param backpressure the backpressure mode to apply if the downstream Subscriber doesn't request (fast) enough - * @return the new Observable instance - * @see Emitter - * @see Emitter.BackpressureMode - * @see rx.functions.Cancellable - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) - * @deprecated 1.2.7 - aliased to {@link #create(Action1, rx.Emitter.BackpressureMode)}, will be removed in 1.3.0 - */ - @Experimental - @Deprecated - public static Observable fromEmitter(Action1> emitter, Emitter.BackpressureMode backpressure) { - return unsafeCreate(new OnSubscribeCreate(emitter, backpressure)); - } - /** * Returns an Observable that, when an observer subscribes to it, invokes a function you specify and then * emits the value returned from that function. @@ -3068,9 +3006,8 @@ public static Observable mergeDelayError(ObservableReactiveX operators documentation: Merge - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable mergeDelayError(Observable> source, int maxConcurrent) { return source.lift(OperatorMerge.instance(true, maxConcurrent)); } @@ -3684,10 +3621,8 @@ public static Observable switchOnNext(ObservableReactiveX operators documentation: Switch - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable switchOnNextDelayError(Observable> sequenceOfSequences) { return sequenceOfSequences.lift(OperatorSwitch.instance(true)); } @@ -3861,10 +3796,8 @@ public static Observable using( * a terminal event ({@code onComplete} or {@code onError}). * @return the Observable whose lifetime controls the lifetime of the dependent resource object * @see ReactiveX operators documentation: Using - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Observable using( final Func0 resourceFactory, final Func1> observableFactory, @@ -3966,8 +3899,8 @@ public static Observable zip(Iterable> ws, FuncN< * an item that will be emitted by the resulting Observable * @return an Observable that emits the zipped results * @see ReactiveX operators documentation: Zip + * @since 1.3 */ - @Experimental public static Observable zip(Observable[] ws, FuncN zipFunction) { return Observable.just(ws).lift(new OperatorZip(zipFunction)); } @@ -5192,9 +5125,8 @@ public final Observable concatMap(Func1 the result value type * @param func the function that maps the items of this Observable into the inner Observables. * @return the new Observable instance with the concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Observable concatMapDelayError(Func1> func) { if (this instanceof ScalarSynchronousObservable) { ScalarSynchronousObservable scalar = (ScalarSynchronousObservable) this; @@ -5692,9 +5624,8 @@ public final Observable delaySubscription(Func0> * to this Observable. * @return an Observable that delays the subscription to this Observable * until the other Observable emits an element or completes normally. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Observable delaySubscription(Observable other) { if (other == null) { throw new NullPointerException(); @@ -5836,10 +5767,8 @@ public final Observable distinctUntilChanged(Func1ReactiveX operators documentation: Distinct - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical - * with the release number) + * @since 1.3 */ - @Beta public final Observable distinctUntilChanged(Func2 comparator) { return lift(new OperatorDistinctUntilChanged(comparator)); } @@ -6098,9 +6027,8 @@ public final Observable doOnUnsubscribe(final Action0 unsubscribe) { * @param o1 the first source * @param o2 the second source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager(Observable o1, Observable o2) { return concatEager(Arrays.asList(o1, o2)); @@ -6124,9 +6052,8 @@ public static Observable concatEager(Observable o1, Observab * @param o2 the second source * @param o3 the third source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager( Observable o1, Observable o2, @@ -6154,9 +6081,8 @@ public static Observable concatEager( * @param o3 the third source * @param o4 the fourth source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager( Observable o1, Observable o2, @@ -6185,9 +6111,8 @@ public static Observable concatEager( * @param o4 the fourth source * @param o5 the fifth source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager( Observable o1, Observable o2, @@ -6218,9 +6143,8 @@ public static Observable concatEager( * @param o5 the fifth source * @param o6 the sixth source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager( Observable o1, Observable o2, @@ -6252,9 +6176,8 @@ public static Observable concatEager( * @param o6 the sixth source * @param o7 the seventh source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager( Observable o1, Observable o2, @@ -6288,9 +6211,8 @@ public static Observable concatEager( * @param o7 the seventh source * @param o8 the eighth source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager( Observable o1, Observable o2, @@ -6325,9 +6247,8 @@ public static Observable concatEager( * @param o8 the eighth source * @param o9 the ninth source * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings("unchecked") public static Observable concatEager( Observable o1, Observable o2, @@ -6355,9 +6276,8 @@ public static Observable concatEager( * @param the value type * @param sources a sequence of Observables that need to be eagerly concatenated * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings({ "unchecked", "rawtypes" }) public static Observable concatEager(Iterable> sources) { return Observable.from(sources).concatMapEager((Func1)UtilityFunctions.identity()); @@ -6380,9 +6300,8 @@ public static Observable concatEager(Iterable Observable concatEager(Iterable> sources, int capacityHint) { return Observable.from(sources).concatMapEager((Func1)UtilityFunctions.identity(), capacityHint); @@ -6404,9 +6323,8 @@ public static Observable concatEager(Iterable the value type * @param sources a sequence of Observables that need to be eagerly concatenated * @return the new Observable instance with the specified concatenation behavior - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta @SuppressWarnings({ "unchecked", "rawtypes" }) public static Observable concatEager(Observable> sources) { return sources.concatMapEager((Func1)UtilityFunctions.identity()); @@ -6429,9 +6347,8 @@ public static Observable concatEager(Observable Observable concatEager(Observable> sources, int capacityHint) { return sources.concatMapEager((Func1)UtilityFunctions.identity(), capacityHint); @@ -6455,9 +6372,8 @@ public static Observable concatEager(Observable Observable concatMapEager(Func1> mapper) { return concatMapEager(mapper, RxRingBuffer.SIZE); } @@ -6481,9 +6397,8 @@ public final Observable concatMapEager(Func1 Observable concatMapEager(Func1> mapper, int capacityHint) { if (capacityHint < 1) { throw new IllegalArgumentException("capacityHint > 0 required but it was " + capacityHint); @@ -6511,9 +6426,8 @@ public final Observable concatMapEager(Func1 Observable concatMapEager(Func1> mapper, int capacityHint, int maxConcurrent) { if (capacityHint < 1) { throw new IllegalArgumentException("capacityHint > 0 required but it was " + capacityHint); @@ -6983,13 +6897,13 @@ public final Observable flatMap(final Func1Scheduler: *

{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param mapper the function that receives an upstream value and turns it into a Completable * to be merged. * @return the new Observable instance * @see #flatMapCompletable(Func1, boolean, int) - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public final Observable flatMapCompletable(Func1 mapper) { return flatMapCompletable(mapper, false, Integer.MAX_VALUE); } @@ -7004,15 +6918,15 @@ public final Observable flatMapCompletable(Func1Scheduler: *

{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param mapper the function that receives an upstream value and turns it into a Completable * to be merged. * @param delayErrors if true, errors from the upstream and from the inner Completables get delayed till * the all of them terminate. * @return the new Observable instance - * @since 1.2.7 - experimental + * @since 1.3 * @see #flatMapCompletable(Func1, boolean, int) */ - @Experimental public final Observable flatMapCompletable(Func1 mapper, boolean delayErrors) { return flatMapCompletable(mapper, delayErrors, Integer.MAX_VALUE); } @@ -7028,15 +6942,15 @@ public final Observable flatMapCompletable(Func1Scheduler: *

{@code flatMapCompletable} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param mapper the function that receives an upstream value and turns it into a Completable * to be merged. * @param delayErrors if true, errors from the upstream and from the inner Completables get delayed till * the all of them terminate. * @param maxConcurrency the maximum number of inner Completables to run at a time * @return the new Observable instance - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public final Observable flatMapCompletable(Func1 mapper, boolean delayErrors, int maxConcurrency) { return unsafeCreate(new OnSubscribeFlatMapCompletable(this, mapper, delayErrors, maxConcurrency)); } @@ -7183,14 +7097,14 @@ public final Observable flatMapIterable(Func1Scheduler: *

{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param the value type of the inner Singles and the resulting Observable * @param mapper the function that receives an upstream value and turns it into a Single * to be merged. * @return the new Observable instance * @see #flatMapSingle(Func1, boolean, int) - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public final Observable flatMapSingle(Func1> mapper) { return flatMapSingle(mapper, false, Integer.MAX_VALUE); } @@ -7204,16 +7118,16 @@ public final Observable flatMapSingle(Func1Scheduler: *

{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param the value type of the inner Singles and the resulting Observable * @param mapper the function that receives an upstream value and turns it into a Single * to be merged. * @param delayErrors if true, errors from the upstream and from the inner Singles get delayed till * the all of them terminate. * @return the new Observable instance - * @since 1.2.7 - experimental + * @since 1.3 * @see #flatMapSingle(Func1, boolean, int) */ - @Experimental public final Observable flatMapSingle(Func1> mapper, boolean delayErrors) { return flatMapSingle(mapper, delayErrors, Integer.MAX_VALUE); } @@ -7228,6 +7142,7 @@ public final Observable flatMapSingle(Func1Scheduler: *

{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param the value type of the inner Singles and the resulting Observable * @param mapper the function that receives an upstream value and turns it into a Single * to be merged. @@ -7235,9 +7150,8 @@ public final Observable flatMapSingle(Func1 Observable flatMapSingle(Func1> mapper, boolean delayErrors, int maxConcurrency) { return unsafeCreate(new OnSubscribeFlatMapSingle(this, mapper, delayErrors, maxConcurrency)); } @@ -7419,8 +7333,8 @@ public final Observable> groupBy(final Func1ReactiveX operators documentation: GroupBy + * @since 1.3 */ - @Experimental public final Observable> groupBy(final Func1 keySelector, final Func1 elementSelector, final Func1, Map> evictingMapFactory) { if (evictingMapFactory == null) { @@ -8049,9 +7963,8 @@ public final Observable onBackpressureBuffer(long capacity, Action0 onOverflo * @param overflowStrategy how should the {@code Observable} react to buffer overflows. Null is not allowed. * @return the source {@code Observable} modified to buffer items up to the given capacity * @see ReactiveX operators documentation: backpressure operators - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Observable onBackpressureBuffer(long capacity, Action0 onOverflow, BackpressureOverflow.Strategy overflowStrategy) { return lift(new OperatorOnBackpressureBuffer(capacity, onOverflow, overflowStrategy)); } @@ -8075,7 +7988,6 @@ public final Observable onBackpressureBuffer(long capacity, Action0 onOverflo * @param onDrop the action to invoke for each item dropped. onDrop action should be fast and should never block. * @return the source Observable modified to drop {@code onNext} notifications on overflow * @see ReactiveX operators documentation: backpressure operators - * @Experimental The behavior of this can change at any time. * @since 1.1.0 */ public final Observable onBackpressureDrop(Action1 onDrop) { @@ -8306,9 +8218,8 @@ public final Observable onExceptionResumeNext(final Observable r * * @return an Observable which out references to the upstream producer and downstream Subscriber if * the sequence is terminated or downstream unsubscribes - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable onTerminateDetach() { return unsafeCreate(new OnSubscribeDetach(this)); } @@ -8381,9 +8292,8 @@ public final Observable publish(Func1, ? extends Ob * * @param n the initial request amount, further request will happen after 75% of this value * @return the Observable that rebatches request amounts from downstream - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable rebatchRequests(int n) { if (n <= 0) { throw new IllegalArgumentException("n > 0 required but it was " + n); @@ -10511,7 +10421,7 @@ public final Observable subscribeOn(Scheduler scheduler) { *

Scheduler:
*
you specify which {@link Scheduler} this operator will use
* - * + *

History: 1.2.7 - experimental * @param scheduler * the {@link Scheduler} to perform subscription actions on * @param requestOn if true, requests are rerouted to the given Scheduler as well (strong pipelining) @@ -10523,9 +10433,8 @@ public final Observable subscribeOn(Scheduler scheduler) { * @see RxJava Threading Examples * @see #observeOn * @see #subscribeOn(Scheduler) - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public final Observable subscribeOn(Scheduler scheduler, boolean requestOn) { if (this instanceof ScalarSynchronousObservable) { return ((ScalarSynchronousObservable)this).scalarScheduleOn(scheduler); @@ -10589,10 +10498,8 @@ public final Observable switchMap(Func1ReactiveX operators documentation: FlatMap - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Observable switchMapDelayError(Func1> func) { return switchOnNextDelayError(map(func)); } @@ -11929,9 +11836,8 @@ public final Observable> toSortedList(Func2ReactiveX operators documentation: To - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Observable> toSortedList(int initialCapacity) { return lift(new OperatorToObservableSortedList(initialCapacity)); } @@ -11957,9 +11863,8 @@ public final Observable> toSortedList(int initialCapacity) { * @return an Observable that emits a list that contains the items emitted by the source Observable in * sorted order * @see ReactiveX operators documentation: To - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Observable> toSortedList(Func2 sortFunction, int initialCapacity) { return lift(new OperatorToObservableSortedList(sortFunction, initialCapacity)); } @@ -11984,8 +11889,8 @@ public final Observable> toSortedList(Func2 sorted() { return toSortedList().flatMapIterable(UtilityFunctions.>identity()); } @@ -12009,8 +11914,8 @@ public final Observable sorted() { * a function that compares two items emitted by the source Observable and returns an Integer * that indicates their sort order * @return an Observable that emits the items emitted by the source Observable in sorted order + * @since 1.3 */ - @Experimental public final Observable sorted(Func2 sortFunction) { return toSortedList(sortFunction).flatMapIterable(UtilityFunctions.>identity()); } @@ -12061,11 +11966,9 @@ public final Observable unsubscribeOn(Scheduler scheduler) { * @return an Observable that merges the specified Observable into this Observable by using the * {@code resultSelector} function only when the source Observable sequence (this instance) emits an * item - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 * @see ReactiveX operators documentation: CombineLatest */ - @Experimental public final Observable withLatestFrom(Observable other, Func2 resultSelector) { return lift(new OperatorWithLatestFrom(other, resultSelector)); } @@ -12094,10 +11997,8 @@ public final Observable withLatestFrom(Observable other, * @param o2 the second other Observable * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom(Observable o1, Observable o2, Func3 combiner) { return unsafeCreate(new OperatorWithLatestFromMany(this, new Observable[] { o1, o2 }, null, Functions.fromFunc(combiner))); } @@ -12128,10 +12029,8 @@ public final Observable withLatestFrom(Observable o1, Observa * @param o3 the third other Observable * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, @@ -12168,10 +12067,8 @@ public final Observable withLatestFrom( * @param o4 the fourth other Observable * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, Observable o4, @@ -12209,10 +12106,8 @@ public final Observable withLatestFrom( * @param o5 the fifth other Observable * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, Observable o4, @@ -12254,10 +12149,8 @@ public final Observable withLatestFrom( * @param o6 the sixth other Observable * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, Observable o4, @@ -12301,10 +12194,8 @@ public final Observable withLatestFrom( * @param o7 the seventh other Observable * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, Observable o4, @@ -12351,10 +12242,8 @@ public final Observable withLatestFrom( * @param o8 the eighth other Observable * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom( Observable o1, Observable o2, Observable o3, Observable o4, @@ -12386,10 +12275,8 @@ public final Observable withLatestFrom( * @param others the array of other sources * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom(Observable[] others, FuncN combiner) { return unsafeCreate(new OperatorWithLatestFromMany(this, others, null, combiner)); } @@ -12415,10 +12302,8 @@ public final Observable withLatestFrom(Observable[] others, FuncN c * @param others the iterable of other sources * @param combiner the function called with an array of values from each participating observable * @return the new Observable instance - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Observable withLatestFrom(Iterable> others, FuncN combiner) { return unsafeCreate(new OperatorWithLatestFromMany(this, null, others, combiner)); } @@ -12899,10 +12784,10 @@ public final Observable zipWith(Observable other, Func2 *

Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.3 - experimental * @return the new AssertableSubscriber instance - * @since 1.2.3 + * @since 1.3 */ - @Experimental public final AssertableSubscriber test() { AssertableSubscriber ts = AssertableSubscriberObservable.create(Long.MAX_VALUE); subscribe(ts); @@ -12918,11 +12803,11 @@ public final AssertableSubscriber test() { *

Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.3 - experimental * @return the new AssertableSubscriber instance * @param initialRequestAmount the amount to request from upstream upfront, non-negative (not verified) - * @since 1.2.3 + * @since 1.3 */ - @Experimental public final AssertableSubscriber test(long initialRequestAmount) { AssertableSubscriber ts = AssertableSubscriberObservable.create(initialRequestAmount); subscribe(ts); diff --git a/src/main/java/rx/Scheduler.java b/src/main/java/rx/Scheduler.java index b98615ff47..89259b178b 100644 --- a/src/main/java/rx/Scheduler.java +++ b/src/main/java/rx/Scheduler.java @@ -17,7 +17,6 @@ import java.util.concurrent.TimeUnit; -import rx.annotations.Experimental; import rx.functions.*; import rx.internal.schedulers.*; import rx.schedulers.Schedulers; @@ -203,9 +202,9 @@ public long now() { * @param combine the function that takes a two-level nested Observable sequence of a Completable and returns * the Completable that will be subscribed to and should trigger the execution of the scheduled Actions. * @return the Scheduler with the customized execution behavior + * @since 1.3 */ @SuppressWarnings("unchecked") - @Experimental public S when(Func1>, Completable> combine) { return (S) new SchedulerWhen(combine, this); } diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index 0b39b6f24f..a9bff5e388 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -145,8 +145,8 @@ public interface OnSubscribe extends Action1> { * the Operator that implements the Single-operating function to be applied to the source Single * @return a Single that is the result of applying the lifted Operator to the source Single * @see RxJava wiki: Implementing Your Own Operators + * @since 1.3 */ - @Beta public final Single lift(final Operator lift) { return create(new SingleLiftObservableOperator(this.onSubscribe, lift)); } @@ -602,12 +602,12 @@ public static Single fromCallable(final Callable func) { * *

All of the SingleEmitter's methods are thread-safe and ensure the * Single's protocol are held. + *

History: 1.2.3 - experimental * @param the success value type * @param producer the callback invoked for each incoming SingleSubscriber * @return the new Single instance - * @since 1.2.3 - experimental (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public static Single fromEmitter(Action1> producer) { if (producer == null) { throw new NullPointerException("producer is null"); } return create(new SingleFromEmitter(producer)); @@ -939,15 +939,15 @@ public static Observable merge(Single t1, SingleScheduler: *

{@code merge} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param the value type of the inner Singles and the resulting Observable * @param sources the Observable that emits Singles to be merged * @return the new Observable instance * @see #merge(Observable, int) * @see #mergeDelayError(Observable) * @see #mergeDelayError(Observable, int) - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public static Observable merge(Observable> sources) { return merge(sources, Integer.MAX_VALUE); } @@ -963,14 +963,14 @@ public static Observable merge(Observable> *

Scheduler:
*
{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param the value type of the inner Singles and the resulting Observable * @param sources the Observable that emits Singles to be merged * @param maxConcurrency the maximum number of inner Singles to run at a time * @return the new Observable instance - * @since 1.2.7 - experimental + * @since 1.3 */ @SuppressWarnings({ "unchecked", "rawtypes" }) - @Experimental public static Observable merge(Observable> sources, int maxConcurrency) { return sources.flatMapSingle((Func1)UtilityFunctions.identity(), false, maxConcurrency); } @@ -985,15 +985,15 @@ public static Observable merge(Observable> *

Scheduler:
*
{@code merge} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param the value type of the inner Singles and the resulting Observable * @param sources the Observable that emits Singles to be merged * @return the new Observable instance * @see #mergeDelayError(Observable, int) * @see #merge(Observable) * @see #merge(Observable, int) - * @since 1.2.7 - experimental + * @since 1.3 */ - @Experimental public static Observable mergeDelayError(Observable> sources) { return merge(sources, Integer.MAX_VALUE); } @@ -1009,14 +1009,14 @@ public static Observable mergeDelayError(ObservableScheduler: *

{@code flatMapSingle} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.7 - experimental * @param the value type of the inner Singles and the resulting Observable * @param sources the Observable that emits Singles to be merged * @param maxConcurrency the maximum number of inner Singles to run at a time * @return the new Observable instance - * @since 1.2.7 - experimental + * @since 1.3 */ @SuppressWarnings({ "unchecked", "rawtypes" }) - @Experimental public static Observable mergeDelayError(Observable> sources, int maxConcurrency) { return sources.flatMapSingle((Func1)UtilityFunctions.identity(), true, maxConcurrency); } @@ -1452,8 +1452,8 @@ public static Single zip(Iterable> singles, FuncNReactiveX operators documentation: Replay + * @since 1.3 */ - @Experimental public final Single cache() { return toObservable().cacheWithInitialCapacity(1).toSingle(); } @@ -1537,9 +1537,8 @@ public final Observable flatMapObservable(Func1ReactiveX operators documentation: FlatMap - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Completable flatMapCompletable(final Func1 func) { return Completable.create(new CompletableFlatMapSingleToCompletable(this, func)); } @@ -1669,10 +1668,8 @@ public final Single onErrorReturn(Func1 resumeFunctio * @param resumeSingleInCaseOfError a Single that will take control if source Single encounters an error. * @return the original Single, with appropriately modified behavior. * @see ReactiveX operators documentation: Catch - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single onErrorResumeNext(Single resumeSingleInCaseOfError) { return new Single(SingleOperatorOnErrorResumeNext.withOther(this, resumeSingleInCaseOfError)); } @@ -1703,10 +1700,8 @@ public final Single onErrorResumeNext(Single resumeSingleInCaseO * @param resumeFunctionInCaseOfError a function that returns a Single that will take control if source Single encounters an error. * @return the original Single, with appropriately modified behavior. * @see ReactiveX operators documentation: Catch - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single onErrorResumeNext(final Func1> resumeFunctionInCaseOfError) { return new Single(SingleOperatorOnErrorResumeNext.withFunction(this, resumeFunctionInCaseOfError)); } @@ -2117,8 +2112,8 @@ public final Single takeUntil(final Single other) { * @param the resulting object type * @param converter the function that receives the current Single instance and returns a value * @return the value returned by the function + * @since 1.3 */ - @Experimental public final R to(Func1, R> converter) { return converter.call(this); } @@ -2150,10 +2145,8 @@ public final Observable toObservable() { * @return a {@link Completable} that calls {@code onCompleted} on it's subscriber when the source {@link Single} * calls {@code onSuccess}. * @see ReactiveX documentation: Completable - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical - * with the release number). + * @since 1.3 */ - @Beta public final Completable toCompletable() { return Completable.fromSingle(this); } @@ -2276,8 +2269,8 @@ public Single call() { * * @return a {@code BlockingSingle} version of this Single. * @see ReactiveX operators documentation: To + * @since 1.3 */ - @Beta public final BlockingSingle toBlocking() { return BlockingSingle.from(this); } @@ -2326,9 +2319,8 @@ public final Single zipWith(Single other, Func2ReactiveX operators documentation: Do - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single doOnError(final Action1 onError) { if (onError == null) { throw new IllegalArgumentException("onError is null"); @@ -2355,9 +2347,8 @@ public void call(final Throwable throwable) { * the action to invoke when the source {@link Single} calls {@code onSuccess} or {@code onError}. * @return the source {@link Single} with the side-effecting behavior applied * @see ReactiveX operators documentation: Do - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Single doOnEach(final Action1> onNotification) { if (onNotification == null) { throw new IllegalArgumentException("onNotification is null"); @@ -2389,9 +2380,8 @@ public void call(final Throwable throwable) { * the action to invoke when the source {@link Single} calls {@code onSuccess} * @return the source {@link Single} with the side-effecting behavior applied * @see ReactiveX operators documentation: Do - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final Single doOnSuccess(final Action1 onSuccess) { if (onSuccess == null) { throw new IllegalArgumentException("onSuccess is null"); @@ -2417,9 +2407,8 @@ public final Single doOnSuccess(final Action1 onSuccess) { * the action that gets called when an observer subscribes to this {@code Single} * @return the source {@code Single} modified so as to call this Action when appropriate * @see ReactiveX operators documentation: Do - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single doOnSubscribe(final Action0 subscribe) { return create(new SingleDoOnSubscribe(onSubscribe, subscribe)); } @@ -2442,9 +2431,8 @@ public final Single doOnSubscribe(final Action0 subscribe) { * the {@link Scheduler} to use for delaying * @return the source Single shifted in time by the specified delay * @see ReactiveX operators documentation: Delay - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single delay(long delay, TimeUnit unit, Scheduler scheduler) { return create(new SingleDelay(onSubscribe, delay, unit, scheduler)); } @@ -2465,9 +2453,8 @@ public final Single delay(long delay, TimeUnit unit, Scheduler scheduler) { * the {@link TimeUnit} in which {@code period} is defined * @return the source Single shifted in time by the specified delay * @see ReactiveX operators documentation: Delay - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single delay(long delay, TimeUnit unit) { return delay(delay, unit, Schedulers.computation()); } @@ -2495,9 +2482,8 @@ public final Single delay(long delay, TimeUnit unit) { * @return a {@link Single} whose {@link Observer}s' subscriptions trigger an invocation of the given * {@link Single} factory function. * @see ReactiveX operators documentation: Defer - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Single defer(final Callable> singleFactory) { return create(new OnSubscribe() { @Override @@ -2531,9 +2517,8 @@ public void call(SingleSubscriber singleSubscriber) { * the action that gets called when this {@link Single} is unsubscribed. * @return the source {@link Single} modified so as to call this Action when appropriate. * @see ReactiveX operators documentation: Do - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single doOnUnsubscribe(final Action0 action) { return create(new SingleDoOnUnsubscribe(onSubscribe, action)); } @@ -2553,9 +2538,8 @@ public final Single doOnUnsubscribe(final Action0 action) { * @return a {@link Single} that emits the same item or error as the source {@link Single}, then invokes the * {@link Action0} * @see ReactiveX operators documentation: Do - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single doAfterTerminate(Action0 action) { return create(new SingleDoAfterTerminate(this, action)); } @@ -2735,8 +2719,8 @@ public final Single retryWhen(final Func1, ? * the function that will dispose of the resource * @return the Single whose lifetime controls the lifetime of the dependent resource object * @see ReactiveX operators documentation: Using + * @since 1.3 */ - @Beta public static Single using( final Func0 resourceFactory, final Func1> singleFactory, @@ -2770,10 +2754,8 @@ public static Single using( * a terminal event ({@code onComplete} or {@code onError}). * @return the Single whose lifetime controls the lifetime of the dependent resource object * @see ReactiveX operators documentation: Using - * @Experimental The behavior of this can change at any time. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static Single using( final Func0 resourceFactory, final Func1> singleFactory, @@ -2806,9 +2788,8 @@ public static Single using( * to this Single. * @return a Single that delays the subscription to this Single * until the Observable emits an element or completes normally. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public final Single delaySubscription(Observable other) { if (other == null) { throw new NullPointerException(); @@ -2874,10 +2855,10 @@ public void call() { *

Scheduler:
*
{@code test} does not operate by default on a particular {@link Scheduler}.
* + *

History: 1.2.3 - experimental * @return the new AssertableSubscriber instance - * @since 1.2.3 + * @since 1.3 */ - @Experimental public final AssertableSubscriber test() { AssertableSubscriberObservable ts = AssertableSubscriberObservable.create(Long.MAX_VALUE); subscribe(ts); diff --git a/src/main/java/rx/SingleEmitter.java b/src/main/java/rx/SingleEmitter.java index c4f3d11615..a60d0840a5 100644 --- a/src/main/java/rx/SingleEmitter.java +++ b/src/main/java/rx/SingleEmitter.java @@ -15,7 +15,6 @@ */ package rx; -import rx.annotations.Experimental; import rx.functions.Cancellable; /** @@ -24,11 +23,10 @@ *

* All methods are thread-safe; calling onSuccess or onError twice or one after the other has * no effect. - * @since 1.2.3 - experimental (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) - * + *

History: 1.2.3 - experimental * @param the success value type + * @since 1.3 */ -@Experimental public interface SingleEmitter { /** diff --git a/src/main/java/rx/exceptions/AssemblyStackTraceException.java b/src/main/java/rx/exceptions/AssemblyStackTraceException.java index 8342adc637..c21cb94510 100644 --- a/src/main/java/rx/exceptions/AssemblyStackTraceException.java +++ b/src/main/java/rx/exceptions/AssemblyStackTraceException.java @@ -17,14 +17,13 @@ import java.util.*; -import rx.annotations.Experimental; import rx.plugins.RxJavaHooks; /** * A RuntimeException that is stackless but holds onto a textual * stacktrace from tracking the assembly location of operators. + * @since 1.3 */ -@Experimental public final class AssemblyStackTraceException extends RuntimeException { /** */ diff --git a/src/main/java/rx/exceptions/CompositeException.java b/src/main/java/rx/exceptions/CompositeException.java index cfbfdc2113..855d720e49 100644 --- a/src/main/java/rx/exceptions/CompositeException.java +++ b/src/main/java/rx/exceptions/CompositeException.java @@ -18,8 +18,6 @@ import java.io.*; import java.util.*; -import rx.annotations.Beta; - /** * Represents an exception that is a composite of one or more other exceptions. A {@code CompositeException} * does not modify the structure of any exception it wraps, but at print-time it iterates through the list of @@ -85,8 +83,8 @@ public CompositeException(Collection errors) { /** * Constructs a CompositeException instance with the supplied initial Throwables. * @param errors the array of Throwables + * @since 1.3 */ - @Beta public CompositeException(Throwable... errors) { Set deDupedExceptions = new LinkedHashSet(); List localExceptions = new ArrayList(); diff --git a/src/main/java/rx/exceptions/Exceptions.java b/src/main/java/rx/exceptions/Exceptions.java index 276e563e48..9e5f25393d 100644 --- a/src/main/java/rx/exceptions/Exceptions.java +++ b/src/main/java/rx/exceptions/Exceptions.java @@ -19,7 +19,6 @@ import rx.Observer; import rx.SingleSubscriber; -import rx.annotations.Beta; /** * Utility class with methods to wrap checked exceptions and @@ -182,9 +181,8 @@ public static void throwIfAny(List exceptions) { * @param t the exception * @param o the observer to report to * @param value the value that caused the exception - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static void throwOrReport(Throwable t, Observer o, Object value) { Exceptions.throwIfFatal(t); o.onError(OnErrorThrowable.addValueAsLastCause(t, value)); @@ -196,9 +194,8 @@ public static void throwOrReport(Throwable t, Observer o, Object value) { * @param t the exception * @param o the observer to report to * @param value the value that caused the exception - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static void throwOrReport(Throwable t, SingleSubscriber o, Object value) { Exceptions.throwIfFatal(t); o.onError(OnErrorThrowable.addValueAsLastCause(t, value)); @@ -208,9 +205,8 @@ public static void throwOrReport(Throwable t, SingleSubscriber o, Object valu * Forwards a fatal exception or reports it to the given Observer. * @param t the exception * @param o the observer to report to - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public static void throwOrReport(Throwable t, Observer o) { Exceptions.throwIfFatal(t); o.onError(t); @@ -221,9 +217,8 @@ public static void throwOrReport(Throwable t, Observer o) { * * @param throwable the exception. * @param subscriber the subscriber to report to. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number). + * @since 1.3 */ - @Beta public static void throwOrReport(Throwable throwable, SingleSubscriber subscriber) { Exceptions.throwIfFatal(throwable); subscriber.onError(throwable); diff --git a/src/main/java/rx/functions/Cancellable.java b/src/main/java/rx/functions/Cancellable.java index 1109522d86..7b92b71884 100644 --- a/src/main/java/rx/functions/Cancellable.java +++ b/src/main/java/rx/functions/Cancellable.java @@ -16,12 +16,10 @@ package rx.functions; -import rx.annotations.Experimental; - /** * A functional interface that has a single close method that can throw. + * @since 1.3 */ -@Experimental public interface Cancellable { /** diff --git a/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java b/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java index b9068b04ff..d9081b5a8d 100644 --- a/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java +++ b/src/main/java/rx/internal/observers/AssertableSubscriberObservable.java @@ -20,7 +20,6 @@ import rx.Producer; import rx.Subscriber; -import rx.annotations.Experimental; import rx.functions.Action0; import rx.observers.TestSubscriber; import rx.observers.AssertableSubscriber; @@ -33,8 +32,8 @@ * * @param * the value type + * @since 1.3 */ -@Experimental public class AssertableSubscriberObservable extends Subscriber implements AssertableSubscriber { private final TestSubscriber ts; diff --git a/src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java b/src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java index bfb8d6d69a..8b22e740a0 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java +++ b/src/main/java/rx/internal/operators/OnSubscribeFlatMapCompletable.java @@ -27,8 +27,9 @@ /** * Maps upstream values to Completables and merges them, up to a given * number of them concurrently, optionally delaying errors. + *

History: 1.2.7 - experimental * @param the upstream value type - * @since 1.2.7 - experimental + * @since 1.3 */ public final class OnSubscribeFlatMapCompletable implements Observable.OnSubscribe { diff --git a/src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java b/src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java index b64a4ef760..190d6acbc0 100644 --- a/src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java +++ b/src/main/java/rx/internal/operators/OnSubscribeFlatMapSingle.java @@ -31,9 +31,10 @@ /** * Maps upstream values to Singles and merges them, up to a given * number of them concurrently, optionally delaying errors. + *

History: 1.2.7 - experimental * @param the upstream value type * @param the inner Singles and result value type - * @since 1.2.7 - experimental + * @since 1.3 */ public final class OnSubscribeFlatMapSingle implements Observable.OnSubscribe { diff --git a/src/main/java/rx/internal/schedulers/SchedulerWhen.java b/src/main/java/rx/internal/schedulers/SchedulerWhen.java index 880992c9d5..f35528bb12 100644 --- a/src/main/java/rx/internal/schedulers/SchedulerWhen.java +++ b/src/main/java/rx/internal/schedulers/SchedulerWhen.java @@ -26,7 +26,6 @@ import rx.Observer; import rx.Scheduler; import rx.Subscription; -import rx.annotations.Experimental; import rx.functions.Action0; import rx.functions.Func1; import rx.internal.operators.BufferUntilSubscriber; @@ -101,8 +100,8 @@ * })); * }); * + * @since 1.3 */ -@Experimental public class SchedulerWhen extends Scheduler implements Subscription { private final Scheduler actualScheduler; private final Observer> workerObserver; diff --git a/src/main/java/rx/internal/util/BackpressureDrainManager.java b/src/main/java/rx/internal/util/BackpressureDrainManager.java index 9fde1e62f7..da31c78178 100644 --- a/src/main/java/rx/internal/util/BackpressureDrainManager.java +++ b/src/main/java/rx/internal/util/BackpressureDrainManager.java @@ -18,16 +18,14 @@ import java.util.concurrent.atomic.AtomicLong; import rx.Producer; -import rx.annotations.Experimental; /** * Manages the producer-backpressure-consumer interplay by * matching up available elements with requested elements and/or * terminal events. - * - * @since 1.1.0 + *

History: 1.1.0 - experimental + * @since 1.3 */ -@Experimental public final class BackpressureDrainManager extends AtomicLong implements Producer { /** */ private static final long serialVersionUID = 2826241102729529449L; diff --git a/src/main/java/rx/internal/util/BlockingUtils.java b/src/main/java/rx/internal/util/BlockingUtils.java index 17b0143e52..cb010af57e 100644 --- a/src/main/java/rx/internal/util/BlockingUtils.java +++ b/src/main/java/rx/internal/util/BlockingUtils.java @@ -17,7 +17,6 @@ package rx.internal.util; import rx.Subscription; -import rx.annotations.Experimental; import java.util.concurrent.CountDownLatch; @@ -25,8 +24,8 @@ * Utility functions relating to blocking types. *

* Not intended to be part of the public API. + * @since 1.3 */ -@Experimental public final class BlockingUtils { private BlockingUtils() { } @@ -37,7 +36,6 @@ private BlockingUtils() { } * @param latch a CountDownLatch * @param subscription the Subscription to wait on. */ - @Experimental public static void awaitForComplete(CountDownLatch latch, Subscription subscription) { if (latch.getCount() == 0) { // Synchronous observable completes before awaiting for it. diff --git a/src/main/java/rx/observables/AsyncOnSubscribe.java b/src/main/java/rx/observables/AsyncOnSubscribe.java index e3acb1627e..e8d1ff71e6 100644 --- a/src/main/java/rx/observables/AsyncOnSubscribe.java +++ b/src/main/java/rx/observables/AsyncOnSubscribe.java @@ -23,7 +23,7 @@ import rx.Observable; import rx.Observable.OnSubscribe; import rx.Observer; -import rx.annotations.Experimental; +import rx.annotations.Beta; import rx.functions.*; import rx.internal.operators.BufferUntilSubscriber; import rx.observers.SerializedObserver; @@ -43,8 +43,9 @@ * {@link #onUnsubscribe(Object) onUnsubscribe(S)}. * @param * the type of {@code Subscribers} that will be compatible with {@code this}. + * @since 1.3 - beta */ -@Experimental +@Beta public abstract class AsyncOnSubscribe implements OnSubscribe { /** @@ -110,7 +111,6 @@ protected void onUnsubscribe(S state) { * {@link #next(Object, long, Observer) next(S, long, Observer)}) * @return an AsyncOnSubscribe that emits data in a protocol compatible with back-pressure. */ - @Experimental public static AsyncOnSubscribe createSingleState(Func0 generator, final Action3>> next) { Func3>, S> nextFunc = @@ -141,7 +141,6 @@ public S call(S state, Long requested, Observer> subscri * @return an AsyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. */ - @Experimental public static AsyncOnSubscribe createSingleState(Func0 generator, final Action3>> next, final Action1 onUnsubscribe) { @@ -171,7 +170,6 @@ public S call(S state, Long requested, Observer> subscri * @return an AsyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. */ - @Experimental public static AsyncOnSubscribe createStateful(Func0 generator, Func3>, ? extends S> next, Action1 onUnsubscribe) { @@ -192,7 +190,6 @@ public static AsyncOnSubscribe createStateful(Func0 ge * @return an AsyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. */ - @Experimental public static AsyncOnSubscribe createStateful(Func0 generator, Func3>, ? extends S> next) { return new AsyncOnSubscribeImpl(generator, next); @@ -212,7 +209,6 @@ public static AsyncOnSubscribe createStateful(Func0 ge * @return an AsyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. */ - @Experimental public static AsyncOnSubscribe createStateless(final Action2>> next) { Func3>, Void> nextFunc = new Func3>, Void>() { @@ -240,7 +236,6 @@ public Void call(Void state, Long requested, Observer> s * @return an AsyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. */ - @Experimental public static AsyncOnSubscribe createStateless(final Action2>> next, final Action0 onUnsubscribe) { Func3>, Void> nextFunc = diff --git a/src/main/java/rx/observables/BlockingObservable.java b/src/main/java/rx/observables/BlockingObservable.java index 59cb245415..ebde4486b0 100644 --- a/src/main/java/rx/observables/BlockingObservable.java +++ b/src/main/java/rx/observables/BlockingObservable.java @@ -22,7 +22,6 @@ import rx.*; import rx.Observable; import rx.Observer; -import rx.annotations.Beta; import rx.exceptions.*; import rx.functions.*; import rx.internal.operators.*; @@ -469,9 +468,8 @@ public void onNext(final T item) { /** * Runs the source observable to a terminal event, ignoring any values and rethrowing any exception. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public void subscribe() { final CountDownLatch cdl = new CountDownLatch(1); final Throwable[] error = { null }; @@ -503,9 +501,8 @@ public void onCompleted() { /** * Subscribes to the source and calls back the Observer methods on the current thread. * @param observer the observer to call event methods on - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public void subscribe(Observer observer) { final BlockingQueue queue = new LinkedBlockingQueue(); @@ -548,10 +545,9 @@ public void onCompleted() { *

* The unsubscription and backpressure is composed through. * @param subscriber the subscriber to forward events and calls to in the current thread - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ @SuppressWarnings("unchecked") - @Beta public void subscribe(Subscriber subscriber) { final BlockingQueue queue = new LinkedBlockingQueue(); final Producer[] theProducer = { null }; @@ -631,9 +627,8 @@ public void call() { * * @param onNext the callback action for each source value * @see #forEach(Action1) - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public void subscribe(final Action1 onNext) { subscribe(onNext, new Action1() { @Override @@ -647,9 +642,8 @@ public void call(Throwable t) { * Subscribes to the source and calls the given actions on the current thread. * @param onNext the callback action for each source value * @param onError the callback action for an error event - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Beta public void subscribe(final Action1 onNext, final Action1 onError) { subscribe(onNext, onError, Actions.empty()); } @@ -659,9 +653,8 @@ public void subscribe(final Action1 onNext, final Action1 onNext, final Action1 onError, final Action0 onCompleted) { subscribe(new Observer() { @Override diff --git a/src/main/java/rx/observables/SyncOnSubscribe.java b/src/main/java/rx/observables/SyncOnSubscribe.java index cf848e7bc4..9d4b5245f4 100644 --- a/src/main/java/rx/observables/SyncOnSubscribe.java +++ b/src/main/java/rx/observables/SyncOnSubscribe.java @@ -20,7 +20,6 @@ import rx.*; import rx.Observable.OnSubscribe; -import rx.annotations.Beta; import rx.exceptions.Exceptions; import rx.functions.*; import rx.internal.operators.BackpressureUtils; @@ -120,8 +119,8 @@ protected void onUnsubscribe(S state) { * produces data to the downstream subscriber (see {@link #next(Object, Observer) * next(S, Subscriber)}) * @return a SyncOnSubscribe that emits data in a protocol compatible with back-pressure. + * @since 1.3 */ - @Beta public static SyncOnSubscribe createSingleState(Func0 generator, final Action2> next) { Func2, S> nextFunc = new Func2, S>() { @@ -151,8 +150,8 @@ public S call(S state, Observer subscriber) { * clean up behavior (see {@link #onUnsubscribe(Object) onUnsubscribe(S)}) * @return a SyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. + * @since 1.3 */ - @Beta public static SyncOnSubscribe createSingleState(Func0 generator, final Action2> next, final Action1 onUnsubscribe) { @@ -181,8 +180,8 @@ public S call(S state, Observer subscriber) { * clean up behavior (see {@link #onUnsubscribe(Object) onUnsubscribe(S)}) * @return a SyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. + * @since 1.3 */ - @Beta public static SyncOnSubscribe createStateful(Func0 generator, Func2, ? extends S> next, Action1 onUnsubscribe) { @@ -202,8 +201,8 @@ public static SyncOnSubscribe createStateful(Func0 gen * next(S, Subscriber)}) * @return a SyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. + * @since 1.3 */ - @Beta public static SyncOnSubscribe createStateful(Func0 generator, Func2, ? extends S> next) { return new SyncOnSubscribeImpl(generator, next); @@ -222,8 +221,8 @@ public static SyncOnSubscribe createStateful(Func0 gen * next(S, Subscriber)}) * @return a SyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. + * @since 1.3 */ - @Beta public static SyncOnSubscribe createStateless(final Action1> next) { Func2, Void> nextFunc = new Func2, Void>() { @Override @@ -250,8 +249,8 @@ public Void call(Void state, Observer subscriber) { * clean up behavior (see {@link #onUnsubscribe(Object) onUnsubscribe(S)}) * @return a SyncOnSubscribe that emits data downstream in a protocol compatible with * back-pressure. + * @since 1.3 */ - @Beta public static SyncOnSubscribe createStateless(final Action1> next, final Action0 onUnsubscribe) { Func2, Void> nextFunc = new Func2, Void>() { diff --git a/src/main/java/rx/observers/AssertableSubscriber.java b/src/main/java/rx/observers/AssertableSubscriber.java index 756d3049d0..21180c7eb2 100644 --- a/src/main/java/rx/observers/AssertableSubscriber.java +++ b/src/main/java/rx/observers/AssertableSubscriber.java @@ -19,7 +19,6 @@ import java.util.concurrent.TimeUnit; import rx.*; -import rx.annotations.Experimental; import rx.functions.Action0; /** @@ -30,10 +29,10 @@ *

* This interface extends {@link Observer} and allows injecting onXXX signals into * the testing process. + *

History: 1.2.3 - experimental * @param the value type consumed by this Observer - * @since 1.2.3 + * @since 1.3 */ -@Experimental public interface AssertableSubscriber extends Observer, Subscription { /** diff --git a/src/main/java/rx/observers/AsyncCompletableSubscriber.java b/src/main/java/rx/observers/AsyncCompletableSubscriber.java index 28c346da76..81933b80e6 100644 --- a/src/main/java/rx/observers/AsyncCompletableSubscriber.java +++ b/src/main/java/rx/observers/AsyncCompletableSubscriber.java @@ -19,7 +19,6 @@ import rx.CompletableSubscriber; import rx.Subscription; -import rx.annotations.Experimental; import rx.plugins.RxJavaHooks; /** @@ -54,9 +53,8 @@ * } * } * - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ -@Experimental public abstract class AsyncCompletableSubscriber implements CompletableSubscriber, Subscription { /** * Indicates the unsubscribed state. diff --git a/src/main/java/rx/observers/SafeCompletableSubscriber.java b/src/main/java/rx/observers/SafeCompletableSubscriber.java index bc7b35e858..6f96ecfc0d 100644 --- a/src/main/java/rx/observers/SafeCompletableSubscriber.java +++ b/src/main/java/rx/observers/SafeCompletableSubscriber.java @@ -17,7 +17,6 @@ import rx.CompletableSubscriber; import rx.Subscription; -import rx.annotations.Experimental; import rx.exceptions.*; import rx.plugins.RxJavaHooks; @@ -25,9 +24,8 @@ * Wraps another CompletableSubscriber and handles exceptions thrown * from onError and onCompleted. * - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ -@Experimental public final class SafeCompletableSubscriber implements CompletableSubscriber, Subscription { final CompletableSubscriber actual; diff --git a/src/main/java/rx/observers/TestSubscriber.java b/src/main/java/rx/observers/TestSubscriber.java index bb76878ba6..6553dcb2bf 100644 --- a/src/main/java/rx/observers/TestSubscriber.java +++ b/src/main/java/rx/observers/TestSubscriber.java @@ -20,7 +20,6 @@ import rx.*; import rx.Observer; -import rx.annotations.Experimental; import rx.exceptions.CompositeException; /** @@ -225,9 +224,8 @@ public List> getOnCompletedEvents() { /** * Returns the number of times onCompleted was called on this TestSubscriber. * @return the number of times onCompleted was called on this TestSubscriber. - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final int getCompletions() { return completions; } @@ -356,9 +354,8 @@ private void assertItem(T expected, int i) { * @param unit the time unit of waiting * @return true if the expected number of onNext events happened * @throws RuntimeException if the sleep is interrupted - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final boolean awaitValueCount(int expected, long timeout, TimeUnit unit) { while (timeout != 0 && valueCount < expected) { try { @@ -696,9 +693,8 @@ final void assertionError(String message) { * * @param expectedFirstValue the expected first value * @param expectedRestValues the optional rest values - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public final void assertValuesAndClear(T expectedFirstValue, T... expectedRestValues) { int n = 1 + expectedRestValues.length; assertValueCount(n); diff --git a/src/main/java/rx/plugins/RxJavaCompletableExecutionHook.java b/src/main/java/rx/plugins/RxJavaCompletableExecutionHook.java index c8303ed779..d759d0d021 100644 --- a/src/main/java/rx/plugins/RxJavaCompletableExecutionHook.java +++ b/src/main/java/rx/plugins/RxJavaCompletableExecutionHook.java @@ -16,7 +16,6 @@ package rx.plugins; import rx.*; -import rx.annotations.Experimental; import rx.functions.Func1; /** @@ -35,9 +34,8 @@ * should be fast. If anything time-consuming is to be done it should be spawned asynchronously onto separate * worker threads. * - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ -@Experimental public abstract class RxJavaCompletableExecutionHook { // NOPMD /** * Invoked during the construction by {@link Completable#create(Completable.OnSubscribe)} diff --git a/src/main/java/rx/plugins/RxJavaErrorHandler.java b/src/main/java/rx/plugins/RxJavaErrorHandler.java index 9324cb9062..4c0dfba9d0 100644 --- a/src/main/java/rx/plugins/RxJavaErrorHandler.java +++ b/src/main/java/rx/plugins/RxJavaErrorHandler.java @@ -16,7 +16,6 @@ package rx.plugins; import rx.*; -import rx.annotations.Beta; import rx.exceptions.Exceptions; /** @@ -64,10 +63,8 @@ public void handleError(Throwable e) { * {@code OnErrorThrowable.OnNextValue} * @return a short {@link String} representation of the item if one is known for its type, or null for * default - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the - * release number) + * @since 1.3 */ - @Beta public final String handleOnNextValueRendering(Object item) { try { @@ -95,10 +92,8 @@ public final String handleOnNextValueRendering(Object item) { * @return a short {@link String} representation of the item if one is known for its type, or null for * default * @throws InterruptedException if the rendering thread is interrupted - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the - * release number) + * @since 1.3 */ - @Beta protected String render (Object item) throws InterruptedException { //do nothing by default return null; diff --git a/src/main/java/rx/plugins/RxJavaHooks.java b/src/main/java/rx/plugins/RxJavaHooks.java index 0cac048984..106b9e627f 100644 --- a/src/main/java/rx/plugins/RxJavaHooks.java +++ b/src/main/java/rx/plugins/RxJavaHooks.java @@ -19,7 +19,6 @@ import java.util.concurrent.ScheduledExecutorService; import rx.*; -import rx.annotations.Experimental; import rx.functions.*; import rx.internal.operators.*; @@ -29,8 +28,8 @@ *

* The class features a lockdown state, see {@link #lockdown()} and {@link #isLockdown()}, to * prevent further changes to the hooks. + * @since 1.3 */ -@Experimental public final class RxJavaHooks { /** * Prevents changing the hook callbacks when set to true. diff --git a/src/main/java/rx/plugins/RxJavaPlugins.java b/src/main/java/rx/plugins/RxJavaPlugins.java index 91ba9fa1fa..7a5856d431 100644 --- a/src/main/java/rx/plugins/RxJavaPlugins.java +++ b/src/main/java/rx/plugins/RxJavaPlugins.java @@ -17,7 +17,6 @@ import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import rx.annotations.Experimental; /** * Registry for plugin implementations that allows global override and handles the retrieval of correct @@ -84,9 +83,9 @@ public static RxJavaPlugins getInstance() { * during application runtime and also bad code could invoke it in * the middle of an application life-cycle and really break applications * if not used cautiously. For more detailed discussions: - * * @see Make RxJavaPlugins.reset() public + * @see Make RxJavaPlugins.reset() public + * @since 1.3 */ - @Experimental public void reset() { INSTANCE.errorHandler.set(null); INSTANCE.observableExecutionHook.set(null); @@ -228,9 +227,8 @@ public void registerSingleExecutionHook(RxJavaSingleExecutionHook impl) { * full class name to load. * * @return {@link RxJavaCompletableExecutionHook} implementation to use - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public RxJavaCompletableExecutionHook getCompletableExecutionHook() { if (completableExecutionHook.get() == null) { // check for an implementation from System.getProperty first @@ -256,9 +254,8 @@ public RxJavaCompletableExecutionHook getCompletableExecutionHook() { * @throws IllegalStateException * if called more than once or after the default was initialized (if usage occurs before trying * to register) - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ - @Experimental public void registerCompletableExecutionHook(RxJavaCompletableExecutionHook impl) { if (!completableExecutionHook.compareAndSet(null, impl)) { throw new IllegalStateException("Another strategy was already registered: " + singleExecutionHook.get()); diff --git a/src/main/java/rx/plugins/RxJavaSchedulersHook.java b/src/main/java/rx/plugins/RxJavaSchedulersHook.java index cc1675f322..e65ab1f3bc 100644 --- a/src/main/java/rx/plugins/RxJavaSchedulersHook.java +++ b/src/main/java/rx/plugins/RxJavaSchedulersHook.java @@ -18,7 +18,6 @@ import java.util.concurrent.ThreadFactory; import rx.Scheduler; -import rx.annotations.Experimental; import rx.functions.Action0; import rx.internal.schedulers.CachedThreadScheduler; import rx.internal.schedulers.EventLoopsScheduler; @@ -47,8 +46,8 @@ public class RxJavaSchedulersHook { /** * Create an instance of the default {@link Scheduler} used for {@link Schedulers#computation()}. * @return the created Scheduler instance + * @since 1.3 */ - @Experimental public static Scheduler createComputationScheduler() { return createComputationScheduler(new RxThreadFactory("RxComputationScheduler-")); } @@ -58,8 +57,8 @@ public static Scheduler createComputationScheduler() { * except using {@code threadFactory} for thread creation. * @param threadFactory the factory to use for each worker thread * @return the created Scheduler instance + * @since 1.3 */ - @Experimental public static Scheduler createComputationScheduler(ThreadFactory threadFactory) { if (threadFactory == null) { throw new NullPointerException("threadFactory == null"); @@ -70,8 +69,8 @@ public static Scheduler createComputationScheduler(ThreadFactory threadFactory) /** * Create an instance of the default {@link Scheduler} used for {@link Schedulers#io()}. * @return the created Scheduler instance + * @since 1.3 */ - @Experimental public static Scheduler createIoScheduler() { return createIoScheduler(new RxThreadFactory("RxIoScheduler-")); } @@ -81,8 +80,8 @@ public static Scheduler createIoScheduler() { * except using {@code threadFactory} for thread creation. * @param threadFactory the factory to use for each worker thread * @return the created Scheduler instance + * @since 1.3 */ - @Experimental public static Scheduler createIoScheduler(ThreadFactory threadFactory) { if (threadFactory == null) { throw new NullPointerException("threadFactory == null"); @@ -93,8 +92,8 @@ public static Scheduler createIoScheduler(ThreadFactory threadFactory) { /** * Create an instance of the default {@link Scheduler} used for {@link Schedulers#newThread()}. * @return the created Scheduler instance + * @since 1.3 */ - @Experimental public static Scheduler createNewThreadScheduler() { return createNewThreadScheduler(new RxThreadFactory("RxNewThreadScheduler-")); } @@ -104,8 +103,8 @@ public static Scheduler createNewThreadScheduler() { * except using {@code threadFactory} for thread creation. * @param threadFactory the factory to use for each worker thread * @return the created Scheduler instance + * @since 1.3 */ - @Experimental public static Scheduler createNewThreadScheduler(ThreadFactory threadFactory) { if (threadFactory == null) { throw new NullPointerException("threadFactory == null"); diff --git a/src/main/java/rx/schedulers/Schedulers.java b/src/main/java/rx/schedulers/Schedulers.java index e6435965e5..1327c6ba93 100644 --- a/src/main/java/rx/schedulers/Schedulers.java +++ b/src/main/java/rx/schedulers/Schedulers.java @@ -19,7 +19,6 @@ import java.util.concurrent.atomic.AtomicReference; import rx.Scheduler; -import rx.annotations.Experimental; import rx.internal.schedulers.*; import rx.plugins.*; @@ -185,8 +184,8 @@ public static Scheduler from(Executor executor) { * Resets the current {@link Schedulers} instance. * This will re-init the cached schedulers on the next usage, * which can be useful in testing. + * @since 1.3 */ - @Experimental public static void reset() { Schedulers s = INSTANCE.getAndSet(null); if (s != null) { diff --git a/src/main/java/rx/singles/BlockingSingle.java b/src/main/java/rx/singles/BlockingSingle.java index 470c012cdb..a113f272ba 100644 --- a/src/main/java/rx/singles/BlockingSingle.java +++ b/src/main/java/rx/singles/BlockingSingle.java @@ -20,7 +20,6 @@ import java.util.concurrent.atomic.AtomicReference; import rx.*; -import rx.annotations.*; import rx.exceptions.Exceptions; import rx.internal.operators.BlockingOperatorToFuture; import rx.internal.util.BlockingUtils; @@ -33,9 +32,8 @@ * or {@link Single#toBlocking()}. * * @param the value type of the sequence - * @since (if this graduates from Experimental/Beta to supported, replace this parenthetical with the release number) + * @since 1.3 */ -@Beta public final class BlockingSingle { private final Single single; diff --git a/src/main/java/rx/subjects/UnicastSubject.java b/src/main/java/rx/subjects/UnicastSubject.java index 1c51fe48bb..e7addc5cd8 100644 --- a/src/main/java/rx/subjects/UnicastSubject.java +++ b/src/main/java/rx/subjects/UnicastSubject.java @@ -19,7 +19,6 @@ import java.util.concurrent.atomic.*; import rx.*; -import rx.annotations.Experimental; import rx.exceptions.*; import rx.functions.Action0; import rx.internal.operators.*; @@ -35,8 +34,8 @@ *

* * @param the input and output value type + * @since 1.3 */ -@Experimental public final class UnicastSubject extends Subject { final State state; From daf1022ce86291791817b1ef0f45445445e9a15e Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 5 May 2017 09:49:16 +0200 Subject: [PATCH 47/74] Release 1.3.0 --- CHANGES.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index b02e08b281..6517018463 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,56 @@ # RxJava Releases # +### Version 1.3.0 - May 5, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.0%7C)) + +#### Summary + +Version 1.3.0 is the next minor release of the 1.x series of RxJava containing many formerly experimental API components promoted to standard. Most notably the `Completable` base reactive type is now standard as well. + +Note that the experimental `rx.Observable.fromEmitter()` has been removed in favor for the now also standard `Observable.create(Action1> emitter, Emitter.BackpressureMode backpressure)` + +The planned lifecycle of the 1.x line is as follows: + +Date | Remark +------------|------------------- + **June 1, 2017** | Feature freeze, only bugfixes from this on. + **September 1, 2017** | Release `1.4.0` finalizing the remaining API components. + **March 31, 2018** | End of development. + +The following components have been promoted to standard: + +**Classes, interfaces** + +- **classes**: `AssemblyStackTraceException`, `RxJavaCompletableExecutionHook`, `RxJavaHooks`, `UnicastSubject`, `BlockingSingle`, `Completable`, `AssertableSubscriber`, `AsyncCompletableSubscriber`, `SafeCompletableSubscriber` +- **interfaces**: `Cancellable`, `Emitter`, `SingleEmitter`, `CompletableEmitter`, `CompletableSubscriber`, `BackpressureOverflow.Strategy` + +**Operators** + +- **`Observable`**: `create`, `unsafeCreate`, `to`, `zip(Observable[], FuncN)`, `flatMapCompletable`, `flatMapSingle`, `groupby(Func1, Func1, Func1, Map>)`, `onTerminateDetach`, `rebatchRequests`, `subscribeOn(Scheduler, boolean)`, `sorted`, `withLatestFrom`, `test`, `toCompletable`, `concatDelayError`, `mergeDelayError`, `switchOnNextDelayError`, `using(Func0, Func1, Action1, boolean)`, `concatMapDelayError`, `delaySubscription(Observable)`, `distinctUntilChanged(Func2)`, `concatEager`, `concatMapEager`, `onBackpressureBuffer(long, Action0, BackpressureOverflow.Strategy)`, `switchMapDelayError`, `toSortedList(int)`, `toSortedList(Func2, int)` +- **`Completable`**: `fromEmitter`, `test` +- **`Single`**: `fromEmitter`, `merge`, `mergeDelayError`, `cache`, `to`, `doOnEach`, `doOnSuccess`, `test`, `onErrorResumeNext`, `toCompletable`, `doOnError`, `doOnSubscribe`, `delay`, `defer`, `doOnUnsubscribe`, `doAfterTerminate`, `flatMapCompletable`, `lift`, `toBlocking`, `using`, `delaySubscription(Observable)` +- **`TestSubscriber`**: `getCompletions`, `awaitValueCount`, `assertValuesAndClear` +- **`SyncOnSubscriber`**: `createSingleState`, `createStateful`, `createStateless` + +**Other** + +- `Schedulers.reset` +- `CompositeException(Throwable...)` constructor +- `Exceptions.throwOrReport` (4 overloads) +- `BlockingObservable.subscribe` (6 overloads) +- **`RxJavaSchedulersHook`**: `createComputationScheduler`, `createIoScheduler`, `createNewThreadScheduler` +- **internal**: `AssertableSubscriberObservable`, `FlatMapCompletable`, `FlatMapSingle`, `SchedulerWhen`, `BackpressureDrainManager`, `BlockingUtils`. +- **`RxJavaPlugins`**: `reset`, `getCompletableExecutionHook`, `registerCompletableExecutionHook` +- **`RxJavaErrorHandler`**: `handleOnNextValueRendering`, `render` + +In addition, the class `AsyncOnsubscribe` with its 7 factory methods and `Observable.create(AsyncOnSubscribe)` have been promoted to **beta**. + +#### Acknowledgements + +Thanks to all who contributed to the 1.x line in the past 6 months (in order they appear on the [commit](https://github.com/ReactiveX/RxJava/commits/1.x) page): + +@mtiidla, @dhendry, @mostroverkhov, @yshrsmz, @BraisGabin, @cesar1000, @Jawnnypoo, @chanx2, @abersnaze, @davidmoten, @ortex, @marwinxxii, @ekchang, @pyricau, @JakeWharton, @VictorAlbertos + + ### Version 1.2.10 - April 26, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.2.10%7C)) #### Bugfixes From a5c0cd0359fa2a697435f9c41b76bc0f6d6b1888 Mon Sep 17 00:00:00 2001 From: Michael Burns Date: Mon, 8 May 2017 17:10:26 -0400 Subject: [PATCH 48/74] Add the cast operator to Single. (#5332) * Add the cast operator to Single. Signed-off-by: Mike Burns * Create a separate operator for Single.cast and test it. Signed-off-by: Inferno23 * Update spacing and javadoc. Signed-off-by: Inferno23 * Add missing @Experimental annotation. Signed-off-by: Inferno23 * Fix the copyrights. Signed-off-by: Inferno23 * Remove extra verify call. Signed-off-by: Inferno23 --- src/main/java/rx/Single.java | 17 +++++++ .../operators/SingleOperatorCast.java | 37 ++++++++++++++ .../operators/SingleOperatorCastTest.java | 51 +++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 src/main/java/rx/internal/operators/SingleOperatorCast.java create mode 100644 src/test/java/rx/internal/operators/SingleOperatorCastTest.java diff --git a/src/main/java/rx/Single.java b/src/main/java/rx/Single.java index a9bff5e388..0cf0d5f06f 100644 --- a/src/main/java/rx/Single.java +++ b/src/main/java/rx/Single.java @@ -210,6 +210,23 @@ private static Observable asObservable(Single t) { * ********************************************************************************************************* */ + /** + * Casts the success value of the current Single into the target type or signals a + * ClassCastException if not compatible. + *

+ *
Scheduler:
+ *
{@code cast} does not operate by default on a particular {@link Scheduler}.
+ *
+ * @param the target type + * @param klass the type token to use for casting the success result from the current Single + * @return the new Single instance + * @since 1.3.1 - experimental + */ + @Experimental + public final Single cast(final Class klass) { + return map(new SingleOperatorCast(klass)); + } + /** * Returns an Observable that emits the items emitted by two Singles, one after the other. *

diff --git a/src/main/java/rx/internal/operators/SingleOperatorCast.java b/src/main/java/rx/internal/operators/SingleOperatorCast.java new file mode 100644 index 0000000000..b77381b161 --- /dev/null +++ b/src/main/java/rx/internal/operators/SingleOperatorCast.java @@ -0,0 +1,37 @@ +/** + * 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.internal.operators; + +import rx.functions.Func1; + +/** + * Converts the element of a Single to the specified type. + * @param the input value type + * @param the output value type + */ +public class SingleOperatorCast implements Func1 { + + final Class castClass; + + public SingleOperatorCast(Class castClass) { + this.castClass = castClass; + } + + @Override + public R call(T t) { + return castClass.cast(t); + } +} diff --git a/src/test/java/rx/internal/operators/SingleOperatorCastTest.java b/src/test/java/rx/internal/operators/SingleOperatorCastTest.java new file mode 100644 index 0000000000..48d19045f5 --- /dev/null +++ b/src/test/java/rx/internal/operators/SingleOperatorCastTest.java @@ -0,0 +1,51 @@ +/** + * 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.internal.operators; +; +import org.junit.Test; +import rx.Observer; +import rx.Single; + +import static org.mockito.Mockito.*; + +public class SingleOperatorCastTest { + + @Test + public void testSingleCast() { + Single source = Single.just(1); + Single single = source.cast(Integer.class); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + single.subscribe(observer); + verify(observer, times(1)).onNext(1); + verify(observer, never()).onError( + org.mockito.Matchers.any(Throwable.class)); + verify(observer, times(1)).onCompleted(); + } + + @Test + public void testSingleCastWithWrongType() { + Single source = Single.just(1); + Single single = source.cast(Boolean.class); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + single.subscribe(observer); + verify(observer, times(1)).onError( + org.mockito.Matchers.any(ClassCastException.class)); + } +} From 433b099c2d97cc24a2e7d2041755bbe5a8ddd5a0 Mon Sep 17 00:00:00 2001 From: Dave Moten Date: Thu, 18 May 2017 17:53:34 +1000 Subject: [PATCH 49/74] remove semicolon that Eclipse thinks is compile error (#5353) --- src/test/java/rx/internal/operators/SingleOperatorCastTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/rx/internal/operators/SingleOperatorCastTest.java b/src/test/java/rx/internal/operators/SingleOperatorCastTest.java index 48d19045f5..6d60c8b411 100644 --- a/src/test/java/rx/internal/operators/SingleOperatorCastTest.java +++ b/src/test/java/rx/internal/operators/SingleOperatorCastTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ package rx.internal.operators; -; + import org.junit.Test; import rx.Observer; import rx.Single; From 1dd023f073548f977ea8d199fa2151279078a340 Mon Sep 17 00:00:00 2001 From: yurgis Date: Fri, 23 Jun 2017 02:16:13 -0700 Subject: [PATCH 50/74] fix for https://github.com/ReactiveX/RxJava/issues/5429 (#5430) --- .../java/rx/observables/AsyncOnSubscribe.java | 7 ++-- .../rx/observables/AsyncOnSubscribeTest.java | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/main/java/rx/observables/AsyncOnSubscribe.java b/src/main/java/rx/observables/AsyncOnSubscribe.java index e8d1ff71e6..108c9a4c8e 100644 --- a/src/main/java/rx/observables/AsyncOnSubscribe.java +++ b/src/main/java/rx/observables/AsyncOnSubscribe.java @@ -532,8 +532,11 @@ boolean tryEmit(long n) { onNextCalled = false; expectedDelivery = n; nextIteration(n); - - if (hasTerminated || isUnsubscribed()) { + + //hasTerminated will be true when onCompleted was already emitted from the request callback + //even if the the observer has not seen onCompleted from the requested observable, + //so we should not clean up while there are active subscriptions + if (hasTerminated && !subscriptions.hasSubscriptions() || isUnsubscribed()) { cleanup(); return true; } diff --git a/src/test/java/rx/observables/AsyncOnSubscribeTest.java b/src/test/java/rx/observables/AsyncOnSubscribeTest.java index d344532aae..72afaad285 100644 --- a/src/test/java/rx/observables/AsyncOnSubscribeTest.java +++ b/src/test/java/rx/observables/AsyncOnSubscribeTest.java @@ -483,4 +483,38 @@ public Integer call(Integer state, Long requested, Observer os = Observable.create(AsyncOnSubscribe. createStateful( + new Func0() { + + @Override + public Integer call() { + return 0; + } + + }, + new Func3>, Integer>() { + + @Override + public Integer call(Integer state, Long requested, Observer> emitter) { + if (state == 0) { + emitter.onNext(Observable.range(0,100).delay(1, TimeUnit.SECONDS, scheduler)); + } else { + emitter.onCompleted(); + } + return state + 1; + } + + })); + + TestSubscriber ts = new TestSubscriber(); + os.mergeWith(Observable.just(0)).subscribe(ts); + scheduler.advanceTimeBy(1, TimeUnit.HOURS); + ts.assertCompleted(); + ts.assertValueCount(101); + } + } \ No newline at end of file From 3e5b117fbfd8ef5fecc7869b84e7f6c794b1d399 Mon Sep 17 00:00:00 2001 From: Matt Laux Date: Sat, 24 Jun 2017 07:34:48 -0400 Subject: [PATCH 51/74] 1.x: TestSubscriber::assertValuesAndClear should reset valueCount (#5437) --- src/main/java/rx/observers/TestSubscriber.java | 1 + .../java/rx/observers/AssertableSubscriberTest.java | 2 +- src/test/java/rx/observers/TestSubscriberTest.java | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/rx/observers/TestSubscriber.java b/src/main/java/rx/observers/TestSubscriber.java index 6553dcb2bf..d35602f572 100644 --- a/src/main/java/rx/observers/TestSubscriber.java +++ b/src/main/java/rx/observers/TestSubscriber.java @@ -703,5 +703,6 @@ public final void assertValuesAndClear(T expectedFirstValue, T... expectedRestVa assertItem(expectedRestValues[i], i + 1); } values.clear(); + valueCount = 0; } } diff --git a/src/test/java/rx/observers/AssertableSubscriberTest.java b/src/test/java/rx/observers/AssertableSubscriberTest.java index 838f57d6ec..4c6adbb06d 100644 --- a/src/test/java/rx/observers/AssertableSubscriberTest.java +++ b/src/test/java/rx/observers/AssertableSubscriberTest.java @@ -151,7 +151,7 @@ public void testSingle() { assertEquals(Thread.currentThread().getName(), ts.getLastSeenThread().getName()); assertTrue(ts.getOnErrorEvents().isEmpty()); assertTrue(ts.getOnNextEvents().isEmpty()); - assertEquals(1, ts.getValueCount()); + assertEquals(0, ts.getValueCount()); } @Test diff --git a/src/test/java/rx/observers/TestSubscriberTest.java b/src/test/java/rx/observers/TestSubscriberTest.java index 5e2c8edc07..a78890aa74 100644 --- a/src/test/java/rx/observers/TestSubscriberTest.java +++ b/src/test/java/rx/observers/TestSubscriberTest.java @@ -815,4 +815,15 @@ public void assertAndConsume() { ts.assertNoValues(); } + + @Test + public void assertAndClearResetsValueCount() { + TestSubscriber ts = TestSubscriber.create(); + + ts.onNext(1); + ts.assertValuesAndClear(1); + + ts.assertNoValues(); + Assert.assertEquals(0, ts.getValueCount()); + } } From b8f3cedefb350091d3daf53aa3dfabe2da5ae17d Mon Sep 17 00:00:00 2001 From: Gene Taylor Date: Thu, 6 Jul 2017 19:54:00 +1000 Subject: [PATCH 52/74] fix #5468: eager hooks onError call (#5470) * fix #5468: eager hooks onError call Move the call to RxJavaHooks into the catch block, so we only report it if the underlying subscriber throws in its onError method. This brings the behaviour in line with that of SafeSubscriber, which only call Hooks.onError inside the catch * #5468 move hooks OnError into correct if block --- src/main/java/rx/observers/SafeCompletableSubscriber.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/rx/observers/SafeCompletableSubscriber.java b/src/main/java/rx/observers/SafeCompletableSubscriber.java index 6f96ecfc0d..7430fa371a 100644 --- a/src/main/java/rx/observers/SafeCompletableSubscriber.java +++ b/src/main/java/rx/observers/SafeCompletableSubscriber.java @@ -54,8 +54,8 @@ public void onCompleted() { @Override public void onError(Throwable e) { - RxJavaHooks.onError(e); if (done) { + RxJavaHooks.onError(e); return; } done = true; From 8e925345814c291e2ab2f10f4986f1ac9b8ee68a Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 6 Jul 2017 22:23:10 +0200 Subject: [PATCH 53/74] 1.x: increase timeout of some tests (#5471) * 1.x: increase timeout of some tests * OperatorFlatMapTest.flatMapRangeMixedAsyncLoop more time * Retry testNoBufferingOrBlockingOfSequence multiple times --- src/main/java/rx/SingleEmitter.java | 2 +- .../java/rx/observables/AsyncOnSubscribe.java | 6 +- .../operators/BlockingOperatorNextTest.java | 105 ++++++++++-------- .../operators/CompletableOnErrorXTest.java | 4 +- .../operators/OperatorFlatMapTest.java | 2 +- .../OperatorMergeMaxConcurrentTest.java | 6 +- .../operators/OperatorSwitchTest.java | 2 +- 7 files changed, 69 insertions(+), 58 deletions(-) diff --git a/src/main/java/rx/SingleEmitter.java b/src/main/java/rx/SingleEmitter.java index a60d0840a5..53d034a076 100644 --- a/src/main/java/rx/SingleEmitter.java +++ b/src/main/java/rx/SingleEmitter.java @@ -23,7 +23,7 @@ *

* All methods are thread-safe; calling onSuccess or onError twice or one after the other has * no effect. - *

History: 1.2.3 - experimental + *

History: 1.2.3 - experimental * @param the success value type * @since 1.3 */ diff --git a/src/main/java/rx/observables/AsyncOnSubscribe.java b/src/main/java/rx/observables/AsyncOnSubscribe.java index 108c9a4c8e..7a1eef7112 100644 --- a/src/main/java/rx/observables/AsyncOnSubscribe.java +++ b/src/main/java/rx/observables/AsyncOnSubscribe.java @@ -532,9 +532,9 @@ boolean tryEmit(long n) { onNextCalled = false; expectedDelivery = n; nextIteration(n); - - //hasTerminated will be true when onCompleted was already emitted from the request callback - //even if the the observer has not seen onCompleted from the requested observable, + + //hasTerminated will be true when onCompleted was already emitted from the request callback + //even if the the observer has not seen onCompleted from the requested observable, //so we should not clean up while there are active subscriptions if (hasTerminated && !subscriptions.hasSubscriptions() || isUnsubscribed()) { cleanup(); diff --git a/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java b/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java index 4cff913cea..69541f712b 100644 --- a/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java +++ b/src/test/java/rx/internal/operators/BlockingOperatorNextTest.java @@ -234,69 +234,80 @@ public void testNextWithCallingHasNextMultipleTimes() { */ @Test public void testNoBufferingOrBlockingOfSequence() throws Throwable { - final CountDownLatch finished = new CountDownLatch(1); - final int COUNT = 30; - final CountDownLatch timeHasPassed = new CountDownLatch(COUNT); - final AtomicBoolean running = new AtomicBoolean(true); - final AtomicInteger count = new AtomicInteger(0); - final Observable obs = Observable.unsafeCreate(new Observable.OnSubscribe() { + int retries = 10; - @Override - public void call(final Subscriber o) { - new Thread(new Runnable() { + for (;;) { + try { + final CountDownLatch finished = new CountDownLatch(1); + final int COUNT = 30; + final CountDownLatch timeHasPassed = new CountDownLatch(COUNT); + final AtomicBoolean running = new AtomicBoolean(true); + final AtomicInteger count = new AtomicInteger(0); + final Observable obs = Observable.unsafeCreate(new Observable.OnSubscribe() { @Override - public void run() { - try { - while (running.get()) { - o.onNext(count.incrementAndGet()); - timeHasPassed.countDown(); + public void call(final Subscriber o) { + new Thread(new Runnable() { + + @Override + public void run() { + try { + while (running.get()) { + o.onNext(count.incrementAndGet()); + timeHasPassed.countDown(); + } + o.onCompleted(); + } catch (Throwable e) { + o.onError(e); + } finally { + finished.countDown(); + } } - o.onCompleted(); - } catch (Throwable e) { - o.onError(e); - } finally { - finished.countDown(); - } + }).start(); } - }).start(); - } - }); + }); - try { - Iterator it = next(obs).iterator(); + try { + Iterator it = next(obs).iterator(); - assertTrue(it.hasNext()); - int a = it.next(); - assertTrue(it.hasNext()); - int b = it.next(); - // we should have a different value - assertTrue("a and b should be different", a != b); + assertTrue(it.hasNext()); + int a = it.next(); + assertTrue(it.hasNext()); + int b = it.next(); + // we should have a different value + assertTrue("a and b should be different", a != b); - // wait for some time (if times out we are blocked somewhere so fail ... set very high for very slow, constrained machines) - timeHasPassed.await(8000, TimeUnit.MILLISECONDS); + // wait for some time (if times out we are blocked somewhere so fail ... set very high for very slow, constrained machines) + timeHasPassed.await(8000, TimeUnit.MILLISECONDS); - assertTrue(it.hasNext()); - int c = it.next(); + assertTrue(it.hasNext()); + int c = it.next(); - assertTrue("c should not just be the next in sequence", c != (b + 1)); - assertTrue("expected that c [" + c + "] is higher than or equal to " + COUNT, c >= COUNT); + assertTrue("c should not just be the next in sequence", c != (b + 1)); + assertTrue("expected that c [" + c + "] is higher than or equal to " + COUNT, c >= COUNT); - assertTrue(it.hasNext()); - int d = it.next(); - assertTrue(d > c); + assertTrue(it.hasNext()); + int d = it.next(); + assertTrue(d > c); - // shut down the thread - running.set(false); + // shut down the thread + running.set(false); - finished.await(); + finished.await(); - assertFalse(it.hasNext()); + assertFalse(it.hasNext()); - System.out.println("a: " + a + " b: " + b + " c: " + c); - } finally { - running.set(false); // don't let the thread spin indefinitely + System.out.println("a: " + a + " b: " + b + " c: " + c); + } finally { + running.set(false); // don't let the thread spin indefinitely + } + return; + } catch (AssertionError ex) { + if (retries-- == 0) { + throw ex; + } + } } } diff --git a/src/test/java/rx/internal/operators/CompletableOnErrorXTest.java b/src/test/java/rx/internal/operators/CompletableOnErrorXTest.java index c462352af3..31cbff9df1 100644 --- a/src/test/java/rx/internal/operators/CompletableOnErrorXTest.java +++ b/src/test/java/rx/internal/operators/CompletableOnErrorXTest.java @@ -29,7 +29,7 @@ public class CompletableOnErrorXTest { @Test public void nextUnsubscribe() { PublishSubject ps = PublishSubject.create(); - + AssertableSubscriber as = ps.toCompletable() .onErrorResumeNext(new Func1() { @Override @@ -49,7 +49,7 @@ public Completable call(Throwable e) { @Test public void completeUnsubscribe() { PublishSubject ps = PublishSubject.create(); - + AssertableSubscriber as = ps.toCompletable() .onErrorComplete() .test(); diff --git a/src/test/java/rx/internal/operators/OperatorFlatMapTest.java b/src/test/java/rx/internal/operators/OperatorFlatMapTest.java index 61805d7372..286a2a03bc 100644 --- a/src/test/java/rx/internal/operators/OperatorFlatMapTest.java +++ b/src/test/java/rx/internal/operators/OperatorFlatMapTest.java @@ -468,7 +468,7 @@ public Observable call(Integer t) { } } } - @Test(timeout = 30000) + @Test(timeout = 60000) public void flatMapRangeMixedAsyncLoop() { for (int i = 0; i < 2000; i++) { if (i % 10 == 0) { diff --git a/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java b/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java index 21ce364b34..5be03a3b6f 100644 --- a/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java +++ b/src/test/java/rx/internal/operators/OperatorMergeMaxConcurrentTest.java @@ -197,7 +197,7 @@ public void testSimpleAsyncLoop() { testSimpleAsync(); } } - @Test(timeout = 10000) + @Test(timeout = 30000) public void testSimpleAsync() { for (int i = 1; i < 50; i++) { TestSubscriber ts = new TestSubscriber(); @@ -217,7 +217,7 @@ public void testSimpleAsync() { assertEquals(expected, actual); } } - @Test(timeout = 10000) + @Test(timeout = 30000) public void testSimpleOneLessAsyncLoop() { int max = 200; if (PlatformDependent.isAndroid()) { @@ -227,7 +227,7 @@ public void testSimpleOneLessAsyncLoop() { testSimpleOneLessAsync(); } } - @Test(timeout = 10000) + @Test(timeout = 30000) public void testSimpleOneLessAsync() { long t = System.currentTimeMillis(); for (int i = 2; i < 50; i++) { diff --git a/src/test/java/rx/internal/operators/OperatorSwitchTest.java b/src/test/java/rx/internal/operators/OperatorSwitchTest.java index 8525c18cd6..00887db5e1 100644 --- a/src/test/java/rx/internal/operators/OperatorSwitchTest.java +++ b/src/test/java/rx/internal/operators/OperatorSwitchTest.java @@ -894,7 +894,7 @@ public void asyncInner() throws Throwable { .switchMap(UtilityFunctions.>identity()) .observeOn(Schedulers.computation()) .ignoreElements() - .timeout(5, TimeUnit.SECONDS) + .timeout(15, TimeUnit.SECONDS) .toBlocking() .subscribe(Actions.empty(), new Action1() { @Override From 85350bf1465416fbc23a54f465e9b75cb71fd361 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sun, 10 Sep 2017 18:19:29 +0200 Subject: [PATCH 54/74] Update CHANGES.md --- CHANGES.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 6517018463..373c3665c9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,18 @@ # RxJava Releases # +### Version 1.3.1 - September 10, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.1%7C)) + +#### API changes +*Remark: submitted & merged before the feature freeze of June 1st.* + +- [Pull 5332](https://github.com/ReactiveX/RxJava/pull/5332): Add the `cast` operator to `Single`. + +#### Bugfixes + +- [Pull 5430](https://github.com/ReactiveX/RxJava/pull/5430): Fix premature cleanup in `AsyncOnSubscribe` when the last `Observable` is still running. +- [Pull 5437](https://github.com/ReactiveX/RxJava/pull/5437): `TestSubscriber::assertValuesAndClear` should reset `valueCount`. +- [Pull 5470](https://github.com/ReactiveX/RxJava/pull/5470): Fix eager call to `RxJavHooks.onError` in `SafeCompletableSuscriber`. + ### Version 1.3.0 - May 5, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.0%7C)) #### Summary From ed35a14b8b8c5899f292e60905e082563d516539 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sun, 10 Sep 2017 18:21:42 +0200 Subject: [PATCH 55/74] Use oraclejdk8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f07cf8d5e4..751937fa52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: java jdk: -- oraclejdk7 +- oraclejdk8 sudo: false # as per http://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/ From 50ea46a344485df787d938a954cf871f36abc44a Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 15 Sep 2017 09:27:06 +0200 Subject: [PATCH 56/74] 1.x: Workaround for CHM.keySet bad type with Java 8 compiler (#5602) --- src/main/java/rx/internal/schedulers/NewThreadWorker.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/rx/internal/schedulers/NewThreadWorker.java b/src/main/java/rx/internal/schedulers/NewThreadWorker.java index dd63eddf9a..23f8af90e2 100644 --- a/src/main/java/rx/internal/schedulers/NewThreadWorker.java +++ b/src/main/java/rx/internal/schedulers/NewThreadWorker.java @@ -16,7 +16,7 @@ package rx.internal.schedulers; import java.lang.reflect.*; -import java.util.Iterator; +import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; @@ -110,10 +110,12 @@ public static void deregisterExecutor(ScheduledExecutorService service) { } /** Purges each registered executor and eagerly evicts shutdown executors. */ - @SuppressAnimalSniffer // CHM.keySet returns KeySetView in Java 8+; false positive here static void purgeExecutors() { try { - Iterator it = EXECUTORS.keySet().iterator(); + // This prevents map.keySet to compile to a Java 8+ KeySetView return type + // and cause NoSuchMethodError on Java 6-7 runtimes. + Map map = EXECUTORS; + Iterator it = map.keySet().iterator(); while (it.hasNext()) { ScheduledThreadPoolExecutor exec = it.next(); if (!exec.isShutdown()) { From 81542cdc4278c8d4509a66441976d908a2197ea5 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 15 Sep 2017 09:35:00 +0200 Subject: [PATCH 57/74] Release 1.3.2 --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 373c3665c9..3a834830b7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # RxJava Releases # +### Version 1.3.2 - September 15, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.2%7C)) + +#### Bugfixes + +- [Pull 5602](https://github.com/ReactiveX/RxJava/pull/5602): Workaround for CHM.keySet bad type with Java 8 compiler + ### Version 1.3.1 - September 10, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.1%7C)) #### API changes From 0660284a9ba53e755c04c407c1dcdd5d4c7fd85b Mon Sep 17 00:00:00 2001 From: David Karnok Date: Fri, 13 Oct 2017 21:11:12 +0200 Subject: [PATCH 58/74] 1.x: fix timeout (timed, selector) unsubscribe bug (#5660) * 1.x: fix timeout(time, [fallback]) unsubscribe bug * Fix timeout(selector) variant. --- src/main/java/rx/Observable.java | 6 +- ...nSubscribeTimeoutSelectorWithFallback.java | 247 ++++++++++++++++++ .../OnSubscribeTimeoutTimedWithFallback.java | 227 ++++++++++++++++ .../internal/operators/OperatorTimeout.java | 58 ---- .../operators/OperatorTimeoutBase.java | 206 --------------- .../OperatorTimeoutWithSelector.java | 111 -------- .../operators/OperatorTimeoutTests.java | 78 +++++- .../OperatorTimeoutWithSelectorTest.java | 178 ++++++++++++- 8 files changed, 726 insertions(+), 385 deletions(-) create mode 100644 src/main/java/rx/internal/operators/OnSubscribeTimeoutSelectorWithFallback.java create mode 100644 src/main/java/rx/internal/operators/OnSubscribeTimeoutTimedWithFallback.java delete mode 100644 src/main/java/rx/internal/operators/OperatorTimeout.java delete mode 100644 src/main/java/rx/internal/operators/OperatorTimeoutBase.java delete mode 100644 src/main/java/rx/internal/operators/OperatorTimeoutWithSelector.java diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 6c4b599bb6..4b3d7802b4 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -11284,11 +11284,13 @@ public final Observable timeout(Func0> firstTi * if {@code timeoutSelector} is null * @see ReactiveX operators documentation: Timeout */ + @SuppressWarnings("unchecked") public final Observable timeout(Func0> firstTimeoutSelector, Func1> timeoutSelector, Observable other) { if (timeoutSelector == null) { throw new NullPointerException("timeoutSelector is null"); } - return lift(new OperatorTimeoutWithSelector(firstTimeoutSelector, timeoutSelector, other)); + return unsafeCreate(new OnSubscribeTimeoutSelectorWithFallback(this, + firstTimeoutSelector != null ? defer((Func0>)firstTimeoutSelector) : null, timeoutSelector, other)); } /** @@ -11443,7 +11445,7 @@ public final Observable timeout(long timeout, TimeUnit timeUnit, ObservableReactiveX operators documentation: Timeout */ public final Observable timeout(long timeout, TimeUnit timeUnit, Observable other, Scheduler scheduler) { - return lift(new OperatorTimeout(timeout, timeUnit, other, scheduler)); + return unsafeCreate(new OnSubscribeTimeoutTimedWithFallback(this, timeout, timeUnit, scheduler, other)); } /** diff --git a/src/main/java/rx/internal/operators/OnSubscribeTimeoutSelectorWithFallback.java b/src/main/java/rx/internal/operators/OnSubscribeTimeoutSelectorWithFallback.java new file mode 100644 index 0000000000..75d75777c8 --- /dev/null +++ b/src/main/java/rx/internal/operators/OnSubscribeTimeoutSelectorWithFallback.java @@ -0,0 +1,247 @@ +/** + * 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.internal.operators; + +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicLong; + +import rx.*; +import rx.exceptions.Exceptions; +import rx.functions.Func1; +import rx.internal.operators.OnSubscribeTimeoutTimedWithFallback.FallbackSubscriber; +import rx.internal.producers.ProducerArbiter; +import rx.internal.subscriptions.SequentialSubscription; +import rx.plugins.RxJavaHooks; + +/** + * Switches to the fallback Observable if: the first upstream item doesn't arrive before + * the first timeout Observable signals an item or completes; or the Observable generated from + * the previous upstream item signals its item or completes before the upstream signals the next item + * of its own. + * + * @param the input and output value type + * @param the value type of the first timeout Observable + * @param the value type of the item-based timeout Observable + * + * @since 1.3.3 + */ +public final class OnSubscribeTimeoutSelectorWithFallback implements Observable.OnSubscribe { + + final Observable source; + + final Observable firstTimeoutIndicator; + + final Func1> itemTimeoutIndicator; + + final Observable fallback; + + public OnSubscribeTimeoutSelectorWithFallback(Observable source, + Observable firstTimeoutIndicator, + Func1> itemTimeoutIndicator, + Observable fallback) { + this.source = source; + this.firstTimeoutIndicator = firstTimeoutIndicator; + this.itemTimeoutIndicator = itemTimeoutIndicator; + this.fallback = fallback; + } + + @Override + public void call(Subscriber t) { + TimeoutMainSubscriber parent = new TimeoutMainSubscriber(t, itemTimeoutIndicator, fallback); + t.add(parent.upstream); + t.setProducer(parent.arbiter); + parent.startFirst(firstTimeoutIndicator); + source.subscribe(parent); + } + + static final class TimeoutMainSubscriber extends Subscriber { + + final Subscriber actual; + + final Func1> itemTimeoutIndicator; + + final Observable fallback; + + final ProducerArbiter arbiter; + + final AtomicLong index; + + final SequentialSubscription task; + + final SequentialSubscription upstream; + + long consumed; + + TimeoutMainSubscriber(Subscriber actual, + Func1> itemTimeoutIndicator, + Observable fallback) { + this.actual = actual; + this.itemTimeoutIndicator = itemTimeoutIndicator; + this.fallback = fallback; + this.arbiter = new ProducerArbiter(); + this.index = new AtomicLong(); + this.task = new SequentialSubscription(); + this.upstream = new SequentialSubscription(this); + this.add(task); + } + + + @Override + public void onNext(T t) { + long idx = index.get(); + if (idx == Long.MAX_VALUE || !index.compareAndSet(idx, idx + 1)) { + return; + } + + Subscription s = task.get(); + if (s != null) { + s.unsubscribe(); + } + + actual.onNext(t); + + consumed++; + + Observable timeoutObservable; + + try { + timeoutObservable = itemTimeoutIndicator.call(t); + if (timeoutObservable == null) { + throw new NullPointerException("The itemTimeoutIndicator returned a null Observable"); + } + } catch (Throwable ex) { + Exceptions.throwIfFatal(ex); + unsubscribe(); + index.getAndSet(Long.MAX_VALUE); + actual.onError(ex); + return; + } + + TimeoutConsumer tc = new TimeoutConsumer(idx + 1); + if (task.replace(tc)) { + timeoutObservable.subscribe(tc); + } + + } + + void startFirst(Observable firstTimeoutIndicator) { + if (firstTimeoutIndicator != null) { + TimeoutConsumer tc = new TimeoutConsumer(0L); + if (task.replace(tc)) { + firstTimeoutIndicator.subscribe(tc); + } + } + } + + @Override + public void onError(Throwable e) { + if (index.getAndSet(Long.MAX_VALUE) != Long.MAX_VALUE) { + task.unsubscribe(); + + actual.onError(e); + } else { + RxJavaHooks.onError(e); + } + } + + @Override + public void onCompleted() { + if (index.getAndSet(Long.MAX_VALUE) != Long.MAX_VALUE) { + task.unsubscribe(); + + actual.onCompleted(); + } + } + + @Override + public void setProducer(Producer p) { + arbiter.setProducer(p); + } + + void onTimeout(long idx) { + if (!index.compareAndSet(idx, Long.MAX_VALUE)) { + return; + } + + unsubscribe(); + + if (fallback == null) { + actual.onError(new TimeoutException()); + } else { + long c = consumed; + if (c != 0L) { + arbiter.produced(c); + } + + FallbackSubscriber fallbackSubscriber = new FallbackSubscriber(actual, arbiter); + + if (upstream.replace(fallbackSubscriber)) { + fallback.subscribe(fallbackSubscriber); + } + } + } + + void onTimeoutError(long idx, Throwable ex) { + if (index.compareAndSet(idx, Long.MAX_VALUE)) { + unsubscribe(); + + actual.onError(ex); + } else { + RxJavaHooks.onError(ex); + } + + } + + final class TimeoutConsumer extends Subscriber { + + final long idx; + + boolean done; + + TimeoutConsumer(long idx) { + this.idx = idx; + } + + @Override + public void onNext(Object t) { + if (!done) { + done = true; + unsubscribe(); + onTimeout(idx); + } + } + + @Override + public void onError(Throwable e) { + if (!done) { + done = true; + onTimeoutError(idx, e); + } else { + RxJavaHooks.onError(e); + } + } + + @Override + public void onCompleted() { + if (!done) { + done = true; + onTimeout(idx); + } + } + } + } +} diff --git a/src/main/java/rx/internal/operators/OnSubscribeTimeoutTimedWithFallback.java b/src/main/java/rx/internal/operators/OnSubscribeTimeoutTimedWithFallback.java new file mode 100644 index 0000000000..e70c57d667 --- /dev/null +++ b/src/main/java/rx/internal/operators/OnSubscribeTimeoutTimedWithFallback.java @@ -0,0 +1,227 @@ +/** + * 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.internal.operators; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; + +import rx.*; +import rx.Scheduler.Worker; +import rx.functions.Action0; +import rx.internal.producers.ProducerArbiter; +import rx.internal.subscriptions.SequentialSubscription; +import rx.plugins.RxJavaHooks; + +/** + * Switches to consuming a fallback Observable if the main source doesn't signal an onNext event + * within the given time frame after subscription or the previous onNext event. + * + * @param the value type + * @since 1.3.3 + */ +public final class OnSubscribeTimeoutTimedWithFallback implements Observable.OnSubscribe { + + final Observable source; + + final long timeout; + + final TimeUnit unit; + + final Scheduler scheduler; + + final Observable fallback; + + public OnSubscribeTimeoutTimedWithFallback(Observable source, long timeout, + TimeUnit unit, Scheduler scheduler, + Observable fallback) { + this.source = source; + this.timeout = timeout; + this.unit = unit; + this.scheduler = scheduler; + this.fallback = fallback; + } + + @Override + public void call(Subscriber t) { + TimeoutMainSubscriber parent = new TimeoutMainSubscriber(t, timeout, unit, scheduler.createWorker(), fallback); + t.add(parent.upstream); + t.setProducer(parent.arbiter); + parent.startTimeout(0L); + source.subscribe(parent); + } + + static final class TimeoutMainSubscriber extends Subscriber { + + final Subscriber actual; + + final long timeout; + + final TimeUnit unit; + + final Worker worker; + + final Observable fallback; + + final ProducerArbiter arbiter; + + final AtomicLong index; + + final SequentialSubscription task; + + final SequentialSubscription upstream; + + long consumed; + + TimeoutMainSubscriber(Subscriber actual, long timeout, + TimeUnit unit, Worker worker, + Observable fallback) { + this.actual = actual; + this.timeout = timeout; + this.unit = unit; + this.worker = worker; + this.fallback = fallback; + this.arbiter = new ProducerArbiter(); + this.index = new AtomicLong(); + this.task = new SequentialSubscription(); + this.upstream = new SequentialSubscription(this); + this.add(worker); + this.add(task); + } + + + @Override + public void onNext(T t) { + long idx = index.get(); + if (idx == Long.MAX_VALUE || !index.compareAndSet(idx, idx + 1)) { + return; + } + + Subscription s = task.get(); + if (s != null) { + s.unsubscribe(); + } + + consumed++; + + actual.onNext(t); + + startTimeout(idx + 1); + } + + void startTimeout(long nextIdx) { + task.replace(worker.schedule(new TimeoutTask(nextIdx), timeout, unit)); + } + + @Override + public void onError(Throwable e) { + if (index.getAndSet(Long.MAX_VALUE) != Long.MAX_VALUE) { + task.unsubscribe(); + + actual.onError(e); + + worker.unsubscribe(); + } else { + RxJavaHooks.onError(e); + } + } + + @Override + public void onCompleted() { + if (index.getAndSet(Long.MAX_VALUE) != Long.MAX_VALUE) { + task.unsubscribe(); + + actual.onCompleted(); + + worker.unsubscribe(); + } + } + + @Override + public void setProducer(Producer p) { + arbiter.setProducer(p); + } + + void onTimeout(long idx) { + if (!index.compareAndSet(idx, Long.MAX_VALUE)) { + return; + } + + unsubscribe(); + + if (fallback == null) { + actual.onError(new TimeoutException()); + } else { + long c = consumed; + if (c != 0L) { + arbiter.produced(c); + } + + FallbackSubscriber fallbackSubscriber = new FallbackSubscriber(actual, arbiter); + + if (upstream.replace(fallbackSubscriber)) { + fallback.subscribe(fallbackSubscriber); + } + } + } + + final class TimeoutTask implements Action0 { + + final long idx; + + TimeoutTask(long idx) { + this.idx = idx; + } + + @Override + public void call() { + onTimeout(idx); + } + } + } + + static final class FallbackSubscriber extends Subscriber { + + final Subscriber actual; + + final ProducerArbiter arbiter; + + FallbackSubscriber(Subscriber actual, ProducerArbiter arbiter) { + this.actual = actual; + this.arbiter = arbiter; + } + + @Override + public void onNext(T t) { + actual.onNext(t); + } + + @Override + public void onError(Throwable e) { + actual.onError(e); + } + + @Override + public void onCompleted() { + actual.onCompleted(); + } + + @Override + public void setProducer(Producer p) { + arbiter.setProducer(p); + } + } +} diff --git a/src/main/java/rx/internal/operators/OperatorTimeout.java b/src/main/java/rx/internal/operators/OperatorTimeout.java deleted file mode 100644 index 3c74663e80..0000000000 --- a/src/main/java/rx/internal/operators/OperatorTimeout.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * 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.internal.operators; - -import java.util.concurrent.TimeUnit; - -import rx.*; -import rx.functions.Action0; - -/** - * Applies a timeout policy for each element in the observable sequence, using - * the specified scheduler to run timeout timers. If the next element isn't - * received within the specified timeout duration starting from its predecessor, - * the other observable sequence is used to produce future messages from that - * point on. - * @param the value type - */ -public final class OperatorTimeout extends OperatorTimeoutBase { - - public OperatorTimeout(final long timeout, final TimeUnit timeUnit, Observable other, Scheduler scheduler) { - super(new FirstTimeoutStub() { - - @Override - public Subscription call(final TimeoutSubscriber timeoutSubscriber, final Long seqId, Scheduler.Worker inner) { - return inner.schedule(new Action0() { - @Override - public void call() { - timeoutSubscriber.onTimeout(seqId); - } - }, timeout, timeUnit); - } - }, new TimeoutStub() { - - @Override - public Subscription call(final TimeoutSubscriber timeoutSubscriber, final Long seqId, T value, Scheduler.Worker inner) { - return inner.schedule(new Action0() { - @Override - public void call() { - timeoutSubscriber.onTimeout(seqId); - } - }, timeout, timeUnit); - } - }, other, scheduler); - } -} diff --git a/src/main/java/rx/internal/operators/OperatorTimeoutBase.java b/src/main/java/rx/internal/operators/OperatorTimeoutBase.java deleted file mode 100644 index 435a60e503..0000000000 --- a/src/main/java/rx/internal/operators/OperatorTimeoutBase.java +++ /dev/null @@ -1,206 +0,0 @@ -/** - * 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.internal.operators; - -import java.util.concurrent.TimeoutException; - -import rx.*; -import rx.Observable.Operator; -import rx.functions.*; -import rx.internal.producers.ProducerArbiter; -import rx.observers.SerializedSubscriber; -import rx.subscriptions.SerialSubscription; - -class OperatorTimeoutBase implements Operator { - final FirstTimeoutStub firstTimeoutStub; - final TimeoutStub timeoutStub; - final Observable other; - final Scheduler scheduler; - - /** - * Set up the timeout action on the first value. - * - * @param - */ - /* package-private */interface FirstTimeoutStub extends - Func3, Long, Scheduler.Worker, Subscription> { - } - - /** - * Set up the timeout action based on every value - * - * @param - */ - /* package-private */interface TimeoutStub extends - Func4, Long, T, Scheduler.Worker, Subscription> { - } - - /* package-private */OperatorTimeoutBase(FirstTimeoutStub firstTimeoutStub, TimeoutStub timeoutStub, Observable other, Scheduler scheduler) { - this.firstTimeoutStub = firstTimeoutStub; - this.timeoutStub = timeoutStub; - this.other = other; - this.scheduler = scheduler; - } - - @Override - public Subscriber call(Subscriber subscriber) { - Scheduler.Worker inner = scheduler.createWorker(); - subscriber.add(inner); - // Use SynchronizedSubscriber for safe memory access - // as the subscriber will be accessed in the current thread or the - // scheduler or other Observables. - final SerializedSubscriber synchronizedSubscriber = new SerializedSubscriber(subscriber); - - final SerialSubscription serial = new SerialSubscription(); - synchronizedSubscriber.add(serial); - - TimeoutSubscriber timeoutSubscriber = new TimeoutSubscriber(synchronizedSubscriber, timeoutStub, serial, other, inner); - - synchronizedSubscriber.add(timeoutSubscriber); - synchronizedSubscriber.setProducer(timeoutSubscriber.arbiter); - - serial.set(firstTimeoutStub.call(timeoutSubscriber, 0L, inner)); - - return timeoutSubscriber; - } - - /* package-private */static final class TimeoutSubscriber extends - Subscriber { - - final SerialSubscription serial; - - final SerializedSubscriber serializedSubscriber; - - final TimeoutStub timeoutStub; - - final Observable other; - - final Scheduler.Worker inner; - - final ProducerArbiter arbiter; - - /** Guarded by this. */ - boolean terminated; - /** Guarded by this. */ - long actual; - - TimeoutSubscriber( - SerializedSubscriber serializedSubscriber, - TimeoutStub timeoutStub, SerialSubscription serial, - Observable other, - Scheduler.Worker inner) { - this.serializedSubscriber = serializedSubscriber; - this.timeoutStub = timeoutStub; - this.serial = serial; - this.other = other; - this.inner = inner; - this.arbiter = new ProducerArbiter(); - } - - @Override - public void setProducer(Producer p) { - arbiter.setProducer(p); - } - - @Override - public void onNext(T value) { - boolean onNextWins = false; - long a; - synchronized (this) { - if (!terminated) { - a = ++actual; - onNextWins = true; - } else { - a = actual; - } - } - if (onNextWins) { - serializedSubscriber.onNext(value); - serial.set(timeoutStub.call(this, a, value, inner)); - } - } - - @Override - public void onError(Throwable error) { - boolean onErrorWins = false; - synchronized (this) { - if (!terminated) { - terminated = true; - onErrorWins = true; - } - } - if (onErrorWins) { - serial.unsubscribe(); - serializedSubscriber.onError(error); - } - } - - @Override - public void onCompleted() { - boolean onCompletedWins = false; - synchronized (this) { - if (!terminated) { - terminated = true; - onCompletedWins = true; - } - } - if (onCompletedWins) { - serial.unsubscribe(); - serializedSubscriber.onCompleted(); - } - } - - public void onTimeout(long seqId) { - long expected = seqId; - boolean timeoutWins = false; - synchronized (this) { - if (expected == actual && !terminated) { - terminated = true; - timeoutWins = true; - } - } - if (timeoutWins) { - if (other == null) { - serializedSubscriber.onError(new TimeoutException()); - } else { - Subscriber second = new Subscriber() { - @Override - public void onNext(T t) { - serializedSubscriber.onNext(t); - } - - @Override - public void onError(Throwable e) { - serializedSubscriber.onError(e); - } - - @Override - public void onCompleted() { - serializedSubscriber.onCompleted(); - } - - @Override - public void setProducer(Producer p) { - arbiter.setProducer(p); - } - }; - other.unsafeSubscribe(second); - serial.set(second); - } - } - } - } -} \ No newline at end of file diff --git a/src/main/java/rx/internal/operators/OperatorTimeoutWithSelector.java b/src/main/java/rx/internal/operators/OperatorTimeoutWithSelector.java deleted file mode 100644 index 16034dba6c..0000000000 --- a/src/main/java/rx/internal/operators/OperatorTimeoutWithSelector.java +++ /dev/null @@ -1,111 +0,0 @@ -/** - * 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.internal.operators; - -import rx.*; -import rx.exceptions.Exceptions; -import rx.functions.*; -import rx.schedulers.Schedulers; -import rx.subscriptions.Subscriptions; - -/** - * Returns an Observable that mirrors the source Observable. If either the first - * item emitted by the source Observable or any subsequent item don't arrive - * within time windows defined by provided Observables, switch to the - * other Observable if provided, or emit a TimeoutException . - * @param the value type of the main Observable - * @param the value type of the first timeout Observable - * @param the value type of the subsequent timeout Observable - */ -public class OperatorTimeoutWithSelector extends - OperatorTimeoutBase { - - public OperatorTimeoutWithSelector( - final Func0> firstTimeoutSelector, - final Func1> timeoutSelector, - Observable other) { - super(new FirstTimeoutStub() { - - @Override - public Subscription call( - final TimeoutSubscriber timeoutSubscriber, - final Long seqId, Scheduler.Worker inner) { - if (firstTimeoutSelector != null) { - Observable o; - try { - o = firstTimeoutSelector.call(); - } catch (Throwable t) { - Exceptions.throwOrReport(t, timeoutSubscriber); - return Subscriptions.unsubscribed(); - } - return o.unsafeSubscribe(new Subscriber() { - - @Override - public void onCompleted() { - timeoutSubscriber.onTimeout(seqId); - } - - @Override - public void onError(Throwable e) { - timeoutSubscriber.onError(e); - } - - @Override - public void onNext(U t) { - timeoutSubscriber.onTimeout(seqId); - } - - }); - } else { - return Subscriptions.unsubscribed(); - } - } - }, new TimeoutStub() { - - @Override - public Subscription call( - final TimeoutSubscriber timeoutSubscriber, - final Long seqId, T value, Scheduler.Worker inner) { - Observable o; - try { - o = timeoutSelector.call(value); - } catch (Throwable t) { - Exceptions.throwOrReport(t, timeoutSubscriber); - return Subscriptions.unsubscribed(); - } - return o.unsafeSubscribe(new Subscriber() { - - @Override - public void onCompleted() { - timeoutSubscriber.onTimeout(seqId); - } - - @Override - public void onError(Throwable e) { - timeoutSubscriber.onError(e); - } - - @Override - public void onNext(V t) { - timeoutSubscriber.onTimeout(seqId); - } - - }); - } - }, other, Schedulers.immediate()); - } - -} diff --git a/src/test/java/rx/internal/operators/OperatorTimeoutTests.java b/src/test/java/rx/internal/operators/OperatorTimeoutTests.java index fba5b1d6c5..6be7706d0f 100644 --- a/src/test/java/rx/internal/operators/OperatorTimeoutTests.java +++ b/src/test/java/rx/internal/operators/OperatorTimeoutTests.java @@ -15,21 +15,26 @@ */ package rx.internal.operators; +import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.io.IOException; +import java.util.*; import java.util.concurrent.*; import org.junit.*; import org.mockito.*; import rx.*; +import rx.Observable; import rx.Observable.OnSubscribe; -import rx.functions.Func1; -import rx.observers.TestSubscriber; +import rx.Observer; +import rx.exceptions.TestException; +import rx.functions.*; +import rx.observers.*; import rx.schedulers.TestScheduler; -import rx.subjects.PublishSubject; +import rx.subjects.*; public class OperatorTimeoutTests { private PublishSubject underlyingSubject; @@ -427,4 +432,71 @@ public void withDefaultSchedulerAndOther() { ts.assertNoErrors(); ts.assertCompleted(); } + + @Test + public void disconnectOnTimeout() { + final List list = Collections.synchronizedList(new ArrayList()); + + TestScheduler sch = new TestScheduler(); + + Subject subject = PublishSubject.create(); + Observable initialObservable = subject.share() + .map(new Func1() { + @Override + public Long call(Long value) { + list.add("Received value " + value); + return value; + } + }); + + Observable timeoutObservable = initialObservable + .map(new Func1() { + @Override + public Long call(Long value) { + list.add("Timeout received value " + value); + return value; + } + }); + + TestSubscriber subscriber = new TestSubscriber(); + initialObservable + .doOnUnsubscribe(new Action0() { + @Override + public void call() { + list.add("Unsubscribed"); + } + }) + .timeout(1, TimeUnit.SECONDS, timeoutObservable, sch).subscribe(subscriber); + + subject.onNext(5L); + + sch.advanceTimeBy(2, TimeUnit.SECONDS); + + subject.onNext(10L); + subject.onCompleted(); + + subscriber.awaitTerminalEvent(); + subscriber.assertNoErrors(); + subscriber.assertValues(5L, 10L); + + assertEquals(Arrays.asList( + "Received value 5", + "Unsubscribed", + "Received value 10", + "Timeout received value 10" + ), list); + } + + @Test + public void fallbackIsError() { + TestScheduler sch = new TestScheduler(); + + AssertableSubscriber as = Observable.never() + .timeout(1, TimeUnit.SECONDS, Observable.error(new TestException()), sch) + .test(); + + sch.advanceTimeBy(1, TimeUnit.SECONDS); + + as.assertFailure(TestException.class); + } } diff --git a/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java b/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java index 50ce9e5865..628d1eca55 100644 --- a/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java +++ b/src/test/java/rx/internal/operators/OperatorTimeoutWithSelectorTest.java @@ -19,7 +19,8 @@ import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; -import java.util.Arrays; +import java.io.IOException; +import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -28,13 +29,15 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import rx.*; +import rx.Observable; import rx.Observable.OnSubscribe; +import rx.Observer; +import rx.Subscriber; import rx.exceptions.TestException; import rx.functions.*; -import rx.observers.TestSubscriber; -import rx.schedulers.Schedulers; -import rx.subjects.PublishSubject; +import rx.observers.*; +import rx.schedulers.*; +import rx.subjects.*; public class OperatorTimeoutWithSelectorTest { @Test(timeout = 2000) @@ -439,4 +442,169 @@ public Observable call() { assertEquals("timeoutSelector is null", ex.getMessage()); } } + + @Test + public void disconnectOnTimeout() { + final List list = Collections.synchronizedList(new ArrayList()); + + final TestScheduler sch = new TestScheduler(); + + Subject subject = PublishSubject.create(); + Observable initialObservable = subject.share() + .map(new Func1() { + @Override + public Long call(Long value) { + list.add("Received value " + value); + return value; + } + }); + + Observable timeoutObservable = initialObservable + .map(new Func1() { + @Override + public Long call(Long value) { + list.add("Timeout received value " + value); + return value; + } + }); + + TestSubscriber subscriber = new TestSubscriber(); + initialObservable + .doOnUnsubscribe(new Action0() { + @Override + public void call() { + list.add("Unsubscribed"); + } + }) + .timeout( + new Func0>() { + @Override + public Observable call() { + return Observable.timer(1, TimeUnit.SECONDS, sch); + } + }, + new Func1>() { + @Override + public Observable call(Long v) { + return Observable.timer(1, TimeUnit.SECONDS, sch); + } + }, + timeoutObservable).subscribe(subscriber); + + subject.onNext(5L); + + sch.advanceTimeBy(2, TimeUnit.SECONDS); + + subject.onNext(10L); + subject.onCompleted(); + + subscriber.awaitTerminalEvent(); + subscriber.assertNoErrors(); + subscriber.assertValues(5L, 10L); + + assertEquals(Arrays.asList( + "Received value 5", + "Unsubscribed", + "Received value 10", + "Timeout received value 10" + ), list); + } + + @Test + public void fallbackIsError() { + final TestScheduler sch = new TestScheduler(); + + AssertableSubscriber as = Observable.never() + .timeout(new Func0>() { + @Override + public Observable call() { + return Observable.timer(1, TimeUnit.SECONDS, sch); + } + }, + new Func1>() { + @Override + public Observable call(Object v) { + return Observable.timer(1, TimeUnit.SECONDS, sch); + } + }, Observable.error(new TestException())) + .test(); + + sch.advanceTimeBy(1, TimeUnit.SECONDS); + + as.assertFailure(TestException.class); + } + + @Test + public void mainErrors() { + final TestScheduler sch = new TestScheduler(); + + AssertableSubscriber as = Observable.error(new IOException()) + .timeout(new Func0>() { + @Override + public Observable call() { + return Observable.timer(1, TimeUnit.SECONDS, sch); + } + }, + new Func1>() { + @Override + public Observable call(Object v) { + return Observable.timer(1, TimeUnit.SECONDS, sch); + } + }, Observable.error(new TestException())) + .test(); + + as.assertFailure(IOException.class); + + sch.advanceTimeBy(1, TimeUnit.SECONDS); + + as.assertFailure(IOException.class); + } + + @Test + public void timeoutCompletesWithFallback() { + final TestScheduler sch = new TestScheduler(); + + AssertableSubscriber as = Observable.never() + .timeout(new Func0>() { + @Override + public Observable call() { + return Observable.timer(1, TimeUnit.SECONDS, sch).ignoreElements(); + } + }, + new Func1>() { + @Override + public Observable call(Object v) { + return Observable.timer(1, TimeUnit.SECONDS, sch); + } + }, Observable.just(1)) + .test(); + + sch.advanceTimeBy(1, TimeUnit.SECONDS); + + as.assertResult(1); + } + + @Test + public void nullItemTimeout() { + final TestScheduler sch = new TestScheduler(); + + AssertableSubscriber as = Observable.just(1).concatWith(Observable.never()) + .timeout(new Func0>() { + @Override + public Observable call() { + return Observable.timer(1, TimeUnit.SECONDS, sch).ignoreElements(); + } + }, + new Func1>() { + @Override + public Observable call(Object v) { + return null; + } + }, Observable.just(1)) + .test(); + + sch.advanceTimeBy(1, TimeUnit.SECONDS); + + as.assertFailureAndMessage(NullPointerException.class, "The itemTimeoutIndicator returned a null Observable", 1); + } } From 396b6104e419b80002c45faf76ac38f00d2ff64a Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 19 Oct 2017 10:54:04 +0200 Subject: [PATCH 59/74] Release 1.3.3 --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 3a834830b7..b8ac66c635 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # RxJava Releases # +### Version 1.3.3 - October 19, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.3%7C)) + +#### Bugfixes + +- [Pull 5660](https://github.com/ReactiveX/RxJava/pull/5660): Fix `timeout` (timed, selector) unsubscribe bug. + ### Version 1.3.2 - September 15, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.2%7C)) #### Bugfixes From 5b2394c9ee91f298661fff5e043744c84b425808 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Tue, 31 Oct 2017 19:37:55 +0100 Subject: [PATCH 60/74] 1.x: fix Completable.concat to use replace (don't dispose old) (#5696) * 1.x: fix Completable.concat to use replace (don't dispose old) * Remove original issue comments --- .../CompletableOnSubscribeConcatArray.java | 8 +- .../CompletableOnSubscribeConcatIterable.java | 9 ++- .../operators/CompletableConcatTest.java | 79 ++++++++++++++++++- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatArray.java b/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatArray.java index f291f0f649..cbac07ded5 100644 --- a/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatArray.java +++ b/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatArray.java @@ -20,7 +20,7 @@ import rx.*; import rx.Completable.OnSubscribe; -import rx.subscriptions.SerialSubscription; +import rx.internal.subscriptions.SequentialSubscription; public final class CompletableOnSubscribeConcatArray implements OnSubscribe { final Completable[] sources; @@ -45,17 +45,17 @@ static final class ConcatInnerSubscriber extends AtomicInteger implements Comple int index; - final SerialSubscription sd; + final SequentialSubscription sd; public ConcatInnerSubscriber(CompletableSubscriber actual, Completable[] sources) { this.actual = actual; this.sources = sources; - this.sd = new SerialSubscription(); + this.sd = new SequentialSubscription(); } @Override public void onSubscribe(Subscription d) { - sd.set(d); + sd.replace(d); } @Override diff --git a/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatIterable.java b/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatIterable.java index e5a3e95fc7..7506286906 100644 --- a/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatIterable.java +++ b/src/main/java/rx/internal/operators/CompletableOnSubscribeConcatIterable.java @@ -21,7 +21,8 @@ import rx.*; import rx.Completable.OnSubscribe; -import rx.subscriptions.*; +import rx.internal.subscriptions.SequentialSubscription; +import rx.subscriptions.Subscriptions; public final class CompletableOnSubscribeConcatIterable implements OnSubscribe { final Iterable sources; @@ -61,17 +62,17 @@ static final class ConcatInnerSubscriber extends AtomicInteger implements Comple final CompletableSubscriber actual; final Iterator sources; - final SerialSubscription sd; + final SequentialSubscription sd; public ConcatInnerSubscriber(CompletableSubscriber actual, Iterator sources) { this.actual = actual; this.sources = sources; - this.sd = new SerialSubscription(); + this.sd = new SequentialSubscription(); } @Override public void onSubscribe(Subscription d) { - sd.set(d); + sd.replace(d); } @Override diff --git a/src/test/java/rx/internal/operators/CompletableConcatTest.java b/src/test/java/rx/internal/operators/CompletableConcatTest.java index d05b11fc45..f55898193c 100644 --- a/src/test/java/rx/internal/operators/CompletableConcatTest.java +++ b/src/test/java/rx/internal/operators/CompletableConcatTest.java @@ -16,7 +16,11 @@ package rx.internal.operators; -import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertFalse; + +import java.util.Arrays; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.*; @@ -58,4 +62,77 @@ public void call() { Assert.assertEquals(5, calls[0]); } + + @Test + public void andThenNoInterrupt() throws InterruptedException { + for (int k = 0; k < 100; k++) { + final int count = 10; + final CountDownLatch latch = new CountDownLatch(count); + final AtomicBoolean interrupted = new AtomicBoolean(); + + for (int i = 0; i < count; i++) { + Completable.complete() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .andThen(Completable.fromAction(new Action0() { + @Override + public void call() { + try { + Thread.sleep(30); + } catch (InterruptedException e) { + System.out.println("Interrupted! " + Thread.currentThread()); + interrupted.set(true); + } + } + })) + .subscribe(new Action0() { + @Override + public void call() { + latch.countDown(); + } + }); + } + + latch.await(); + assertFalse("The second Completable was interrupted!", interrupted.get()); + } + } + + @Test + public void noInterrupt() throws InterruptedException { + for (int k = 0; k < 100; k++) { + final int count = 10; + final CountDownLatch latch = new CountDownLatch(count); + final AtomicBoolean interrupted = new AtomicBoolean(); + + for (int i = 0; i < count; i++) { + Completable c0 = Completable.fromAction(new Action0() { + @Override + public void call() { + try { + Thread.sleep(30); + } catch (InterruptedException e) { + System.out.println("Interrupted! " + Thread.currentThread()); + interrupted.set(true); + } + } + }); + Completable.concat(Arrays.asList(Completable.complete() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()), + c0) + ) + .subscribe(new Action0() { + @Override + public void call() { + latch.countDown(); + } + }); + } + + latch.await(); + assertFalse("The second Completable was interrupted!", interrupted.get()); + } + } + } From 048175a529f4b29b8c9778d3aecd4989fba4e486 Mon Sep 17 00:00:00 2001 From: Sadegh Date: Sat, 11 Nov 2017 17:00:46 +0330 Subject: [PATCH 61/74] 1.x: Add a sentence to documentation of take() operator (#5719) * Add a sentence to documentation of take() operator * Rephrase java doc for take() method --- src/main/java/rx/Observable.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 4b3d7802b4..5d1896008e 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -10536,6 +10536,9 @@ public final Observable take(final int count) { * Returns an Observable that emits those items emitted by source Observable before a specified time runs * out. *

+ * If time runs out before the {@code Observable} completes normally, the {@code onComplete} event will be + * signaled on the default {@code computation} {@link Scheduler}. + *

* *

*
Backpressure:
@@ -10560,6 +10563,9 @@ public final Observable take(long time, TimeUnit unit) { * Returns an Observable that emits those items emitted by source Observable before a specified time (on a * specified Scheduler) runs out. *

+ * If time runs out before the {@code Observable} completes normally, the {@code onComplete} event will be + * signaled on the provided {@link Scheduler}. + *

* *

*
Backpressure:
From bd862bc2335fe64190a8503da81c5146b9aadad7 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 16 Nov 2017 09:36:46 +0100 Subject: [PATCH 62/74] 1.x: fix broken backpressure through unsubscribeOn() (#5726) --- .../operators/OperatorUnsubscribeOn.java | 4 +++ .../operators/OperatorUnsubscribeOnTest.java | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/main/java/rx/internal/operators/OperatorUnsubscribeOn.java b/src/main/java/rx/internal/operators/OperatorUnsubscribeOn.java index 2f72d62d6b..a581009884 100644 --- a/src/main/java/rx/internal/operators/OperatorUnsubscribeOn.java +++ b/src/main/java/rx/internal/operators/OperatorUnsubscribeOn.java @@ -52,6 +52,10 @@ public void onNext(T t) { subscriber.onNext(t); } + @Override + public void setProducer(Producer p) { + subscriber.setProducer(p); + } }; subscriber.add(Subscriptions.create(new Action0() { diff --git a/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java b/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java index fe8d664122..c409a467bf 100644 --- a/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java +++ b/src/test/java/rx/internal/operators/OperatorUnsubscribeOnTest.java @@ -204,4 +204,31 @@ public Thread getThread() { } } + + @Test + public void backpressure() { + AssertableSubscriber as = Observable.range(1, 10) + .unsubscribeOn(Schedulers.trampoline()) + .test(0); + + as.assertNoValues() + .assertNoErrors() + .assertNotCompleted(); + + as.requestMore(1); + + as.assertValue(1) + .assertNoErrors() + .assertNotCompleted(); + + as.requestMore(3); + + as.assertValues(1, 2, 3, 4) + .assertNoErrors() + .assertNotCompleted(); + + as.requestMore(10); + + as.assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } } \ No newline at end of file From 265fb484f504e093da508811c498e6241975950e Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sun, 19 Nov 2017 11:40:40 +0100 Subject: [PATCH 63/74] Release 1.3.4 --- CHANGES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index b8ac66c635..41d2e5b164 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,16 @@ # RxJava Releases # +### Version 1.3.4 - November 19, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.4%7C)) + +#### Bugfixes + +- [Pull 5696](https://github.com/ReactiveX/RxJava/pull/5696): Fix `Completable.concat` to use `replace` and don't dispose the old `Subscription` on switching to the next source. +- [Pull 5726](https://github.com/ReactiveX/RxJava/pull/5726): Fix broken backpressure through `unsubscribeOn()`. + +#### Documentation + +- [Pull 5719](https://github.com/ReactiveX/RxJava/pull/5719): Document the timed `take()` operator will signal the `onCompleted` event on the given `Scheduler` when it times out. + ### Version 1.3.3 - October 19, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.3%7C)) #### Bugfixes From ef329508bc686cd68614da8676bb6b903c82e67a Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 25 Jan 2018 13:39:59 +0100 Subject: [PATCH 64/74] 1.x: Plugin lookup workaround for System.properties access restrictions (#5820) * 1.x: Plugin lookup workaround for System.properties access restrictions * System.getProperties() can also throw SecurityException --- src/main/java/rx/plugins/RxJavaPlugins.java | 54 +++++++++----- .../java/rx/plugins/RxJavaPluginsTest.java | 72 +++++++++++++++++++ 2 files changed, 109 insertions(+), 17 deletions(-) diff --git a/src/main/java/rx/plugins/RxJavaPlugins.java b/src/main/java/rx/plugins/RxJavaPlugins.java index 7a5856d431..cac5b167c6 100644 --- a/src/main/java/rx/plugins/RxJavaPlugins.java +++ b/src/main/java/rx/plugins/RxJavaPlugins.java @@ -105,7 +105,7 @@ public void reset() { public RxJavaErrorHandler getErrorHandler() { if (errorHandler.get() == null) { // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(RxJavaErrorHandler.class, System.getProperties()); + Object impl = getPluginImplementationViaProperty(RxJavaErrorHandler.class, getSystemPropertiesSafe()); if (impl == null) { // nothing set via properties so initialize with default errorHandler.compareAndSet(null, DEFAULT_ERROR_HANDLER); @@ -147,7 +147,7 @@ public void registerErrorHandler(RxJavaErrorHandler impl) { public RxJavaObservableExecutionHook getObservableExecutionHook() { if (observableExecutionHook.get() == null) { // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(RxJavaObservableExecutionHook.class, System.getProperties()); + Object impl = getPluginImplementationViaProperty(RxJavaObservableExecutionHook.class, getSystemPropertiesSafe()); if (impl == null) { // nothing set via properties so initialize with default observableExecutionHook.compareAndSet(null, RxJavaObservableExecutionHookDefault.getInstance()); @@ -189,7 +189,7 @@ public void registerObservableExecutionHook(RxJavaObservableExecutionHook impl) public RxJavaSingleExecutionHook getSingleExecutionHook() { if (singleExecutionHook.get() == null) { // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(RxJavaSingleExecutionHook.class, System.getProperties()); + Object impl = getPluginImplementationViaProperty(RxJavaSingleExecutionHook.class, getSystemPropertiesSafe()); if (impl == null) { // nothing set via properties so initialize with default singleExecutionHook.compareAndSet(null, RxJavaSingleExecutionHookDefault.getInstance()); @@ -232,7 +232,7 @@ public void registerSingleExecutionHook(RxJavaSingleExecutionHook impl) { public RxJavaCompletableExecutionHook getCompletableExecutionHook() { if (completableExecutionHook.get() == null) { // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(RxJavaCompletableExecutionHook.class, System.getProperties()); + Object impl = getPluginImplementationViaProperty(RxJavaCompletableExecutionHook.class, getSystemPropertiesSafe()); if (impl == null) { // nothing set via properties so initialize with default completableExecutionHook.compareAndSet(null, new RxJavaCompletableExecutionHook() { }); @@ -262,6 +262,19 @@ public void registerCompletableExecutionHook(RxJavaCompletableExecutionHook impl } } + /** + * A security manager may prevent accessing the System properties entirely, + * therefore, the SecurityException is turned into an empty properties. + * @return the Properties to use for looking up settings + */ + /* test */ static Properties getSystemPropertiesSafe() { + try { + return System.getProperties(); + } catch (SecurityException ex) { + return new Properties(); + } + } + /* test */ static Object getPluginImplementationViaProperty(Class pluginClass, Properties propsIn) { // Make a defensive clone because traversal may fail with ConcurrentModificationException // if the properties get changed by something outside RxJava. @@ -284,25 +297,32 @@ public void registerCompletableExecutionHook(RxJavaCompletableExecutionHook impl String classSuffix = ".class"; String implSuffix = ".impl"; - for (Map.Entry e : props.entrySet()) { - String key = e.getKey().toString(); - if (key.startsWith(pluginPrefix) && key.endsWith(classSuffix)) { - String value = e.getValue().toString(); + try { + for (Map.Entry e : props.entrySet()) { + String key = e.getKey().toString(); + if (key.startsWith(pluginPrefix) && key.endsWith(classSuffix)) { + String value = e.getValue().toString(); + + if (classSimpleName.equals(value)) { + String index = key.substring(0, key.length() - classSuffix.length()).substring(pluginPrefix.length()); - if (classSimpleName.equals(value)) { - String index = key.substring(0, key.length() - classSuffix.length()).substring(pluginPrefix.length()); + String implKey = pluginPrefix + index + implSuffix; - String implKey = pluginPrefix + index + implSuffix; + implementingClass = props.getProperty(implKey); - implementingClass = props.getProperty(implKey); + if (implementingClass == null) { + throw new IllegalStateException("Implementing class declaration for " + classSimpleName + " missing: " + implKey); + } - if (implementingClass == null) { - throw new IllegalStateException("Implementing class declaration for " + classSimpleName + " missing: " + implKey); + break; } - - break; } } + } catch (SecurityException ex) { + // https://github.com/ReactiveX/RxJava/issues/5819 + // We don't seem to have access to all properties. + // At least print the exception to the console. + ex.printStackTrace(); } } @@ -339,7 +359,7 @@ public void registerCompletableExecutionHook(RxJavaCompletableExecutionHook impl public RxJavaSchedulersHook getSchedulersHook() { if (schedulersHook.get() == null) { // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(RxJavaSchedulersHook.class, System.getProperties()); + Object impl = getPluginImplementationViaProperty(RxJavaSchedulersHook.class, getSystemPropertiesSafe()); if (impl == null) { // nothing set via properties so initialize with default schedulersHook.compareAndSet(null, RxJavaSchedulersHook.getDefaultInstance()); diff --git a/src/test/java/rx/plugins/RxJavaPluginsTest.java b/src/test/java/rx/plugins/RxJavaPluginsTest.java index 1c69ff1389..50d6944a08 100644 --- a/src/test/java/rx/plugins/RxJavaPluginsTest.java +++ b/src/test/java/rx/plugins/RxJavaPluginsTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.mock; +import java.security.Permission; import java.util.*; import java.util.concurrent.TimeUnit; @@ -344,4 +345,75 @@ public void onNext(Object o) { assertEquals(re, errorHandler.e); assertEquals(1, errorHandler.count); } + + @Test + public void systemPropertiesSecurityException() { + assertNull(RxJavaPlugins.getPluginImplementationViaProperty(Object.class, new Properties() { + + private static final long serialVersionUID = -4291534158508255616L; + + @Override + public Set> entrySet() { + return new HashSet>() { + + private static final long serialVersionUID = -7714005655772619143L; + + @Override + public Iterator> iterator() { + return new Iterator>() { + @Override + public boolean hasNext() { + return true; + } + + @Override + public Map.Entry next() { + throw new SecurityException(); + }; + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + @Override + public synchronized Object clone() { + return this; + } + })); + } + + @Test + public void securityManagerDenySystemProperties() { + SecurityManager old = System.getSecurityManager(); + try { + SecurityManager sm = new SecurityManager() { + @Override + public void checkPropertiesAccess() { + throw new SecurityException(); + } + + @Override + public void checkPermission(Permission perm) { + // allow restoring the security manager + } + + @Override + public void checkPermission(Permission perm, Object context) { + // allow restoring the security manager + } + }; + + System.setSecurityManager(sm); + assertTrue(RxJavaPlugins.getSystemPropertiesSafe().isEmpty()); + } finally { + System.setSecurityManager(old); + } + + assertFalse(RxJavaPlugins.getSystemPropertiesSafe().isEmpty()); + } } From a49c49f6646d75aafcdd3b0dea3dc3455e88dfc2 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sat, 27 Jan 2018 12:28:37 +0100 Subject: [PATCH 65/74] Release 1.3.5 --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 41d2e5b164..8f01a33275 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # RxJava Releases # +### Version 1.3.5 - January 27, 2018 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.5%7C)) + +#### Other + +- [Pull 5820](https://github.com/ReactiveX/RxJava/pull/5820): `RxJavaPlugins` lookup workaround for `System.getProperties()` access restrictions. + ### Version 1.3.4 - November 19, 2017 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.4%7C)) #### Bugfixes From 2ba8bb2862255ab26c61d9a14ef17b32d2bfc484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ko=C5=82aczkowski?= Date: Thu, 15 Feb 2018 11:15:43 +0100 Subject: [PATCH 66/74] Fix a race condition in OperatorMerge.InnerSubscriber#onError (#5851) * Fix a race condition in OperatorMerge.InnerSubscriber#onError Inner subscriber must queue the error first before setting done, so that after emitLoop() removes the subscriber, emitLoop is guaranteed to notice the error. Otherwise it would be possible that inner subscribers count was 0, and at the same time the error queue was empty. * Add unit test for OperatorMerge.InnerSubscriber#onError race --- .../rx/internal/operators/OperatorMerge.java | 5 +++- .../internal/operators/OperatorMergeTest.java | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main/java/rx/internal/operators/OperatorMerge.java b/src/main/java/rx/internal/operators/OperatorMerge.java index fa30f46b10..a52eee07e9 100644 --- a/src/main/java/rx/internal/operators/OperatorMerge.java +++ b/src/main/java/rx/internal/operators/OperatorMerge.java @@ -847,8 +847,11 @@ public void onNext(T t) { } @Override public void onError(Throwable e) { - done = true; + // Need to queue the error first before setting done, so that after emitLoop() removes the subscriber, + // it is guaranteed to notice the error. Otherwise it would be possible that inner subscribers count was 0, + // and at the same time the error queue was empty. parent.getOrCreateErrorQueue().offer(e); + done = true; parent.emit(); } @Override diff --git a/src/test/java/rx/internal/operators/OperatorMergeTest.java b/src/test/java/rx/internal/operators/OperatorMergeTest.java index 7528cb88d8..bc13673f5e 100644 --- a/src/test/java/rx/internal/operators/OperatorMergeTest.java +++ b/src/test/java/rx/internal/operators/OperatorMergeTest.java @@ -1205,6 +1205,34 @@ public void onNext(Integer t) { assertTrue(latch.await(10, TimeUnit.SECONDS)); } + @Test + public void testConcurrentMergeInnerError() { + for (int i = 0; i < 1000; i++) { + final TestSubscriber ts = TestSubscriber.create(); + final PublishSubject ps1 = PublishSubject.create(); + final PublishSubject ps2 = PublishSubject.create(); + final Exception error = new NullPointerException(); + Action0 action1 = new Action0() { + @Override + public void call() { + ps1.onNext(1); + ps1.onCompleted(); + } + }; + Action0 action2 = new Action0() { + @Override + public void call() { + ps2.onError(error); + } + }; + + Observable.mergeDelayError(ps1, ps2).subscribe(ts); + TestUtil.race(action1, action2); + ts.assertTerminalEvent(); + ts.assertError(error); + } + } + private static Action1 printCount() { return new Action1() { long count; From c40a06f331cfeea8ccca987edaff54a294abc07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ko=C5=82aczkowski?= Date: Thu, 15 Feb 2018 19:49:26 +0100 Subject: [PATCH 67/74] Fix a race condition that may make OperatorMaterialize emit too many terminal notifications (#5850) * Fix a race condition that may make OperatorMaterialize emit the terminal notification more than once The guards in `OperatorMaterialize.ParentSubscriber#drain` were never working, because `busy` was actually never set to true. Therefore it was possible that the `drain` loop was executed by more than one thread concurrently, which could led to undefined behavior. This fix sets `busy` to true at the entry of `drain`. * Add unit test for race in OperatorMaterialize * Set sudo required in travis config --- .travis.yml | 2 +- .../operators/OperatorMaterialize.java | 1 + .../operators/OperatorMaterializeTest.java | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 751937fa52..e9ae55c471 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: java jdk: - oraclejdk8 -sudo: false +sudo: required # as per http://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/ git: diff --git a/src/main/java/rx/internal/operators/OperatorMaterialize.java b/src/main/java/rx/internal/operators/OperatorMaterialize.java index c1d4a3b65e..ce9e1be604 100644 --- a/src/main/java/rx/internal/operators/OperatorMaterialize.java +++ b/src/main/java/rx/internal/operators/OperatorMaterialize.java @@ -134,6 +134,7 @@ private void drain() { missed = true; return; } + busy = true; } // drain loop final AtomicLong localRequested = this.requested; diff --git a/src/test/java/rx/internal/operators/OperatorMaterializeTest.java b/src/test/java/rx/internal/operators/OperatorMaterializeTest.java index 437593d313..a55758d25c 100644 --- a/src/test/java/rx/internal/operators/OperatorMaterializeTest.java +++ b/src/test/java/rx/internal/operators/OperatorMaterializeTest.java @@ -29,9 +29,12 @@ import rx.Notification; import rx.Observable; import rx.Subscriber; +import rx.TestUtil; +import rx.functions.Action0; import rx.functions.Action1; import rx.observers.TestSubscriber; import rx.schedulers.Schedulers; +import rx.subjects.PublishSubject; public class OperatorMaterializeTest { @@ -201,6 +204,33 @@ public void testUnsubscribeJustBeforeCompletionNotificationShouldPreventThatNoti ts.assertUnsubscribed(); } + @Test + public void testConcurrency() { + for (int i = 0; i < 1000; i++) { + final TestSubscriber> ts = TestSubscriber.create(0); + final PublishSubject ps = PublishSubject.create(); + Action0 publishAction = new Action0() { + @Override + public void call() { + ps.onCompleted(); + } + }; + + Action0 requestAction = new Action0() { + @Override + public void call() { + ts.requestMore(1); + } + }; + + ps.materialize().subscribe(ts); + TestUtil.race(publishAction, requestAction); + ts.assertValueCount(1); + ts.assertTerminalEvent(); + ts.assertNoErrors(); + } + } + private static class TestObserver extends Subscriber> { boolean onCompleted; From 6e6c5143afec6cdddf72e4e890a02a683ea14ba3 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Thu, 15 Feb 2018 20:53:01 +0100 Subject: [PATCH 68/74] Release 1.3.6 --- CHANGES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 8f01a33275..792c803ece 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ # RxJava Releases # +### Version 1.3.6 - February 15, 2018 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.6%7C)) + +#### Bugfixes + +- [Pull 5850](https://github.com/ReactiveX/RxJava/pull/5850): Fix a race condition that may make `OperatorMaterialize` emit the wrong signals. +- [Pull 5851](https://github.com/ReactiveX/RxJava/pull/5851): Fix a race condition in `OperatorMerge.InnerSubscriber#onError` causing incorrect terminal event. + ### Version 1.3.5 - January 27, 2018 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.5%7C)) #### Other From e467798b3b712af4161605e5bd57cb16f7e5168e Mon Sep 17 00:00:00 2001 From: Dave Moten Date: Tue, 20 Mar 2018 01:21:40 +1100 Subject: [PATCH 69/74] 1.x: fix and deprecate evicting groupBy and add new overload (#5917) * 1.x: fix bug and deprecate groupBy overload with evictingMapFactory, add new groupBy evicting overload (#5868) * groupBy, do a null check on g because cancel(K) could have cleared the map --- build.gradle | 2 +- src/main/java/rx/Observable.java | 75 ++- .../internal/operators/OperatorGroupBy.java | 24 +- .../operators/OperatorGroupByEvicting.java | 605 ++++++++++++++++++ .../operators/OperatorGroupByTest.java | 228 +++++++ 5 files changed, 928 insertions(+), 6 deletions(-) create mode 100644 src/main/java/rx/internal/operators/OperatorGroupByEvicting.java diff --git a/build.gradle b/build.gradle index 570ceb242f..8d0d2fa087 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ dependencies { testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.10.19' - testCompile 'com.google.guava:guava:19.0' + testCompile 'com.google.guava:guava:24.0-jre' testCompile 'com.pushtorefresh.java-private-constructor-checker:checker:1.2.0' perfCompile 'org.openjdk.jmh:jmh-core:1.11.3' diff --git a/src/main/java/rx/Observable.java b/src/main/java/rx/Observable.java index 5d1896008e..99e84ec609 100644 --- a/src/main/java/rx/Observable.java +++ b/src/main/java/rx/Observable.java @@ -7275,7 +7275,7 @@ public final void forEach(final Action1 onNext, final Action1ReactiveX operators documentation: GroupBy */ public final Observable> groupBy(final Func1 keySelector, final Func1 elementSelector) { - return lift(new OperatorGroupBy(keySelector, elementSelector)); + return lift(new OperatorGroupByEvicting(keySelector, elementSelector)); } /** @@ -7334,7 +7334,12 @@ public final Observable> groupBy(final Func1ReactiveX operators documentation: GroupBy * @since 1.3 + * @deprecated since 1.3.7, use {@link #groupBy(Func1, Func1, int, boolean, Func1)} + * instead which uses much less memory. Please take note of the + * usage difference involving the evicting action which now expects + * the value from the map instead of the key. */ + @Deprecated public final Observable> groupBy(final Func1 keySelector, final Func1 elementSelector, final Func1, Map> evictingMapFactory) { if (evictingMapFactory == null) { @@ -7369,6 +7374,72 @@ public final Observable> groupBy(final Func1 + * {@code + * Func1, Map> mapFactory + * = action -> CacheBuilder.newBuilder() + * .maximumSize(1000) + * .expireAfterAccess(12, TimeUnit.HOURS) + * .removalListener(entry -> action.call(entry.getValue())) + * . build().asMap(); + * } + * + * + * @param + * the key type + * @param + * the element type + * @return an {@code Observable} that emits {@link GroupedObservable}s, each of which corresponds to a + * unique key value and each of which emits those items from the source Observable that share that + * key value + * @throws NullPointerException + * if {@code evictingMapFactory} is null + * @see ReactiveX operators documentation: GroupBy + * @since 1.3.7 + */ + @Experimental + public final Observable> groupBy(final Func1 keySelector, + final Func1 elementSelector, int bufferSize, boolean delayError, + final Func1, Map> evictingMapFactory) { + if (evictingMapFactory == null) { + throw new NullPointerException("evictingMapFactory cannot be null"); + } + return lift(new OperatorGroupByEvicting( + keySelector, elementSelector, bufferSize, delayError, evictingMapFactory)); + } + + /** + * Groups the items emitted by an {@code Observable} according to a specified criterion, and emits these + * grouped items as {@link GroupedObservable}s. The emitted {@code GroupedObservable} allows only a single + * {@link Subscriber} during its lifetime and if this {@code Subscriber} unsubscribes before the + * source terminates, the next emission by the source having the same key will trigger a new + * {@code GroupedObservable} emission. + *

+ * + *

+ * Note: A {@link GroupedObservable} will cache the items it is to emit until such time as it + * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those + * {@code GroupedObservable}s that do not concern you. Instead, you can signal to them that they may + * discard their buffers by applying an operator like {@link #ignoreElements} to them. + *

+ *
Scheduler:
+ *
{@code groupBy} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @param keySelector + * a function that extracts the key for each item * @param * the key type * @return an {@code Observable} that emits {@link GroupedObservable}s, each of which corresponds to a @@ -7377,7 +7448,7 @@ public final Observable> groupBy(final Func1ReactiveX operators documentation: GroupBy */ public final Observable> groupBy(final Func1 keySelector) { - return lift(new OperatorGroupBy(keySelector)); + return lift(new OperatorGroupByEvicting(keySelector)); } /** diff --git a/src/main/java/rx/internal/operators/OperatorGroupBy.java b/src/main/java/rx/internal/operators/OperatorGroupBy.java index 8892f0d4d0..5d6ec2f556 100644 --- a/src/main/java/rx/internal/operators/OperatorGroupBy.java +++ b/src/main/java/rx/internal/operators/OperatorGroupBy.java @@ -42,13 +42,16 @@ * the source and group value type * @param * the value type of the groups + * @deprecated + * since 1.3.7, use {@link OperatorGroupByEvicting} instead */ +@Deprecated public final class OperatorGroupBy implements Operator, T> { final Func1 keySelector; final Func1 valueSelector; final int bufferSize; final boolean delayError; - final Func1, Map> mapFactory; + final Func1, Map> mapFactory; //nullable @SuppressWarnings({ "unchecked", "rawtypes" }) public OperatorGroupBy(Func1 keySelector) { @@ -116,6 +119,10 @@ public static final class GroupBySubscriber final int bufferSize; final boolean delayError; final Map> groups; + + // double store the groups to workaround the bug in the + // signature of groupBy with evicting map factory + final Map> groupsCopy; final Queue> queue; final GroupByProducer producer; final Queue evictedKeys; @@ -134,7 +141,7 @@ public static final class GroupBySubscriber volatile boolean done; final AtomicInteger wip; - + public GroupBySubscriber(Subscriber> actual, Func1 keySelector, Func1 valueSelector, int bufferSize, boolean delayError, Func1, Map> mapFactory) { @@ -158,6 +165,7 @@ public GroupBySubscriber(Subscriber> actual, Fun this.evictedKeys = new ConcurrentLinkedQueue(); this.groups = createMap(mapFactory, new EvictionAction(evictedKeys)); } + this.groupsCopy = new ConcurrentHashMap>(); } static class EvictionAction implements Action1 { @@ -211,6 +219,9 @@ public void onNext(T t) { if (!cancelled.get()) { group = GroupedUnicast.createWith(key, bufferSize, this, delayError); groups.put(mapKey, group); + if (evictedKeys != null) { + groupsCopy.put(mapKey, group); + } groupCount.getAndIncrement(); @@ -234,7 +245,9 @@ public void onNext(T t) { if (evictedKeys != null) { K evictedKey; while ((evictedKey = evictedKeys.poll()) != null) { - GroupedUnicast g = groups.get(evictedKey); + GroupedUnicast g = groupsCopy.remove(evictedKey); + // do a null check on g because cancel(K) could have cleared + // the map if (g != null) { g.onComplete(); } @@ -270,6 +283,7 @@ public void onCompleted() { } groups.clear(); if (evictedKeys != null) { + groupsCopy.clear(); evictedKeys.clear(); } @@ -304,6 +318,9 @@ public void cancel(K key) { unsubscribe(); } } + if (evictedKeys != null) { + groupsCopy.remove(mapKey); + } } void drain() { @@ -364,6 +381,7 @@ void errorAll(Subscriber> a, Queue q, Throwab List> list = new ArrayList>(groups.values()); groups.clear(); if (evictedKeys != null) { + groupsCopy.clear(); evictedKeys.clear(); } diff --git a/src/main/java/rx/internal/operators/OperatorGroupByEvicting.java b/src/main/java/rx/internal/operators/OperatorGroupByEvicting.java new file mode 100644 index 0000000000..d02ecf5d39 --- /dev/null +++ b/src/main/java/rx/internal/operators/OperatorGroupByEvicting.java @@ -0,0 +1,605 @@ +/** + * Copyright 2018 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.internal.operators; + +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +import rx.*; +import rx.Observable.*; +import rx.exceptions.Exceptions; +import rx.functions.*; +import rx.internal.producers.ProducerArbiter; +import rx.internal.util.*; +import rx.observables.GroupedObservable; +import rx.plugins.RxJavaHooks; +import rx.observers.Subscribers; +import rx.subscriptions.Subscriptions; + +/** + * Groups the items emitted by an Observable according to a specified criterion, and emits these + * grouped items as Observables, one Observable per group. + *

+ * + * + * @param + * the key type + * @param + * the source and group value type + * @param + * the value type of the groups + */ +public final class OperatorGroupByEvicting implements Operator, T>{ + + final Func1 keySelector; + final Func1 valueSelector; + final int bufferSize; + final boolean delayError; + final Func1, Map> mapFactory; //nullable + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public OperatorGroupByEvicting(Func1 keySelector) { + this(keySelector, (Func1)UtilityFunctions.identity(), RxRingBuffer.SIZE, false, null); + } + + public OperatorGroupByEvicting(Func1 keySelector, Func1 valueSelector) { + this(keySelector, valueSelector, RxRingBuffer.SIZE, false, null); + } + + public OperatorGroupByEvicting(Func1 keySelector, Func1 valueSelector, int bufferSize, boolean delayError, Func1, Map> mapFactory) { + this.keySelector = keySelector; + this.valueSelector = valueSelector; + this.bufferSize = bufferSize; + this.delayError = delayError; + this.mapFactory = mapFactory; + } + + @SuppressWarnings("unchecked") + @Override + public Subscriber call(Subscriber> child) { + Map> groups; + Queue> evictedGroups; + + if (mapFactory == null) { + evictedGroups = null; + groups = new ConcurrentHashMap>(); + } else { + evictedGroups = new ConcurrentLinkedQueue>(); + Action1 evictionAction = (Action1)(Action1) + new EvictionAction(evictedGroups); + try { + groups = (Map>)(Map) + mapFactory.call((Action1)(Action1) evictionAction); + } catch (Throwable ex) { + //Can reach here because mapFactory.call() may throw + Exceptions.throwOrReport(ex, child); + Subscriber parent2 = Subscribers.empty(); + parent2.unsubscribe(); + return parent2; + } + } + final GroupBySubscriber parent = new GroupBySubscriber( + child, keySelector, valueSelector, bufferSize, delayError, groups, evictedGroups); + + child.add(Subscriptions.create(new Action0() { + @Override + public void call() { + parent.cancel(); + } + })); + + child.setProducer(parent.producer); + + return parent; + } + + public static final class GroupByProducer implements Producer { + final GroupBySubscriber parent; + + public GroupByProducer(GroupBySubscriber parent) { + this.parent = parent; + } + @Override + public void request(long n) { + parent.requestMore(n); + } + } + + public static final class GroupBySubscriber + extends Subscriber { + final Subscriber> actual; + final Func1 keySelector; + final Func1 valueSelector; + final int bufferSize; + final boolean delayError; + final Map> groups; + final Queue> queue; + final GroupByProducer producer; + final Queue> evictedGroups; + + static final Object NULL_KEY = new Object(); + + final ProducerArbiter s; + + final AtomicBoolean cancelled; + + final AtomicLong requested; + + final AtomicInteger groupCount; + + Throwable error; + volatile boolean done; + + final AtomicInteger wip; + + public GroupBySubscriber(Subscriber> actual, Func1 keySelector, + Func1 valueSelector, int bufferSize, boolean delayError, Map> groups, + Queue> evictedGroups) { + this.actual = actual; + this.keySelector = keySelector; + this.valueSelector = valueSelector; + this.bufferSize = bufferSize; + this.delayError = delayError; + this.queue = new ConcurrentLinkedQueue>(); + this.s = new ProducerArbiter(); + this.s.request(bufferSize); + this.producer = new GroupByProducer(this); + this.cancelled = new AtomicBoolean(); + this.requested = new AtomicLong(); + this.groupCount = new AtomicInteger(1); + this.wip = new AtomicInteger(); + this.groups = groups; + this.evictedGroups = evictedGroups; + } + + @Override + public void setProducer(Producer s) { + this.s.setProducer(s); + } + + @Override + public void onNext(T t) { + if (done) { + return; + } + + final Queue> q = this.queue; + final Subscriber> a = this.actual; + + K key; + try { + key = keySelector.call(t); + } catch (Throwable ex) { + unsubscribe(); + errorAll(a, q, ex); + return; + } + + boolean newGroup = false; + @SuppressWarnings("unchecked") + K mapKey = key != null ? key : (K) NULL_KEY; + GroupedUnicast group = groups.get(mapKey); + if (group == null) { + // if the main has been cancelled, stop creating groups + // and skip this value + if (!cancelled.get()) { + group = GroupedUnicast.createWith(key, bufferSize, this, delayError); + groups.put(mapKey, group); + + groupCount.getAndIncrement(); + + newGroup = false; + q.offer(group); + drain(); + } else { + return; + } + } + + V v; + try { + v = valueSelector.call(t); + } catch (Throwable ex) { + unsubscribe(); + errorAll(a, q, ex); + return; + } + + group.onNext(v); + + if (evictedGroups != null) { + GroupedUnicast evictedGroup; + while ((evictedGroup = evictedGroups.poll()) != null) { + evictedGroup.onComplete(); + } + } + + if (newGroup) { + q.offer(group); + drain(); + } + } + + @Override + public void onError(Throwable t) { + if (done) { + RxJavaHooks.onError(t); + return; + } + error = t; + done = true; + groupCount.decrementAndGet(); + drain(); + } + + @Override + public void onCompleted() { + if (done) { + return; + } + + for (GroupedUnicast e : groups.values()) { + e.onComplete(); + } + groups.clear(); + if (evictedGroups != null) { + evictedGroups.clear(); + } + + done = true; + groupCount.decrementAndGet(); + drain(); + } + + public void requestMore(long n) { + if (n < 0) { + throw new IllegalArgumentException("n >= 0 required but it was " + n); + } + + BackpressureUtils.getAndAddRequest(requested, n); + drain(); + } + + public void cancel() { + // cancelling the main source means we don't want any more groups + // but running groups still require new values + if (cancelled.compareAndSet(false, true)) { + if (groupCount.decrementAndGet() == 0) { + unsubscribe(); + } + } + } + + public void cancel(K key) { + Object mapKey = key != null ? key : NULL_KEY; + if (groups.remove(mapKey) != null) { + if (groupCount.decrementAndGet() == 0) { + unsubscribe(); + } + } + } + + void drain() { + if (wip.getAndIncrement() != 0) { + return; + } + + int missed = 1; + + final Queue> q = this.queue; + final Subscriber> a = this.actual; + + for (;;) { + + if (checkTerminated(done, q.isEmpty(), a, q)) { + return; + } + + long r = requested.get(); + boolean unbounded = r == Long.MAX_VALUE; + long e = 0L; + + while (r != 0) { + boolean d = done; + + GroupedObservable t = q.poll(); + + boolean empty = t == null; + + if (checkTerminated(d, empty, a, q)) { + return; + } + + if (empty) { + break; + } + + a.onNext(t); + + r--; + e--; + } + + if (e != 0L) { + if (!unbounded) { + requested.addAndGet(e); + } + s.request(-e); + } + + missed = wip.addAndGet(-missed); + if (missed == 0) { + break; + } + } + } + + void errorAll(Subscriber> a, Queue q, Throwable ex) { + q.clear(); + List> list = new ArrayList>(groups.values()); + groups.clear(); + if (evictedGroups != null) { + evictedGroups.clear(); + } + + for (GroupedUnicast e : list) { + e.onError(ex); + } + + a.onError(ex); + } + + boolean checkTerminated(boolean d, boolean empty, + Subscriber> a, Queue q) { + if (d) { + Throwable err = error; + if (err != null) { + errorAll(a, q, err); + return true; + } else + if (empty) { + actual.onCompleted(); + return true; + } + } + return false; + } + } + + static class EvictionAction implements Action1> { + + final Queue> evictedGroups; + + EvictionAction(Queue> evictedGroups) { + this.evictedGroups = evictedGroups; + } + + @Override + public void call(GroupedUnicast group) { + evictedGroups.offer(group); + } + } + + static final class GroupedUnicast extends GroupedObservable { + + public static GroupedUnicast createWith(K key, int bufferSize, GroupBySubscriber parent, boolean delayError) { + State state = new State(bufferSize, parent, key, delayError); + return new GroupedUnicast(key, state); + } + + final State state; + + protected GroupedUnicast(K key, State state) { + super(key, state); + this.state = state; + } + + public void onNext(T t) { + state.onNext(t); + } + + public void onError(Throwable e) { + state.onError(e); + } + + public void onComplete() { + state.onComplete(); + } + } + + static final class State extends AtomicInteger implements Producer, Subscription, OnSubscribe { + /** */ + private static final long serialVersionUID = -3852313036005250360L; + + final K key; + final Queue queue; + final GroupBySubscriber parent; + final boolean delayError; + + final AtomicLong requested; + + volatile boolean done; + Throwable error; + + final AtomicBoolean cancelled; + + final AtomicReference> actual; + + final AtomicBoolean once; + + + public State(int bufferSize, GroupBySubscriber parent, K key, boolean delayError) { + this.queue = new ConcurrentLinkedQueue(); + this.parent = parent; + this.key = key; + this.delayError = delayError; + this.cancelled = new AtomicBoolean(); + this.actual = new AtomicReference>(); + this.once = new AtomicBoolean(); + this.requested = new AtomicLong(); + } + + @Override + public void request(long n) { + if (n < 0) { + throw new IllegalArgumentException("n >= required but it was " + n); + } + if (n != 0L) { + BackpressureUtils.getAndAddRequest(requested, n); + drain(); + } + } + + @Override + public boolean isUnsubscribed() { + return cancelled.get(); + } + + @Override + public void unsubscribe() { + if (cancelled.compareAndSet(false, true)) { + if (getAndIncrement() == 0) { + parent.cancel(key); + } + } + } + + @Override + public void call(Subscriber s) { + if (once.compareAndSet(false, true)) { + s.add(this); + s.setProducer(this); + actual.lazySet(s); + drain(); + } else { + s.onError(new IllegalStateException("Only one Subscriber allowed!")); + } + } + + public void onNext(T t) { + if (t == null) { + error = new NullPointerException(); + done = true; + } else { + queue.offer(NotificationLite.next(t)); + } + drain(); + } + + public void onError(Throwable e) { + error = e; + done = true; + drain(); + } + + public void onComplete() { + done = true; + drain(); + } + + void drain() { + if (getAndIncrement() != 0) { + return; + } + int missed = 1; + + final Queue q = queue; + final boolean delayError = this.delayError; + Subscriber a = actual.get(); + for (;;) { + if (a != null) { + if (checkTerminated(done, q.isEmpty(), a, delayError)) { + return; + } + + long r = requested.get(); + boolean unbounded = r == Long.MAX_VALUE; + long e = 0; + + while (r != 0L) { + boolean d = done; + Object v = q.poll(); + boolean empty = v == null; + + if (checkTerminated(d, empty, a, delayError)) { + return; + } + + if (empty) { + break; + } + + a.onNext(NotificationLite.getValue(v)); + + r--; + e--; + } + + if (e != 0L) { + if (!unbounded) { + requested.addAndGet(e); + } + parent.s.request(-e); + } + } + + missed = addAndGet(-missed); + if (missed == 0) { + break; + } + if (a == null) { + a = actual.get(); + } + } + } + + boolean checkTerminated(boolean d, boolean empty, Subscriber a, boolean delayError) { + if (cancelled.get()) { + queue.clear(); + parent.cancel(key); + return true; + } + + if (d) { + if (delayError) { + if (empty) { + Throwable e = error; + if (e != null) { + a.onError(e); + } else { + a.onCompleted(); + } + return true; + } + } else { + Throwable e = error; + if (e != null) { + queue.clear(); + a.onError(e); + return true; + } else + if (empty) { + a.onCompleted(); + return true; + } + } + } + + return false; + } + } +} diff --git a/src/test/java/rx/internal/operators/OperatorGroupByTest.java b/src/test/java/rx/internal/operators/OperatorGroupByTest.java index 7fd6ab0a2e..b9c2bc6ece 100644 --- a/src/test/java/rx/internal/operators/OperatorGroupByTest.java +++ b/src/test/java/rx/internal/operators/OperatorGroupByTest.java @@ -39,8 +39,10 @@ import rx.functions.*; import rx.internal.util.*; import rx.observables.GroupedObservable; +import rx.observers.AssertableSubscriber; import rx.observers.TestSubscriber; import rx.schedulers.Schedulers; +import rx.subjects.PublishSubject; public class OperatorGroupByTest { @@ -2047,4 +2049,230 @@ public Observable call(GroupedObservable v) { assertTrue("" + c, c > 0); assertTrue("" + c, c < 10000); } + + @Test + public void groupByEvictingMapFactoryThrows() { + final RuntimeException ex = new RuntimeException("boo"); + Func1, Map> evictingMapFactory = // + new Func1, Map>() { + + @Override + public Map call(final Action1 notify) { + throw ex; + } + }; + Observable.just(1) + .groupBy(UtilityFunctions.identity(), UtilityFunctions.identity(), 16, true, evictingMapFactory) + .test() + .assertNoValues() + .assertError(ex); + } + + @Test + public void groupByEvictingMapFactoryExpiryCompletesGroupedFlowable() { + final List completed = new CopyOnWriteArrayList(); + Func1, Map> evictingMapFactory = createEvictingMapFactorySynchronousOnly(1); + PublishSubject subject = PublishSubject.create(); + AssertableSubscriber ts = subject + .groupBy(UtilityFunctions.identity(), UtilityFunctions.identity(), 16, true, evictingMapFactory) + .flatMap(addCompletedKey(completed)) + .test(); + subject.onNext(1); + subject.onNext(2); + subject.onNext(3); + ts.assertValues(1, 2, 3) + .assertNoTerminalEvent(); + assertEquals(Arrays.asList(1, 2), completed); + //ensure coverage of the code that clears the evicted queue + subject.onCompleted(); + ts.assertCompleted(); + ts.assertValueCount(3); + } + + private static final Func1 mod5 = new Func1() { + + @Override + public Integer call(Integer n) { + return n % 5; + } + }; + + @Test + public void groupByEvictingMapFactoryWithExpiringGuavaCacheDemonstrationCodeForUseInJavadoc() { + //javadoc will be a version of this using lambdas and without assertions + final List completed = new CopyOnWriteArrayList(); + //size should be less than 5 to notice the effect + Func1, Map> evictingMapFactory = createEvictingMapFactoryGuava(3); + int numValues = 1000; + Observable.range(1, numValues) + .groupBy(mod5, UtilityFunctions.identity(), 16, true, evictingMapFactory) + .flatMap(addCompletedKey(completed)) + .test() + .assertCompleted() + .assertValueCount(numValues); + //the exact eviction behaviour of the guava cache is not specified so we make some approximate tests + assertTrue(completed.size() > numValues * 0.9); + } + + @Test + public void groupByEvictingMapFactoryEvictionQueueClearedOnErrorCoverageOnly() { + Func1, Map> evictingMapFactory = createEvictingMapFactorySynchronousOnly(1); + PublishSubject subject = PublishSubject.create(); + AssertableSubscriber ts = subject + .groupBy(UtilityFunctions.identity(), UtilityFunctions.identity(), 16, true, evictingMapFactory) + .flatMap(new Func1, Observable>() { + @Override + public Observable call(GroupedObservable g) { + return g; + } + }) + .test(); + RuntimeException ex = new RuntimeException(); + //ensure coverage of the code that clears the evicted queue + subject.onError(ex); + ts.assertNoValues() + .assertError(ex); + } + + private static Func1, Observable> addCompletedKey( + final List completed) { + return new Func1, Observable>() { + @Override + public Observable call(final GroupedObservable g) { + return g.doOnCompleted(new Action0() { + @Override + public void call() { + completed.add(g.getKey()); + } + }); + } + }; + } + + //not thread safe + private static final class SingleThreadEvictingHashMap implements Map { + + private final List list = new ArrayList(); + private final Map map = new HashMap(); + private final int maxSize; + private final Action1 evictedListener; + + SingleThreadEvictingHashMap(int maxSize, Action1 evictedListener) { + this.maxSize = maxSize; + this.evictedListener = evictedListener; + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + @Override + public V get(Object key) { + return map.get(key); + } + + @Override + public V put(K key, V value) { + list.remove(key); + V v; + if (maxSize > 0 && list.size() == maxSize) { + //remove first + K k = list.get(0); + list.remove(0); + v = map.remove(k); + } else { + v = null; + } + list.add(key); + V result = map.put(key, value); + if (v != null) { + evictedListener.call(v); + } + return result; + } + + @Override + public V remove(Object key) { + list.remove(key); + return map.remove(key); + } + + @Override + public void putAll(Map m) { + for (Entry entry: m.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + @Override + public void clear() { + list.clear(); + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + @Override + public Set> entrySet() { + return map.entrySet(); + } + } + + private static Func1, Map> createEvictingMapFactoryGuava(final int maxSize) { + Func1, Map> evictingMapFactory = // + new Func1, Map>() { + + @Override + public Map call(final Action1 notify) { + return CacheBuilder.newBuilder() // + .maximumSize(maxSize) // + .removalListener(new RemovalListener() { + @Override + public void onRemoval(RemovalNotification notification) { + notify.call(notification.getValue()); + }}) + . build() + .asMap(); + }}; + return evictingMapFactory; + } + + private static Func1, Map> createEvictingMapFactorySynchronousOnly(final int maxSize) { + Func1, Map> evictingMapFactory = // + new Func1, Map>() { + + @Override + public Map call(final Action1 notify) { + return new SingleThreadEvictingHashMap(maxSize, new Action1() { + @Override + public void call(Object object) { + notify.call(object); + }}); + }}; + return evictingMapFactory; + } } From 0641802a4ff9429abc96fb02e926cddcff6ce7e7 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Wed, 21 Mar 2018 17:44:07 +0100 Subject: [PATCH 70/74] Release 1.3.7 --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 792c803ece..40d826708e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # RxJava Releases # +### Version 1.3.7 - March 21, 2018 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.7%7C)) + +#### Bugfixes + +- [Pull 5917](https://github.com/ReactiveX/RxJava/pull/5917): Fix and deprecate evicting `groupBy` and add a new overload with the corrected signature. + ### Version 1.3.6 - February 15, 2018 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.6%7C)) #### Bugfixes From 3aad9a62ff1db8904812085cb1818eb13f652ecc Mon Sep 17 00:00:00 2001 From: David Karnok Date: Mon, 26 Mar 2018 15:45:52 +0200 Subject: [PATCH 71/74] 1.x: Fix take() to route late errors to RxJavaHooks (#5935) --- .../rx/internal/operators/OperatorTake.java | 3 ++ .../internal/operators/OperatorTakeTest.java | 40 ++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/main/java/rx/internal/operators/OperatorTake.java b/src/main/java/rx/internal/operators/OperatorTake.java index 0be75b4f2c..d49f155d9d 100644 --- a/src/main/java/rx/internal/operators/OperatorTake.java +++ b/src/main/java/rx/internal/operators/OperatorTake.java @@ -19,6 +19,7 @@ import rx.*; import rx.Observable.Operator; +import rx.plugins.RxJavaHooks; /** * An {@code Observable} that emits the first {@code num} items emitted by the source {@code Observable}. @@ -66,6 +67,8 @@ public void onError(Throwable e) { } finally { unsubscribe(); } + } else { + RxJavaHooks.onError(e); } } diff --git a/src/test/java/rx/internal/operators/OperatorTakeTest.java b/src/test/java/rx/internal/operators/OperatorTakeTest.java index edf17bac10..0885a8b343 100644 --- a/src/test/java/rx/internal/operators/OperatorTakeTest.java +++ b/src/test/java/rx/internal/operators/OperatorTakeTest.java @@ -19,7 +19,7 @@ import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; -import java.util.Arrays; +import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -27,10 +27,13 @@ import org.mockito.InOrder; import rx.*; +import rx.Observable; import rx.Observable.OnSubscribe; +import rx.Observer; import rx.exceptions.TestException; import rx.functions.*; import rx.observers.*; +import rx.plugins.RxJavaHooks; import rx.schedulers.Schedulers; import rx.subjects.PublishSubject; @@ -457,4 +460,39 @@ public void takeZero() { ts.assertCompleted(); } + @Test + public void crashReportedToHooks() { + final List errors = Collections.synchronizedList(new ArrayList()); + RxJavaHooks.setOnError(new Action1() { + @Override + public void call(Throwable error) { + errors.add(error); + } + }); + + try { + Observable.just("1") + .take(1) + .toSingle() + .subscribe( + new Action1() { + @Override + public void call(String it) { + throw new TestException("bla"); + } + }, + new Action1() { + @Override + public void call(Throwable error) { + errors.add(new AssertionError()); + } + } + ); + + assertEquals("" + errors, 1, errors.size()); + assertTrue("" + errors.get(0), errors.get(0).getMessage().equals("bla")); + } finally { + RxJavaHooks.setOnError(null); + } + } } From 7e3879abfb32eeebb38c970195a7f1e354eb1f82 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sat, 31 Mar 2018 17:27:03 +0200 Subject: [PATCH 72/74] Release 1.3.8 --- CHANGES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 40d826708e..31299c26f8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,15 @@ # RxJava Releases # +### Version 1.3.8 - March 31, 2018 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.8%7C)) + +RxJava 1.x is now officially **end-of-life (EOL)**. No further developments, bugfixes, enhancements, javadoc changes, maintenance will be provided by this project after version **1.3.8**. + +Users are encourage to [migrate to 2.x](https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0). In accordance, the wiki will be updated in the coming months to describe 2.x features and properties. + +#### Bugfixes + +- [Pull 5935](https://github.com/ReactiveX/RxJava/pull/5935): Fix `take()` to route late errors to `RxJavaHooks`. + ### Version 1.3.7 - March 21, 2018 ([Maven](http://search.maven.org/#artifactdetails%7Cio.reactivex%7Crxjava%7C1.3.7%7C)) #### Bugfixes From 2ea5f309484d395efd3cac49a8e4b18e4302d061 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Sat, 31 Mar 2018 17:44:28 +0200 Subject: [PATCH 73/74] 1.x: readme update about EOL --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 3525242ea4..21176e556d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # RxJava: Reactive Extensions for the JVM +## End-of-Life notice + +As of March 31, 2018, The RxJava 1.x branch and version is end-of-life (EOL). No further development, bugfixes, documentation changes, PRs, releases or maintenance will be performed by the project on the 1.x line. + +Users are encouraged to migrate to [2.x](https://github.com/ReactiveX/RxJava) which is currently the only official RxJava version being managed. + +---------------------------------- + [![codecov.io](http://codecov.io/github/ReactiveX/RxJava/coverage.svg?branch=1.x)](http://codecov.io/github/ReactiveX/RxJava?branch=1.x) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.reactivex/rxjava/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.reactivex/rxjava) From a62edb68aa37899320661225ea4944b1b73ab802 Mon Sep 17 00:00:00 2001 From: David Karnok Date: Tue, 2 Mar 2021 12:59:56 +0100 Subject: [PATCH 74/74] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21176e556d..a0eabf5886 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ As of March 31, 2018, The RxJava 1.x branch and version is end-of-life (EOL). No further development, bugfixes, documentation changes, PRs, releases or maintenance will be performed by the project on the 1.x line. -Users are encouraged to migrate to [2.x](https://github.com/ReactiveX/RxJava) which is currently the only official RxJava version being managed. +Users are encouraged to migrate to [3.x](https://github.com/ReactiveX/RxJava) which is currently the only official RxJava version being managed. ----------------------------------