rx.internal.operators.OnSubscribeUsing Maven / Gradle / Ivy
/**
* 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.internal.operators;
import java.util.concurrent.atomic.AtomicBoolean;
import rx.*;
import rx.Observable.OnSubscribe;
import rx.exceptions.*;
import rx.functions.*;
import rx.observers.Subscribers;
/**
* Constructs an observable sequence that depends on a resource object.
*
* @param the output value type
* @param the resource type
*/
public final class OnSubscribeUsing implements OnSubscribe {
private final Func0 resourceFactory;
private final Func1 super Resource, ? extends Observable extends T>> observableFactory;
private final Action1 super Resource> dispose;
private final boolean disposeEagerly;
public OnSubscribeUsing(Func0 resourceFactory,
Func1 super Resource, ? extends Observable extends T>> observableFactory,
Action1 super Resource> dispose, boolean disposeEagerly) {
this.resourceFactory = resourceFactory;
this.observableFactory = observableFactory;
this.dispose = dispose;
this.disposeEagerly = disposeEagerly;
}
@Override
public void call(final Subscriber super T> subscriber) {
try {
// create the resource
final Resource resource = resourceFactory.call();
// create an action/subscription that disposes only once
final DisposeAction disposeOnceOnly = new DisposeAction(dispose,
resource);
// dispose on unsubscription
subscriber.add(disposeOnceOnly);
// create the observable
Observable extends T> source;
try {
source = observableFactory
// create the observable
.call(resource);
} catch (Throwable e) {
Throwable disposeError = dispose(disposeOnceOnly);
Exceptions.throwIfFatal(e);
Exceptions.throwIfFatal(disposeError);
if (disposeError != null) {
subscriber.onError(new CompositeException(e, disposeError));
} else {
// propagate error
subscriber.onError(e);
}
return;
}
Observable extends T> observable;
// supplement with on termination disposal if requested
if (disposeEagerly) {
observable = source
// dispose on completion or error
.doOnTerminate(disposeOnceOnly);
} else {
observable = source
// dispose after the terminal signals were sent out
.doAfterTerminate(disposeOnceOnly);
}
try {
// start
observable.unsafeSubscribe(Subscribers.wrap(subscriber));
} catch (Throwable e) {
Throwable disposeError = dispose(disposeOnceOnly);
Exceptions.throwIfFatal(e);
Exceptions.throwIfFatal(disposeError);
if (disposeError != null) {
subscriber.onError(new CompositeException(e, disposeError));
} else {
// propagate error
subscriber.onError(e);
}
}
} catch (Throwable e) {
// then propagate error
Exceptions.throwOrReport(e, subscriber);
}
}
private Throwable dispose(final Action0 disposeOnceOnly) {
try {
disposeOnceOnly.call();
return null;
} catch (Throwable e) {
return e;
}
}
static final class DisposeAction extends AtomicBoolean implements Action0,
Subscription {
private static final long serialVersionUID = 4262875056400218316L;
private Action1 super Resource> dispose;
private Resource resource;
DisposeAction(Action1 super Resource> dispose, Resource resource) {
this.dispose = dispose;
this.resource = resource;
lazySet(false); // StoreStore barrier
}
@Override
public void call() {
if (compareAndSet(false, true)) {
try {
dispose.call(resource);
} finally {
resource = null;
dispose = null;
}
}
}
@Override
public boolean isUnsubscribed() {
return get();
}
@Override
public void unsubscribe() {
call();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy