1
+ /**
2
+ * Copyright 2013 Netflix, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
1
16
package rx .operators ;
2
17
3
18
import org .junit .Test ;
9
24
import rx .subjects .Subject ;
10
25
import rx .util .functions .Func1 ;
11
26
27
+ import javax .annotation .concurrent .GuardedBy ;
28
+
12
29
import static org .mockito .Mockito .*;
13
30
14
31
public class OperatorMulticast {
15
32
public static <T , R > ConnectableObservable <R > multicast (Observable <T > source , final Subject <T , R > subject ) {
16
- return new MulticastConnectableObservable <T , R >(source , subject );
33
+ return new MulticastConnectableObservable <T , R >(source , subject );
17
34
}
18
35
19
36
private static class MulticastConnectableObservable <T , R > extends ConnectableObservable <R > {
37
+ private final Object lock = new Object ();
38
+
20
39
private final Observable <T > source ;
21
40
private final Subject <T , R > subject ;
22
41
42
+ @ GuardedBy ("lock" )
43
+ private Subscription subscription ;
44
+
23
45
public MulticastConnectableObservable (Observable <T > source , final Subject <T , R > subject ) {
24
46
super (new Func1 <Observer <R >, Subscription >() {
25
47
@ Override
@@ -32,22 +54,39 @@ public Subscription call(Observer<R> observer) {
32
54
}
33
55
34
56
public Subscription connect () {
35
- return source .subscribe (new Observer <T >() {
36
- @ Override
37
- public void onCompleted () {
38
- subject .onCompleted ();
57
+ synchronized (lock ) {
58
+ if (subscription == null ) {
59
+ subscription = source .subscribe (new Observer <T >() {
60
+ @ Override
61
+ public void onCompleted () {
62
+ subject .onCompleted ();
63
+ }
64
+
65
+ @ Override
66
+ public void onError (Exception e ) {
67
+ subject .onError (e );
68
+ }
69
+
70
+ @ Override
71
+ public void onNext (T args ) {
72
+ subject .onNext (args );
73
+ }
74
+ });
39
75
}
76
+ }
40
77
41
- @ Override
42
- public void onError (Exception e ) {
43
- subject .onError (e );
44
- }
45
78
79
+ return new Subscription () {
46
80
@ Override
47
- public void onNext (T args ) {
48
- subject .onNext (args );
81
+ public void unsubscribe () {
82
+ synchronized (lock ) {
83
+ if (subscription != null ) {
84
+ subscription .unsubscribe ();
85
+ subscription = null ;
86
+ }
87
+ }
49
88
}
50
- }) ;
89
+ };
51
90
}
52
91
53
92
@@ -57,8 +96,7 @@ public static class UnitTest {
57
96
58
97
@ Test
59
98
public void testMulticast () {
60
- Subscription s = mock (Subscription .class );
61
- TestObservable source = new TestObservable (s );
99
+ TestObservable source = new TestObservable ();
62
100
63
101
ConnectableObservable <String > multicasted = OperatorMulticast .multicast (source ,
64
102
DefaultSubject .<String >create ());
@@ -83,6 +121,60 @@ public void testMulticast() {
83
121
84
122
}
85
123
124
+ @ Test
125
+ public void testMulticastConnectTwice () {
126
+ TestObservable source = new TestObservable ();
127
+
128
+ ConnectableObservable <String > multicasted = OperatorMulticast .multicast (source ,
129
+ DefaultSubject .<String >create ());
130
+
131
+ Observer <String > observer = mock (Observer .class );
132
+ multicasted .subscribe (observer );
133
+
134
+ source .sendOnNext ("one" );
135
+
136
+ multicasted .connect ();
137
+ multicasted .connect ();
138
+
139
+ source .sendOnNext ("two" );
140
+ source .sendOnCompleted ();
141
+
142
+ verify (observer , never ()).onNext ("one" );
143
+ verify (observer , times (1 )).onNext ("two" );
144
+ verify (observer , times (1 )).onCompleted ();
145
+
146
+ }
147
+
148
+ @ Test
149
+ public void testMulticastDisconnect () {
150
+ TestObservable source = new TestObservable ();
151
+
152
+ ConnectableObservable <String > multicasted = OperatorMulticast .multicast (source ,
153
+ DefaultSubject .<String >create ());
154
+
155
+ Observer <String > observer = mock (Observer .class );
156
+ multicasted .subscribe (observer );
157
+
158
+ source .sendOnNext ("one" );
159
+
160
+ Subscription connection = multicasted .connect ();
161
+ source .sendOnNext ("two" );
162
+
163
+ connection .unsubscribe ();
164
+ source .sendOnNext ("three" );
165
+
166
+ multicasted .connect ();
167
+ source .sendOnNext ("four" );
168
+ source .sendOnCompleted ();
169
+
170
+ verify (observer , never ()).onNext ("one" );
171
+ verify (observer , times (1 )).onNext ("two" );
172
+ verify (observer , never ()).onNext ("three" );
173
+ verify (observer , times (1 )).onNext ("four" );
174
+ verify (observer , times (1 )).onCompleted ();
175
+
176
+ }
177
+
86
178
87
179
private static class TestObservable extends Observable <String > {
88
180
@@ -102,10 +194,29 @@ public void onNext(String args) {
102
194
// Do nothing
103
195
}
104
196
};
105
- Subscription s ;
197
+ Subscription s = new Subscription () {
198
+ @ Override
199
+ public void unsubscribe () {
200
+ observer = new Observer <String >() {
201
+ @ Override
202
+ public void onCompleted () {
203
+ // Do nothing
204
+ }
205
+
206
+ @ Override
207
+ public void onError (Exception e ) {
208
+ // Do nothing
209
+ }
210
+
211
+ @ Override
212
+ public void onNext (String args ) {
213
+ // Do nothing
214
+ }
215
+ };
216
+ }
217
+ };
106
218
107
- public TestObservable (Subscription s ) {
108
- this .s = s ;
219
+ public TestObservable () {
109
220
}
110
221
111
222
/* used to simulate subscription */
0 commit comments