/**
* Copyright 2009-2016 the original author or authors.
*
* 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 net.javacrumbs.futureconverter.rxjava2common;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.disposables.Disposable;
import net.javacrumbs.futureconverter.common.internal.ValueSource;
import java.util.function.Consumer;
public class RxJava2FutureUtils {
public static <T> Single<T> createSingle(ValueSource<T> valueSource) {
if (valueSource instanceof SingleBackedValueSource) {
return ((SingleBackedValueSource<T>) valueSource).getSingle();
}
return new ValueSourceBackedSingle<>(valueSource);
}
public static <T> ValueSource<T> createValueSource(Single<T> single) {
if (single instanceof ValueSourceBackedSingle) {
return ((ValueSourceBackedSingle<T>) single).getValueSource();
} else {
return new SingleBackedValueSource<>(single);
}
}
private static class SingleBackedValueSource<T> implements ValueSource<T> {
private final Single<T> single;
private Disposable disposable;
private SingleBackedValueSource(Single<T> single) {
this.single = single;
}
@Override
public void addCallbacks(Consumer<T> successCallback, Consumer<Throwable> failureCallback) {
if (disposable == null) {
disposable = single.subscribe(successCallback::accept, failureCallback::accept);
} else {
throw new IllegalStateException("add callbacks can be called only once");
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
disposable.dispose();
return true;
}
private Single<T> getSingle() {
return single;
}
}
private static class ValueSourceBackedSingle<T> extends Single<T> {
private final ValueSource<T> valueSource;
ValueSourceBackedSingle(ValueSource<T> valueSource) {
this.valueSource = valueSource;
}
@Override
protected void subscribeActual(SingleObserver<? super T> observer) {
ValueSourceDisposable disposable = new ValueSourceDisposable();
valueSource.addCallbacks(
result -> {
try {
observer.onSuccess(result);
} catch (Throwable e) {
observer.onError(e);
}
},
ex -> {
if (!disposable.isDisposed()) {
observer.onError(ex);
}
}
);
observer.onSubscribe(disposable);
}
private ValueSource<T> getValueSource() {
return valueSource;
}
private class ValueSourceDisposable implements Disposable {
private volatile boolean disposed = false;
@Override
public void dispose() {
disposed = true;
valueSource.cancel(true);
}
@Override
public boolean isDisposed() {
return disposed;
}
}
}
}