15
15
*/
16
16
package rx .util ;
17
17
18
- import java .util .concurrent .atomic .AtomicBoolean ;
18
+ import org .junit .Test ;
19
+ import rx .Subscription ;
20
+
19
21
import java .util .concurrent .atomic .AtomicReference ;
20
22
21
- import rx .Subscription ;
23
+ import static org .mockito .Mockito .mock ;
24
+ import static org .mockito .Mockito .times ;
25
+ import static org .mockito .Mockito .verify ;
22
26
23
27
/**
24
28
* Thread-safe wrapper around Observable Subscription that ensures unsubscribe can be called only once.
32
36
*/
33
37
public final class AtomicObservableSubscription implements Subscription {
34
38
35
- private AtomicReference <Subscription > actualSubscription = new AtomicReference <Subscription >();
36
- private AtomicBoolean unsubscribed = new AtomicBoolean (false );
39
+ private static final Subscription UNSUBSCRIBED = new Subscription ()
40
+ {
41
+ @ Override
42
+ public void unsubscribe ()
43
+ {
44
+ }
45
+ };
46
+ private final AtomicReference <Subscription > actualSubscription = new AtomicReference <Subscription >();
37
47
38
48
public AtomicObservableSubscription () {
39
-
40
49
}
41
50
42
51
public AtomicObservableSubscription (Subscription actualSubscription ) {
@@ -46,12 +55,16 @@ public AtomicObservableSubscription(Subscription actualSubscription) {
46
55
/**
47
56
* Wraps the actual subscription once it exists (if it wasn't available when constructed)
48
57
*
49
- * @param actualSubscription
58
+ * @param actualSubscription the wrapped subscription
50
59
* @throws IllegalStateException
51
60
* if trying to set more than once (or use this method after setting via constructor)
52
61
*/
53
62
public AtomicObservableSubscription wrap (Subscription actualSubscription ) {
54
63
if (!this .actualSubscription .compareAndSet (null , actualSubscription )) {
64
+ if (this .actualSubscription .get () == UNSUBSCRIBED ) {
65
+ actualSubscription .unsubscribe ();
66
+ return this ;
67
+ }
55
68
throw new IllegalStateException ("Can not set subscription more than once." );
56
69
}
57
70
return this ;
@@ -60,15 +73,25 @@ public AtomicObservableSubscription wrap(Subscription actualSubscription) {
60
73
@ Override
61
74
public void unsubscribe () {
62
75
// get the real thing and set to null in an atomic operation so we will only ever call unsubscribe once
63
- Subscription actual = actualSubscription .getAndSet (null );
76
+ Subscription actual = actualSubscription .getAndSet (UNSUBSCRIBED );
64
77
// if it's not null we will unsubscribe
65
78
if (actual != null ) {
66
79
actual .unsubscribe ();
67
- unsubscribed .set (true );
68
80
}
69
81
}
70
82
71
83
public boolean isUnsubscribed () {
72
- return unsubscribed .get ();
84
+ return actualSubscription .get () == UNSUBSCRIBED ;
85
+ }
86
+
87
+ public static class UnitTest {
88
+ @ Test
89
+ public void testWrapAfterUnsubscribe () {
90
+ AtomicObservableSubscription atomicObservableSubscription = new AtomicObservableSubscription ();
91
+ atomicObservableSubscription .unsubscribe ();
92
+ Subscription innerSubscription = mock (Subscription .class );
93
+ atomicObservableSubscription .wrap (innerSubscription );
94
+ verify (innerSubscription , times (1 )).unsubscribe ();
95
+ }
73
96
}
74
97
}
0 commit comments