Repository navigation
Expand file tree
/
Copy pathCompositeSubscription.java
More file actions
146 lines (134 loc) · 4.43 KB
/
Copy pathCompositeSubscription.java
File metadata and controls
146 lines (134 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* 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.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import rx.Subscription;
import rx.exceptions.*;
/**
* Subscription that represents a group of Subscriptions that are unsubscribed together.
*/
public final class CompositeSubscription implements Subscription {
private Set<Subscription> subscriptions;
private boolean unsubscribed = false;
public CompositeSubscription() {
}
public CompositeSubscription(final Subscription... subscriptions) {
this.subscriptions = new HashSet<Subscription>(Arrays.asList(subscriptions));
}
@Override
public synchronized boolean isUnsubscribed() {
return unsubscribed;
}
/**
* Adds a new {@link Subscription} to this {@code CompositeSubscription} if the
* {@code CompositeSubscription} is not yet unsubscribed. If the {@code CompositeSubscription} <em>is</em>
* unsubscribed, {@code add} will indicate this by explicitly unsubscribing the new {@code Subscription} as
* well.
*
* @param s
* the {@link Subscription} to add
*/
public void add(final Subscription s) {
if (s.isUnsubscribed()) {
return;
}
Subscription unsubscribe = null;
synchronized (this) {
if (unsubscribed) {
unsubscribe = s;
} else {
if (subscriptions == null) {
subscriptions = new HashSet<Subscription>(4);
}
subscriptions.add(s);
}
}
if (unsubscribe != null) {
// call after leaving the synchronized block so we're not holding a lock while executing this
unsubscribe.unsubscribe();
}
}
/**
* Removes a {@link Subscription} from this {@code CompositeSubscription}, and unsubscribes the
* {@link Subscription}.
*
* @param s
* the {@link Subscription} to remove
*/
public void remove(final Subscription s) {
boolean unsubscribe = false;
synchronized (this) {
if (unsubscribed || subscriptions == null) {
return;
}
unsubscribe = subscriptions.remove(s);
}
if (unsubscribe) {
// if we removed successfully we then need to call unsubscribe on it (outside of the lock)
s.unsubscribe();
}
}
/**
* Unsubscribes any subscriptions that are currently part of this {@code CompositeSubscription} and remove
* them from the {@code CompositeSubscription} so that the {@code CompositeSubscription} is empty and in
* an unoperative state.
*/
public void clear() {
Collection<Subscription> unsubscribe = null;
synchronized (this) {
if (unsubscribed || subscriptions == null) {
return;
} else {
unsubscribe = subscriptions;
subscriptions = null;
}
}
unsubscribeFromAll(unsubscribe);
}
@Override
public void unsubscribe() {
synchronized (this) {
if (unsubscribed) {
return;
}
unsubscribed = true;
}
// we will only get here once
unsubscribeFromAll(subscriptions);
}
private static void unsubscribeFromAll(Collection<Subscription> subscriptions) {
if (subscriptions == null) {
return;
}
List<Throwable> es = null;
for (Subscription s : subscriptions) {
try {
s.unsubscribe();
} catch (Throwable e) {
if (es == null) {
es = new ArrayList<Throwable>();
}
es.add(e);
}
}
Exceptions.throwIfAny(es);
}
}