rx.subscriptions.CompositeSubscription Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rxjava-core Show documentation
Show all versions of rxjava-core Show documentation
rxjava-core developed by Netflix
/**
* 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.subscriptions;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import rx.Subscription;
import rx.exceptions.CompositeException;
/**
* Subscription that represents a group of Subscriptions that are unsubscribed
* together.
*
* @see Rx.Net equivalent CompositeDisposable
*/
public final class CompositeSubscription implements Subscription {
private final AtomicReference state = new AtomicReference();
/** Empty initial state. */
private static final State CLEAR_STATE;
/** Unsubscribed empty state. */
private static final State CLEAR_STATE_UNSUBSCRIBED;
static {
Subscription[] s0 = new Subscription[0];
CLEAR_STATE = new State(false, s0);
CLEAR_STATE_UNSUBSCRIBED = new State(true, s0);
}
private static final class State {
final boolean isUnsubscribed;
final Subscription[] subscriptions;
State(boolean u, Subscription[] s) {
this.isUnsubscribed = u;
this.subscriptions = s;
}
State unsubscribe() {
return CLEAR_STATE_UNSUBSCRIBED;
}
State add(Subscription s) {
int idx = subscriptions.length;
Subscription[] newSubscriptions = new Subscription[idx + 1];
System.arraycopy(subscriptions, 0, newSubscriptions, 0, idx);
newSubscriptions[idx] = s;
return new State(isUnsubscribed, newSubscriptions);
}
State remove(Subscription s) {
if ((subscriptions.length == 1 && subscriptions[0].equals(s)) || subscriptions.length == 0) {
return clear();
}
Subscription[] newSubscriptions = new Subscription[subscriptions.length - 1];
int idx = 0;
for (Subscription _s : subscriptions) {
if (!_s.equals(s)) {
// was not in this composite
if (idx == subscriptions.length) {
return this;
}
newSubscriptions[idx] = _s;
idx++;
}
}
if (idx == 0) {
return clear();
}
// subscription appeared more than once
if (idx < newSubscriptions.length) {
Subscription[] newSub2 = new Subscription[idx];
System.arraycopy(newSubscriptions, 0, newSub2, 0, idx);
return new State(isUnsubscribed, newSub2);
}
return new State(isUnsubscribed, newSubscriptions);
}
State clear() {
return isUnsubscribed ? CLEAR_STATE_UNSUBSCRIBED : CLEAR_STATE;
}
}
public CompositeSubscription() {
state.set(CLEAR_STATE);
}
public CompositeSubscription(final Subscription... subscriptions) {
state.set(new State(false, subscriptions));
}
@Override
public boolean isUnsubscribed() {
return state.get().isUnsubscribed;
}
public void add(final Subscription s) {
State oldState;
State newState;
do {
oldState = state.get();
if (oldState.isUnsubscribed) {
s.unsubscribe();
return;
} else {
newState = oldState.add(s);
}
} while (!state.compareAndSet(oldState, newState));
}
public void remove(final Subscription s) {
State oldState;
State newState;
do {
oldState = state.get();
if (oldState.isUnsubscribed) {
return;
} else {
newState = oldState.remove(s);
}
} while (!state.compareAndSet(oldState, newState));
// if we removed successfully we then need to call unsubscribe on it
s.unsubscribe();
}
public void clear() {
State oldState;
State newState;
do {
oldState = state.get();
if (oldState.isUnsubscribed) {
return;
} else {
newState = oldState.clear();
}
} while (!state.compareAndSet(oldState, newState));
// if we cleared successfully we then need to call unsubscribe on all previous
unsubscribeFromAll(oldState.subscriptions);
}
@Override
public void unsubscribe() {
State oldState;
State newState;
do {
oldState = state.get();
if (oldState.isUnsubscribed) {
return;
} else {
newState = oldState.unsubscribe();
}
} while (!state.compareAndSet(oldState, newState));
unsubscribeFromAll(oldState.subscriptions);
}
private static void unsubscribeFromAll(Subscription[] subscriptions) {
final List es = new ArrayList();
for (Subscription s : subscriptions) {
try {
s.unsubscribe();
} catch (Throwable e) {
es.add(e);
}
}
if (!es.isEmpty()) {
if (es.size() == 1) {
Throwable t = es.get(0);
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new CompositeException(
"Failed to unsubscribe to 1 or more subscriptions.", es);
}
} else {
throw new CompositeException(
"Failed to unsubscribe to 2 or more subscriptions.", es);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy