Browse Source
No need for rxjava-reactive-streams dependency and CompletableFutureUtils anymore.pull/1111/head
Sebastien Deleuze
9 years ago
8 changed files with 40 additions and 286 deletions
@ -1,156 +0,0 @@
@@ -1,156 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2015 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 org.springframework.reactive.util; |
||||
|
||||
import org.reactivestreams.Publisher; |
||||
import org.reactivestreams.Subscriber; |
||||
import org.reactivestreams.Subscription; |
||||
import org.springframework.util.Assert; |
||||
import reactor.Publishers; |
||||
import reactor.core.error.CancelException; |
||||
import reactor.core.error.Exceptions; |
||||
import reactor.core.support.BackpressureUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.concurrent.CompletableFuture; |
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater; |
||||
|
||||
/** |
||||
* @author Sebastien Deleuze |
||||
* @author Stephane Maldini |
||||
*/ |
||||
public class CompletableFutureUtils { |
||||
|
||||
public static <T> Publisher<T> toPublisher(CompletableFuture<T> future) { |
||||
return new CompletableFuturePublisher<T>(future); |
||||
} |
||||
|
||||
public static <T> CompletableFuture<List<T>> fromPublisher(Publisher<T> publisher) { |
||||
final CompletableFuture<List<T>> future = new CompletableFuture<>(); |
||||
publisher.subscribe(new Subscriber<T>() { |
||||
private final List<T> values = new ArrayList<>(); |
||||
|
||||
@Override |
||||
public void onSubscribe(Subscription s) { |
||||
s.request(Long.MAX_VALUE); |
||||
} |
||||
|
||||
@Override |
||||
public void onNext(T t) { |
||||
values.add(t); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Throwable t) { |
||||
future.completeExceptionally(t); |
||||
} |
||||
|
||||
@Override |
||||
public void onComplete() { |
||||
future.complete(values); |
||||
} |
||||
}); |
||||
return future; |
||||
} |
||||
|
||||
public static <T> CompletableFuture<T> fromSinglePublisher(Publisher<T> publisher) { |
||||
final CompletableFuture<T> future = new CompletableFuture<>(); |
||||
publisher.subscribe(new Subscriber<T>() { |
||||
private T value; |
||||
|
||||
@Override |
||||
public void onSubscribe(Subscription s) { |
||||
s.request(Long.MAX_VALUE); |
||||
} |
||||
|
||||
@Override |
||||
public void onNext(T t) { |
||||
Assert.state(value == null, "This publisher should not publish multiple values"); |
||||
value = t; |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Throwable t) { |
||||
future.completeExceptionally(t); |
||||
} |
||||
|
||||
@Override |
||||
public void onComplete() { |
||||
future.complete(value); |
||||
} |
||||
}); |
||||
return future; |
||||
} |
||||
|
||||
private static class CompletableFuturePublisher<T> implements Publisher<T> { |
||||
|
||||
private final CompletableFuture<? extends T> future; |
||||
private final Publisher<? extends T> futurePublisher; |
||||
|
||||
@SuppressWarnings("unused") |
||||
private volatile long requested; |
||||
private static final AtomicLongFieldUpdater<CompletableFuturePublisher> REQUESTED = |
||||
AtomicLongFieldUpdater.newUpdater(CompletableFuturePublisher.class, "requested"); |
||||
|
||||
public CompletableFuturePublisher(CompletableFuture<? extends T> future) { |
||||
this.future = future; |
||||
this.futurePublisher = Publishers.createWithDemand((n, sub) -> { |
||||
|
||||
if (!BackpressureUtils.checkRequest(n, sub)) { |
||||
return; |
||||
} |
||||
|
||||
if(BackpressureUtils.getAndAdd(REQUESTED, CompletableFuturePublisher.this, n) > 0) { |
||||
return; |
||||
} |
||||
|
||||
future.whenComplete((result, error) -> { |
||||
if (error != null) { |
||||
sub.onError(error); |
||||
} else { |
||||
sub.onNext(result); |
||||
sub.onComplete(); |
||||
} |
||||
}); |
||||
}, null, nothing -> { |
||||
if(!future.isDone()){ |
||||
future.cancel(true); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void subscribe(final Subscriber<? super T> subscriber) { |
||||
try { |
||||
if (future.isDone()) { |
||||
Publishers.just(future.get()).subscribe(subscriber); |
||||
} |
||||
else if ( future.isCancelled()){ |
||||
Exceptions.publisher(CancelException.get()); |
||||
} |
||||
else { |
||||
futurePublisher.subscribe(subscriber); |
||||
} |
||||
} |
||||
catch (Throwable throwable) { |
||||
Exceptions.publisher(throwable); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,101 +0,0 @@
@@ -1,101 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2015 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 org.springframework.reactive.util; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.concurrent.CompletableFuture; |
||||
import java.util.concurrent.CountDownLatch; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertTrue; |
||||
import org.junit.Test; |
||||
import org.reactivestreams.Publisher; |
||||
import org.reactivestreams.Subscriber; |
||||
import org.reactivestreams.Subscription; |
||||
import reactor.rx.Streams; |
||||
|
||||
/** |
||||
* @author Sebastien Deleuze |
||||
*/ |
||||
public class CompletableFutureUtilsTests { |
||||
|
||||
private CountDownLatch lock = new CountDownLatch(1); |
||||
private final List<Boolean> results = new ArrayList<>(); |
||||
private final List<Throwable> errors = new ArrayList<>(); |
||||
|
||||
@Test |
||||
public void fromPublisher() throws InterruptedException { |
||||
Publisher<Boolean> publisher = Streams.just(true, false); |
||||
CompletableFuture<List<Boolean>> future = CompletableFutureUtils.fromPublisher(publisher); |
||||
future.whenComplete((result, error) -> { |
||||
if (error != null) { |
||||
errors.add(error); |
||||
} |
||||
else { |
||||
results.addAll(result); |
||||
} |
||||
lock.countDown(); |
||||
}); |
||||
lock.await(2000, TimeUnit.MILLISECONDS); |
||||
assertEquals("onError not expected: " + errors.toString(), 0, errors.size()); |
||||
assertEquals(2, results.size()); |
||||
assertTrue(results.get(0)); |
||||
assertFalse(results.get(1)); |
||||
} |
||||
|
||||
@Test |
||||
public void fromSinglePublisher() throws InterruptedException { |
||||
Publisher<Boolean> publisher = Streams.just(true); |
||||
CompletableFuture<Boolean> future = CompletableFutureUtils.fromSinglePublisher(publisher); |
||||
future.whenComplete((result, error) -> { |
||||
if (error != null) { |
||||
errors.add(error); |
||||
} |
||||
else { |
||||
results.add(result); |
||||
} |
||||
lock.countDown(); |
||||
}); |
||||
lock.await(2000, TimeUnit.MILLISECONDS); |
||||
assertEquals("onError not expected: " + errors.toString(), 0, errors.size()); |
||||
assertEquals(1, results.size()); |
||||
assertTrue(results.get(0)); |
||||
} |
||||
|
||||
@Test |
||||
public void fromSinglePublisherWithMultipleValues() throws InterruptedException { |
||||
Publisher<Boolean> publisher = Streams.just(true, false); |
||||
CompletableFuture<Boolean> future = CompletableFutureUtils.fromSinglePublisher(publisher); |
||||
future.whenComplete((result, error) -> { |
||||
if (error != null) { |
||||
errors.add(error); |
||||
} |
||||
else { |
||||
results.add(result); |
||||
} |
||||
lock.countDown(); |
||||
}); |
||||
lock.await(2000, TimeUnit.MILLISECONDS); |
||||
assertEquals(1, errors.size()); |
||||
assertEquals(IllegalStateException.class, errors.get(0).getClass()); |
||||
assertEquals(0, results.size()); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue