15
15
*/
16
16
package rx .internal .operators ;
17
17
18
+ import java .util .Arrays ;
19
+ import java .util .concurrent .atomic .AtomicBoolean ;
20
+
18
21
import rx .Observable ;
19
22
import rx .Observable .OnSubscribe ;
20
23
import rx .Subscriber ;
24
+ import rx .Subscription ;
25
+ import rx .exceptions .CompositeException ;
21
26
import rx .functions .Action0 ;
22
27
import rx .functions .Action1 ;
23
28
import rx .functions .Func0 ;
24
29
import rx .functions .Func1 ;
25
- import rx .subscriptions .Subscriptions ;
26
30
27
31
/**
28
32
* Constructs an observable sequence that depends on a resource object.
@@ -32,35 +36,103 @@ public final class OnSubscribeUsing<T, Resource> implements OnSubscribe<T> {
32
36
private final Func0 <Resource > resourceFactory ;
33
37
private final Func1 <? super Resource , ? extends Observable <? extends T >> observableFactory ;
34
38
private final Action1 <? super Resource > dispose ;
39
+ private final boolean disposeEagerly ;
35
40
36
41
public OnSubscribeUsing (Func0 <Resource > resourceFactory ,
37
42
Func1 <? super Resource , ? extends Observable <? extends T >> observableFactory ,
38
- Action1 <? super Resource > dispose ) {
43
+ Action1 <? super Resource > dispose , boolean disposeEagerly ) {
39
44
this .resourceFactory = resourceFactory ;
40
45
this .observableFactory = observableFactory ;
41
46
this .dispose = dispose ;
47
+ this .disposeEagerly = disposeEagerly ;
42
48
}
43
49
44
50
@ Override
45
51
public void call (Subscriber <? super T > subscriber ) {
46
- try {
47
- final Resource resource = resourceFactory .call ();
48
- subscriber .add (Subscriptions .create (new Action0 () {
49
52
50
- @ Override
51
- public void call () {
52
- dispose .call (resource );
53
- }
53
+ try {
54
54
55
- }));
56
- Observable <? extends T > observable = observableFactory .call (resource );
57
- observable .subscribe (subscriber );
55
+ // create the resource
56
+ final Resource resource = resourceFactory .call ();
57
+ // create an action/subscription that disposes only once
58
+ final DisposeAction <Resource > disposeOnceOnly = new DisposeAction <Resource >(dispose ,
59
+ resource );
60
+ // dispose on unsubscription
61
+ subscriber .add (disposeOnceOnly );
62
+ // create the observable
63
+ final Observable <? extends T > source = observableFactory
64
+ // create the observable
65
+ .call (resource );
66
+ final Observable <? extends T > observable ;
67
+ // supplement with on termination disposal if requested
68
+ if (disposeEagerly )
69
+ observable = source
70
+ // dispose on completion or error
71
+ .doOnTerminate (disposeOnceOnly );
72
+ else
73
+ observable = source ;
74
+ try {
75
+ // start
76
+ observable .unsafeSubscribe (subscriber );
77
+ } catch (Throwable e ) {
78
+ Throwable disposeError = disposeEagerlyIfRequested (disposeOnceOnly );
79
+ if (disposeError != null )
80
+ subscriber .onError (new CompositeException (Arrays .asList (e , disposeError )));
81
+ else
82
+ // propagate error
83
+ subscriber .onError (e );
84
+ }
58
85
} catch (Throwable e ) {
59
- // eagerly call unsubscribe since this operator is specifically about resource management
60
- subscriber .unsubscribe ();
61
86
// then propagate error
62
87
subscriber .onError (e );
63
88
}
64
89
}
65
90
91
+ private Throwable disposeEagerlyIfRequested (final Action0 disposeOnceOnly ) {
92
+ if (disposeEagerly )
93
+ try {
94
+ disposeOnceOnly .call ();
95
+ return null ;
96
+ } catch (Throwable e ) {
97
+ return e ;
98
+ }
99
+ else
100
+ return null ;
101
+ }
102
+
103
+ private static final class DisposeAction <Resource > extends AtomicBoolean implements Action0 ,
104
+ Subscription {
105
+ private static final long serialVersionUID = 4262875056400218316L ;
106
+
107
+ private Action1 <? super Resource > dispose ;
108
+ private Resource resource ;
109
+
110
+ private DisposeAction (Action1 <? super Resource > dispose , Resource resource ) {
111
+ this .dispose = dispose ;
112
+ this .resource = resource ;
113
+ lazySet (false ); // StoreStore barrier
114
+ }
115
+
116
+ @ Override
117
+ public void call () {
118
+ if (compareAndSet (false , true )) {
119
+ try {
120
+ dispose .call (resource );
121
+ } finally {
122
+ resource = null ;
123
+ dispose = null ;
124
+ }
125
+ }
126
+ }
127
+
128
+ @ Override
129
+ public boolean isUnsubscribed () {
130
+ return get ();
131
+ }
132
+
133
+ @ Override
134
+ public void unsubscribe () {
135
+ call ();
136
+ }
137
+ }
66
138
}
0 commit comments