1515 */
1616package rx .internal .operators ;
1717
18+ import java .util .Arrays ;
19+ import java .util .concurrent .atomic .AtomicBoolean ;
20+
1821import rx .Observable ;
1922import rx .Observable .OnSubscribe ;
2023import rx .Subscriber ;
24+ import rx .Subscription ;
25+ import rx .exceptions .CompositeException ;
2126import rx .functions .Action0 ;
2227import rx .functions .Action1 ;
2328import rx .functions .Func0 ;
2429import rx .functions .Func1 ;
25- import rx .subscriptions .Subscriptions ;
2630
2731/**
2832 * Constructs an observable sequence that depends on a resource object.
@@ -32,35 +36,103 @@ public final class OnSubscribeUsing<T, Resource> implements OnSubscribe<T> {
3236 private final Func0 <Resource > resourceFactory ;
3337 private final Func1 <? super Resource , ? extends Observable <? extends T >> observableFactory ;
3438 private final Action1 <? super Resource > dispose ;
39+ private final boolean disposeEagerly ;
3540
3641 public OnSubscribeUsing (Func0 <Resource > resourceFactory ,
3742 Func1 <? super Resource , ? extends Observable <? extends T >> observableFactory ,
38- Action1 <? super Resource > dispose ) {
43+ Action1 <? super Resource > dispose , boolean disposeEagerly ) {
3944 this .resourceFactory = resourceFactory ;
4045 this .observableFactory = observableFactory ;
4146 this .dispose = dispose ;
47+ this .disposeEagerly = disposeEagerly ;
4248 }
4349
4450 @ Override
4551 public void call (Subscriber <? super T > subscriber ) {
46- try {
47- final Resource resource = resourceFactory .call ();
48- subscriber .add (Subscriptions .create (new Action0 () {
4952
50- @ Override
51- public void call () {
52- dispose .call (resource );
53- }
53+ try {
5454
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+ }
5885 } catch (Throwable e ) {
59- // eagerly call unsubscribe since this operator is specifically about resource management
60- subscriber .unsubscribe ();
6186 // then propagate error
6287 subscriber .onError (e );
6388 }
6489 }
6590
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+ }
66138}
0 commit comments