Note that the {@link HttpObject}s in the {@link Publisher} are not released when
+ * {@link Subscription#cancel()} or {@link #abort()} is called. You should add a hook in order to
+ * release the elements. See {@link PublisherBasedStreamMessage} for more information.
*/
static HttpRequest of(RequestHeaders headers, Publisher extends HttpObject> publisher) {
requireNonNull(headers, "headers");
diff --git a/core/src/main/java/com/linecorp/armeria/common/HttpResponse.java b/core/src/main/java/com/linecorp/armeria/common/HttpResponse.java
index 26d229db8d3..c17a4a84a82 100644
--- a/core/src/main/java/com/linecorp/armeria/common/HttpResponse.java
+++ b/core/src/main/java/com/linecorp/armeria/common/HttpResponse.java
@@ -32,6 +32,7 @@
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.errorprone.annotations.FormatMethod;
@@ -43,6 +44,7 @@
import com.linecorp.armeria.common.FixedHttpResponse.TwoElementFixedHttpResponse;
import com.linecorp.armeria.common.annotation.UnstableApi;
import com.linecorp.armeria.common.stream.HttpDecoder;
+import com.linecorp.armeria.common.stream.PublisherBasedStreamMessage;
import com.linecorp.armeria.common.stream.StreamMessage;
import com.linecorp.armeria.common.stream.SubscriptionOption;
import com.linecorp.armeria.common.util.EventLoopCheckingFuture;
@@ -387,6 +389,10 @@ static HttpResponse of(HttpObject... objs) {
/**
* Creates a new HTTP response whose stream is produced from an existing {@link Publisher}.
+ *
+ *
Note that the {@link HttpObject}s in the {@link Publisher} are not released when
+ * {@link Subscription#cancel()} or {@link #abort()} is called. You should add a hook in order to
+ * release the elements. See {@link PublisherBasedStreamMessage} for more information.
*/
static HttpResponse of(Publisher extends HttpObject> publisher) {
requireNonNull(publisher, "publisher");
@@ -400,6 +406,10 @@ static HttpResponse of(Publisher extends HttpObject> publisher) {
/**
* Creates a new HTTP response with the specified headers whose stream is produced from an existing
* {@link Publisher}.
+ *
+ *
Note that the {@link HttpObject}s in the {@link Publisher} are not released when
+ * {@link Subscription#cancel()} or {@link #abort()} is called. You should add a hook in order to
+ * release the elements. See {@link PublisherBasedStreamMessage} for more information.
*/
static HttpResponse of(ResponseHeaders headers, Publisher extends HttpObject> publisher) {
requireNonNull(headers, "headers");
diff --git a/core/src/main/java/com/linecorp/armeria/common/stream/PublisherBasedStreamMessage.java b/core/src/main/java/com/linecorp/armeria/common/stream/PublisherBasedStreamMessage.java
index 840acce9c91..5cc4e80032f 100644
--- a/core/src/main/java/com/linecorp/armeria/common/stream/PublisherBasedStreamMessage.java
+++ b/core/src/main/java/com/linecorp/armeria/common/stream/PublisherBasedStreamMessage.java
@@ -17,6 +17,7 @@
package com.linecorp.armeria.common.stream;
import static com.linecorp.armeria.common.stream.StreamMessageUtil.containsNotifyCancellation;
+import static com.linecorp.armeria.common.stream.StreamMessageUtil.containsWithPooledObjects;
import static com.linecorp.armeria.common.stream.SubscriberUtil.abortedOrLate;
import static com.linecorp.armeria.common.util.Exceptions.throwIfFatal;
import static java.util.Objects.requireNonNull;
@@ -39,6 +40,7 @@
import com.linecorp.armeria.common.util.CompositeException;
import com.linecorp.armeria.common.util.EventLoopCheckingFuture;
import com.linecorp.armeria.internal.common.stream.NoopSubscription;
+import com.linecorp.armeria.unsafe.PooledObjects;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.ImmediateEventExecutor;
@@ -46,6 +48,13 @@
/**
* Adapts a {@link Publisher} into a {@link StreamMessage}.
*
+ *
Note that the elements in the {@link Publisher} are not released when {@link Subscription#cancel()} or
+ * {@link #abort()} is called. So you should add a hook in order to release the elements. You can use
+ * doOnDiscard
+ * if you are using Reactor, or you can use
+ * doOnDispose
+ * if you are using RxJava.
+ *
* @param the type of element signaled
*/
@UnstableApi
@@ -97,24 +106,24 @@ public final long demand() {
@Override
public final void subscribe(Subscriber super T> subscriber, EventExecutor executor) {
- subscribe0(subscriber, executor, false);
+ subscribe0(subscriber, executor, false, false);
}
@Override
public final void subscribe(Subscriber super T> subscriber, EventExecutor executor,
SubscriptionOption... options) {
requireNonNull(options, "options");
-
+ final boolean withPooledObjects = containsWithPooledObjects(options);
final boolean notifyCancellation = containsNotifyCancellation(options);
- subscribe0(subscriber, executor, notifyCancellation);
+ subscribe0(subscriber, executor, withPooledObjects, notifyCancellation);
}
private void subscribe0(Subscriber super T> subscriber, EventExecutor executor,
- boolean notifyCancellation) {
+ boolean withPooledObjects, boolean notifyCancellation) {
requireNonNull(subscriber, "subscriber");
requireNonNull(executor, "executor");
- if (!subscribe1(subscriber, executor, notifyCancellation)) {
+ if (!subscribe1(subscriber, executor, withPooledObjects, notifyCancellation)) {
final AbortableSubscriber oldSubscriber = this.subscriber;
assert oldSubscriber != null;
failLateSubscriber(executor, subscriber, oldSubscriber.subscriber);
@@ -122,8 +131,9 @@ private void subscribe0(Subscriber super T> subscriber, EventExecutor executor
}
private boolean subscribe1(Subscriber super T> subscriber, EventExecutor executor,
- boolean notifyCancellation) {
- final AbortableSubscriber s = new AbortableSubscriber(this, subscriber, executor, notifyCancellation);
+ boolean withPooledObjects, boolean notifyCancellation) {
+ final AbortableSubscriber s =
+ new AbortableSubscriber(this, subscriber, executor, withPooledObjects, notifyCancellation);
if (!subscriberUpdater.compareAndSet(this, null, s)) {
return false;
}
@@ -173,7 +183,7 @@ private void abort0(Throwable cause) {
final AbortableSubscriber abortable = new AbortableSubscriber(this, AbortingSubscriber.get(cause),
ImmediateEventExecutor.INSTANCE,
- false);
+ false, false);
if (!subscriberUpdater.compareAndSet(this, null, abortable)) {
this.subscriber.abort(cause);
return;
@@ -192,6 +202,7 @@ public final CompletableFuture whenComplete() {
static final class AbortableSubscriber implements Subscriber