Clean up Future/Promises API (#11575)

Motivation:
The generics for the existing futures, promises, and listeners are too complicated.
This complication comes from the existence of `ChannelPromise` and `ChannelFuture`, which forces listeners to care about the particular _type_ of future being listened on.

Modification:
* Add a `FutureContextListener` which can take a context object as an additional argument. This allows our listeners to have the channel piped through to them, so they don't need to rely on the `ChannelFuture.channel()` method.
* Make the `FutureListener`, along with the `FutureContextListener` sibling, the default listener API, retiring the `GenericFutureListener` since we no longer need to abstract over the type of the future.
* Change all uses of `ChannelPromise` to `Promise<Void>`.
* Change all uses of `ChannelFuture` to `Future<Void>`.
* Change all uses of `GenericFutureListener` to either `FutureListener` or `FutureContextListener` as needed.
* Remove `ChannelFutureListener` and `GenericFutureListener`.
* Introduce a `ChannelFutureListeners` enum to house the constants that previously lived in `ChannelFutureListener`. These constants now implement `FutureContextListener` and take the `Channel` as a context.
* Remove `ChannelPromise` and `ChannelFuture` — all usages now rely on the plain `Future` and `Promise` APIs.
* Add static factory methods to `DefaultPromise` that allow us to create promises that are initialised as successful or failed.
* Remove `CompleteFuture`, `SucceededFuture`, `FailedFuture`, `CompleteChannelFuture`, `SucceededChannelFuture`, and `FailedChannelFuture`.
* Remove `ChannelPromiseNotifier`.

Result:
Cleaner generics and more straight forward code.
This commit is contained in:
Chris Vest 2021-08-20 09:55:16 +02:00 committed by GitHub
parent afd812c3a4
commit 7971a252a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
304 changed files with 3547 additions and 5233 deletions

View File

@ -16,19 +16,20 @@
package io.netty.handler.codec.haproxy;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.ProtocolDetectionResult;
import io.netty.handler.codec.ProtocolDetectionState;
import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol.AddressFamily;
import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol.TransportProtocol;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static io.netty.buffer.Unpooled.*;
import static io.netty.buffer.Unpooled.buffer;
import static io.netty.buffer.Unpooled.copiedBuffer;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -224,7 +225,7 @@ public class HAProxyMessageDecoderTest {
@Test
public void testCloseOnInvalid() {
ChannelFuture closeFuture = ch.closeFuture();
Future<Void> closeFuture = ch.closeFuture();
String header = "GET / HTTP/1.1\r\n";
try {
ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII));

View File

@ -17,24 +17,24 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.net.SocketAddress;
import java.util.Objects;
abstract class DelegatingChannelHandlerContext implements ChannelHandlerContext {
private final ChannelHandlerContext ctx;
DelegatingChannelHandlerContext(ChannelHandlerContext ctx) {
this.ctx = ObjectUtil.checkNotNull(ctx, "ctx");
this.ctx = Objects.requireNonNull(ctx, "ctx");
}
@Override
@ -150,108 +150,108 @@ abstract class DelegatingChannelHandlerContext implements ChannelHandlerContext
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
public Future<Void> bind(SocketAddress localAddress) {
return ctx.bind(localAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
public Future<Void> connect(SocketAddress remoteAddress) {
return ctx.connect(remoteAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return ctx.connect(remoteAddress, localAddress);
}
@Override
public ChannelFuture disconnect() {
public Future<Void> disconnect() {
return ctx.disconnect();
}
@Override
public ChannelFuture close() {
public Future<Void> close() {
return ctx.close();
}
@Override
public ChannelFuture deregister() {
public Future<Void> deregister() {
return ctx.deregister();
}
@Override
public ChannelFuture register() {
public Future<Void> register() {
return ctx.register();
}
@Override
public ChannelFuture register(ChannelPromise promise) {
public Future<Void> register(Promise<Void> promise) {
return ctx.register(promise);
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> bind(SocketAddress localAddress, Promise<Void> promise) {
return ctx.bind(localAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
public Future<Void> connect(SocketAddress remoteAddress, Promise<Void> promise) {
return ctx.connect(remoteAddress, promise);
}
@Override
public ChannelFuture connect(
SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> connect(
SocketAddress remoteAddress, SocketAddress localAddress, Promise<Void> promise) {
return ctx.connect(remoteAddress, localAddress, promise);
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
public Future<Void> disconnect(Promise<Void> promise) {
return ctx.disconnect(promise);
}
@Override
public ChannelFuture close(ChannelPromise promise) {
public Future<Void> close(Promise<Void> promise) {
return ctx.close(promise);
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
public Future<Void> deregister(Promise<Void> promise) {
return ctx.deregister(promise);
}
@Override
public ChannelFuture write(Object msg) {
public Future<Void> write(Object msg) {
return ctx.write(msg);
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
public Future<Void> write(Object msg, Promise<Void> promise) {
return ctx.write(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
public Future<Void> writeAndFlush(Object msg, Promise<Void> promise) {
return ctx.writeAndFlush(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
public Future<Void> writeAndFlush(Object msg) {
return ctx.writeAndFlush(msg);
}
@Override
public ChannelPromise newPromise() {
public Promise<Void> newPromise() {
return ctx.newPromise();
}
@Override
public ChannelFuture newSucceededFuture() {
public Future<Void> newSucceededFuture() {
return ctx.newSucceededFuture();
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
public Future<Void> newFailedFuture(Throwable cause) {
return ctx.newFailedFuture(cause);
}
}

View File

@ -36,7 +36,7 @@ import io.netty.handler.stream.ChunkedInput;
*
* HttpContentChunkedInput httpChunkWriter = new HttpChunkedInput(
* new ChunkedFile(&quot;/tmp/myfile.txt&quot;));
* ChannelFuture sendFileFuture = ctx.write(httpChunkWriter);
* Future&lt;Void&gt; sendFileFuture = ctx.write(httpChunkWriter);
* }
* </pre>
*/

View File

@ -15,8 +15,8 @@
package io.netty.handler.codec.http;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.AsciiString;
import io.netty.util.concurrent.Promise;
import java.net.SocketAddress;
import java.util.Collection;
@ -121,33 +121,33 @@ public class HttpClientUpgradeHandler extends HttpObjectAggregator {
}
@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, Promise<Void> promise) {
ctx.bind(localAddress, promise);
}
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) {
Promise<Void> promise) {
ctx.connect(remoteAddress, localAddress, promise);
}
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
public void disconnect(ChannelHandlerContext ctx, Promise<Void> promise) {
ctx.disconnect(promise);
}
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
public void close(ChannelHandlerContext ctx, Promise<Void> promise) {
ctx.close(promise);
}
@Override
public void register(ChannelHandlerContext ctx, ChannelPromise promise) {
public void register(ChannelHandlerContext ctx, Promise<Void> promise) {
ctx.register(promise);
}
@Override
public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) {
public void deregister(ChannelHandlerContext ctx, Promise<Void> promise) {
ctx.deregister(promise);
}
@ -157,7 +157,7 @@ public class HttpClientUpgradeHandler extends HttpObjectAggregator {
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (!(msg instanceof HttpRequest)) {
ctx.write(msg, promise);
return;

View File

@ -17,14 +17,13 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.MessageAggregator;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.concurrent.Future;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -250,15 +249,15 @@ public class HttpObjectAggregator
// If keep-alive is off and 'Expect: 100-continue' is missing, no need to leave the connection open.
if (oversized instanceof FullHttpMessage ||
!HttpUtil.is100ContinueExpected(oversized) && !HttpUtil.isKeepAlive(oversized)) {
ChannelFuture future = ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate());
future.addListener((ChannelFutureListener) future1 -> {
Future<Void> future = ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate());
future.addListener(future1 -> {
if (!future1.isSuccess()) {
logger.debug("Failed to send a 413 Request Entity Too Large.", future1.cause());
}
ctx.close();
});
} else {
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener((ChannelFutureListener) future -> {
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener(future -> {
if (!future.isSuccess()) {
logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());
ctx.close();

View File

@ -108,7 +108,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
// Bypass the encoder in case of an empty buffer, so that the following idiom works:
//
// ch.write(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
// ch.write(Unpooled.EMPTY_BUFFER).addListener(ch, ChannelFutureListeners.CLOSE);
//
// See https://github.com/netty/netty/issues/2983 for more information.
if (msg instanceof ByteBufConvertible) {

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec.http;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
@ -84,11 +84,11 @@ public class HttpServerExpectContinueHandler implements ChannelHandler {
// the expectation failed so we refuse the request.
HttpResponse rejection = rejectResponse(req);
ReferenceCountUtil.release(msg);
ctx.writeAndFlush(rejection).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
ctx.writeAndFlush(rejection).addListener(ctx.channel(), ChannelFutureListeners.CLOSE_ON_FAILURE);
return;
}
ctx.writeAndFlush(accept).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
ctx.writeAndFlush(accept).addListener(ctx.channel(), ChannelFutureListeners.CLOSE_ON_FAILURE);
req.headers().remove(HttpHeaderNames.EXPECT);
}
}

View File

@ -15,13 +15,16 @@
*/
package io.netty.handler.codec.http;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Promise;
import static io.netty.handler.codec.http.HttpUtil.*;
import static io.netty.handler.codec.http.HttpUtil.isContentLengthSet;
import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
import static io.netty.handler.codec.http.HttpUtil.isTransferEncodingChunked;
import static io.netty.handler.codec.http.HttpUtil.setKeepAlive;
/**
* HttpServerKeepAliveHandler helps close persistent connections when appropriate.
@ -65,7 +68,7 @@ public class HttpServerKeepAliveHandler implements ChannelHandler {
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
// modify message on way out to add headers if needed
if (msg instanceof HttpResponse) {
final HttpResponse response = (HttpResponse) msg;
@ -82,7 +85,7 @@ public class HttpServerKeepAliveHandler implements ChannelHandler {
}
}
if (msg instanceof LastHttpContent && !shouldKeepAlive()) {
promise.addListener(ChannelFutureListener.CLOSE);
promise.addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
}
ctx.write(msg, promise);
}

View File

@ -15,11 +15,11 @@
package io.netty.handler.codec.http;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.ReferenceCounted;
import io.netty.util.concurrent.Future;
import java.util.ArrayList;
import java.util.Collection;
@ -360,7 +360,7 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
// of the write future and receiving data before the pipeline is
// restructured.
try {
final ChannelFuture writeComplete = ctx.writeAndFlush(upgradeResponse);
Future<Void> writeComplete = ctx.writeAndFlush(upgradeResponse);
// Perform the upgrade to the new protocol.
sourceCodec.upgradeFrom(ctx);
upgradeCodec.upgradeTo(ctx, request);
@ -375,7 +375,7 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
// Add the listener last to avoid firing upgrade logic after
// the channel is already closed since the listener may fire
// immediately if the write failed eagerly.
writeComplete.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
writeComplete.addListener(ctx.channel(), ChannelFutureListeners.CLOSE_ON_FAILURE);
} finally {
// Release the event if the upgrade event wasn't fired.
event.release();

View File

@ -15,11 +15,9 @@
*/
package io.netty.handler.codec.http.cors;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
@ -27,6 +25,8 @@ import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -69,7 +69,7 @@ public class CorsHandler implements ChannelHandler {
* config matches a certain origin, the first in the List will be used.
*
* @param configList List of {@link CorsConfig}
* @param isShortCircuit Same as {@link CorsConfig#shortCircuit} but applicable to all supplied configs.
* @param isShortCircuit Same as {@link CorsConfig#isShortCurcuit()} but applicable to all supplied configs.
*/
public CorsHandler(final List<CorsConfig> configList, boolean isShortCircuit) {
checkNonEmpty(configList, "configList");
@ -215,7 +215,7 @@ public class CorsHandler implements ChannelHandler {
}
@Override
public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) {
public void write(final ChannelHandlerContext ctx, final Object msg, Promise<Void> promise) {
if (config != null && config.isCorsSupportEnabled() && msg instanceof HttpResponse) {
final HttpResponse response = (HttpResponse) msg;
if (setOrigin(response)) {
@ -243,9 +243,9 @@ public class CorsHandler implements ChannelHandler {
HttpUtil.setKeepAlive(response, keepAlive);
final ChannelFuture future = ctx.writeAndFlush(response);
Future<Void> future = ctx.writeAndFlush(response);
if (!keepAlive) {
future.addListener(ChannelFutureListener.CLOSE);
future.addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
}
}
}

View File

@ -17,7 +17,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.CorruptedFrameException;
@ -92,7 +92,7 @@ public class Utf8FrameValidator implements ChannelHandler {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause instanceof CorruptedFrameException && ctx.channel().isOpen()) {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
}
ctx.fireExceptionCaught(cause);
}

View File

@ -55,7 +55,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -448,7 +448,7 @@ public class WebSocket08FrameDecoder extends ByteToMessageDecoder
}
closeMessage = new CloseWebSocketFrame(closeStatus, reasonText);
}
ctx.writeAndFlush(closeMessage).addListener(ChannelFutureListener.CLOSE);
ctx.writeAndFlush(closeMessage).addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
}
throw ex;
}

View File

@ -15,16 +15,11 @@
*/
package io.netty.handler.codec.http.websocketx;
import static java.util.Objects.requireNonNull;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundInvoker;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -39,14 +34,17 @@ import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpScheme;
import io.netty.util.NetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.net.URI;
import java.nio.channels.ClosedChannelException;
import java.util.Locale;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import static java.util.Objects.requireNonNull;
/**
* Base class for web socket client handshake implementations
*/
@ -236,7 +234,7 @@ public abstract class WebSocketClientHandshaker {
* @param channel
* Channel
*/
public ChannelFuture handshake(Channel channel) {
public Future<Void> handshake(Channel channel) {
requireNonNull(channel, "channel");
return handshake(channel, channel.newPromise());
}
@ -247,9 +245,9 @@ public abstract class WebSocketClientHandshaker {
* @param channel
* Channel
* @param promise
* the {@link ChannelPromise} to be notified when the opening handshake is sent
* the {@link Promise} to be notified when the opening handshake is sent
*/
public final ChannelFuture handshake(Channel channel, final ChannelPromise promise) {
public final Future<Void> handshake(Channel channel, final Promise<Void> promise) {
ChannelPipeline pipeline = channel.pipeline();
HttpResponseDecoder decoder = pipeline.get(HttpResponseDecoder.class);
if (decoder == null) {
@ -263,9 +261,9 @@ public abstract class WebSocketClientHandshaker {
FullHttpRequest request = newHandshakeRequest();
channel.writeAndFlush(request).addListener((ChannelFutureListener) future -> {
channel.writeAndFlush(request).addListener(channel, (ch, future) -> {
if (future.isSuccess()) {
ChannelPipeline p = future.channel().pipeline();
ChannelPipeline p = ch.pipeline();
ChannelHandlerContext ctx = p.context(HttpRequestEncoder.class);
if (ctx == null) {
ctx = p.context(HttpClientCodec.class);
@ -277,7 +275,7 @@ public abstract class WebSocketClientHandshaker {
}
p.addAfter(ctx.name(), "ws-encoder", newWebSocketEncoder());
promise.setSuccess();
promise.setSuccess(null);
} else {
promise.setFailure(future.cause());
}
@ -384,9 +382,9 @@ public abstract class WebSocketClientHandshaker {
* @param response
* HTTP response containing the closing handshake details
* @return future
* the {@link ChannelFuture} which is notified once the handshake completes.
* the {@link Future} which is notified once the handshake completes.
*/
public final ChannelFuture processHandshake(final Channel channel, HttpResponse response) {
public final Future<Void> processHandshake(final Channel channel, HttpResponse response) {
return processHandshake(channel, response, channel.newPromise());
}
@ -398,16 +396,16 @@ public abstract class WebSocketClientHandshaker {
* @param response
* HTTP response containing the closing handshake details
* @param promise
* the {@link ChannelPromise} to notify once the handshake completes.
* the {@link Promise} to notify once the handshake completes.
* @return future
* the {@link ChannelFuture} which is notified once the handshake completes.
* the {@link Future} which is notified once the handshake completes.
*/
public final ChannelFuture processHandshake(final Channel channel, HttpResponse response,
final ChannelPromise promise) {
public final Future<Void> processHandshake(final Channel channel, HttpResponse response,
final Promise<Void> promise) {
if (response instanceof FullHttpResponse) {
try {
finishHandshake(channel, (FullHttpResponse) response);
promise.setSuccess();
promise.setSuccess(null);
} catch (Throwable cause) {
promise.setFailure(cause);
}
@ -434,7 +432,7 @@ public abstract class WebSocketClientHandshaker {
ctx.pipeline().remove(this);
try {
finishHandshake(channel, msg);
promise.setSuccess();
promise.setSuccess(null);
} catch (Throwable cause) {
promise.setFailure(cause);
}
@ -491,7 +489,7 @@ public abstract class WebSocketClientHandshaker {
* @param frame
* Closing Frame that was received
*/
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
public Future<Void> close(Channel channel, CloseWebSocketFrame frame) {
requireNonNull(channel, "channel");
return close(channel, frame, channel.newPromise());
}
@ -500,16 +498,16 @@ public abstract class WebSocketClientHandshaker {
* Performs the closing handshake
*
* When called from within a {@link ChannelHandler} you most likely want to use
* {@link #close(ChannelHandlerContext, CloseWebSocketFrame, ChannelPromise)}.
* {@link #close(ChannelHandlerContext, CloseWebSocketFrame, Promise)}.
*
* @param channel
* Channel
* @param frame
* Closing Frame that was received
* @param promise
* the {@link ChannelPromise} to be notified when the closing handshake is done
* the {@link Promise} to be notified when the closing handshake is done
*/
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame, ChannelPromise promise) {
public Future<Void> close(Channel channel, CloseWebSocketFrame frame, Promise<Void> promise) {
requireNonNull(channel, "channel");
return close0(channel, channel, frame, promise);
}
@ -522,7 +520,7 @@ public abstract class WebSocketClientHandshaker {
* @param frame
* Closing Frame that was received
*/
public ChannelFuture close(ChannelHandlerContext ctx, CloseWebSocketFrame frame) {
public Future<Void> close(ChannelHandlerContext ctx, CloseWebSocketFrame frame) {
requireNonNull(ctx, "ctx");
return close(ctx, frame, ctx.newPromise());
}
@ -535,15 +533,15 @@ public abstract class WebSocketClientHandshaker {
* @param frame
* Closing Frame that was received
* @param promise
* the {@link ChannelPromise} to be notified when the closing handshake is done
* the {@link Promise} to be notified when the closing handshake is done
*/
public ChannelFuture close(ChannelHandlerContext ctx, CloseWebSocketFrame frame, ChannelPromise promise) {
public Future<Void> close(ChannelHandlerContext ctx, CloseWebSocketFrame frame, Promise<Void> promise) {
requireNonNull(ctx, "ctx");
return close0(ctx, ctx.channel(), frame, promise);
}
private ChannelFuture close0(final ChannelOutboundInvoker invoker, final Channel channel,
CloseWebSocketFrame frame, ChannelPromise promise) {
private Future<Void> close0(final ChannelOutboundInvoker invoker, final Channel channel,
CloseWebSocketFrame frame, Promise<Void> promise) {
invoker.writeAndFlush(frame, promise);
final long forceCloseTimeoutMillis = this.forceCloseTimeoutMillis;
final WebSocketClientHandshaker handshaker = this;

View File

@ -15,19 +15,16 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler.ClientHandshakeStateEvent;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import java.util.concurrent.TimeUnit;
import static io.netty.util.internal.ObjectUtil.*;
import static io.netty.util.internal.ObjectUtil.checkPositive;
class WebSocketClientProtocolHandshakeHandler implements ChannelHandler {
@ -36,7 +33,7 @@ class WebSocketClientProtocolHandshakeHandler implements ChannelHandler {
private final WebSocketClientHandshaker handshaker;
private final long handshakeTimeoutMillis;
private ChannelHandlerContext ctx;
private ChannelPromise handshakePromise;
private Promise<Void> handshakePromise;
WebSocketClientProtocolHandshakeHandler(WebSocketClientHandshaker handshaker) {
this(handshaker, DEFAULT_HANDSHAKE_TIMEOUT_MS);
@ -56,7 +53,7 @@ class WebSocketClientProtocolHandshakeHandler implements ChannelHandler {
@Override
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
handshaker.handshake(ctx.channel()).addListener((ChannelFutureListener) future -> {
handshaker.handshake(ctx.channel()).addListener(future -> {
if (!future.isSuccess()) {
handshakePromise.tryFailure(future.cause());
ctx.fireExceptionCaught(future.cause());
@ -89,7 +86,7 @@ class WebSocketClientProtocolHandshakeHandler implements ChannelHandler {
try {
if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ctx.channel(), response);
handshakePromise.trySuccess();
handshakePromise.trySuccess(null);
ctx.fireUserEventTriggered(
WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_COMPLETE);
ctx.pipeline().remove(this);
@ -102,7 +99,7 @@ class WebSocketClientProtocolHandshakeHandler implements ChannelHandler {
}
private void applyHandshakeTimeout() {
final ChannelPromise localHandshakePromise = handshakePromise;
final Promise<Void> localHandshakePromise = handshakePromise;
if (handshakeTimeoutMillis <= 0 || localHandshakePromise.isDone()) {
return;
}
@ -120,7 +117,7 @@ class WebSocketClientProtocolHandshakeHandler implements ChannelHandler {
}, handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
// Cancel the handshake timeout when handshake is finished.
localHandshakePromise.addListener((FutureListener<Void>) f -> timeoutFuture.cancel(false));
localHandshakePromise.addListener(f -> timeoutFuture.cancel(false));
}
/**
@ -128,7 +125,7 @@ class WebSocketClientProtocolHandshakeHandler implements ChannelHandler {
*
* @return current handshake future
*/
ChannelFuture getHandshakeFuture() {
Future<Void> getHandshakeFuture() {
return handshakePromise;
}
}

View File

@ -17,9 +17,9 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.PromiseNotifier;
import io.netty.util.concurrent.ScheduledFuture;
@ -31,7 +31,7 @@ abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocke
private final boolean dropPongFrames;
private final WebSocketCloseStatus closeStatus;
private final long forceCloseTimeoutMillis;
private ChannelPromise closeSent;
private Promise<Void> closeSent;
/**
* Creates a new {@link WebSocketProtocolHandler} that will <i>drop</i> {@link PongWebSocketFrame}s.
@ -82,7 +82,7 @@ abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocke
}
@Override
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) {
public void close(final ChannelHandlerContext ctx, final Promise<Void> promise) {
if (closeStatus == null || !ctx.channel().isActive()) {
ctx.close(promise);
} else {
@ -96,7 +96,7 @@ abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocke
}
@Override
public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(final ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (closeSent != null) {
ReferenceCountUtil.release(msg);
promise.setFailure(new ClosedChannelException());
@ -108,7 +108,7 @@ abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocke
}
}
void closeSent(ChannelPromise promise) {
void closeSent(Promise<Void> promise) {
closeSent = promise;
}

View File

@ -15,16 +15,12 @@
*/
package io.netty.handler.codec.http.websocketx;
import static java.util.Objects.requireNonNull;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundInvoker;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -36,6 +32,8 @@ import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -46,6 +44,8 @@ import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import static java.util.Objects.requireNonNull;
/**
* Base class for server side web socket opening and closing handshakes
*/
@ -114,7 +114,7 @@ public abstract class WebSocketServerHandshaker {
} else {
this.subprotocols = EmptyArrays.EMPTY_STRINGS;
}
this.decoderConfig = Objects.requireNonNull(decoderConfig, "decoderConfig");
this.decoderConfig = requireNonNull(decoderConfig, "decoderConfig");
}
/**
@ -167,9 +167,9 @@ public abstract class WebSocketServerHandshaker {
* @param req
* HTTP Request
* @return future
* The {@link ChannelFuture} which is notified once the opening handshake completes
* The {@link Future} which is notified once the opening handshake completes
*/
public ChannelFuture handshake(Channel channel, FullHttpRequest req) {
public Future<Void> handshake(Channel channel, FullHttpRequest req) {
return handshake(channel, req, null, channel.newPromise());
}
@ -185,12 +185,12 @@ public abstract class WebSocketServerHandshaker {
* @param responseHeaders
* Extra headers to add to the handshake response or {@code null} if no extra headers should be added
* @param promise
* the {@link ChannelPromise} to be notified when the opening handshake is done
* the {@link Promise} to be notified when the opening handshake is done
* @return future
* the {@link ChannelFuture} which is notified when the opening handshake is done
* the {@link Future} which is notified when the opening handshake is done
*/
public final ChannelFuture handshake(Channel channel, FullHttpRequest req,
HttpHeaders responseHeaders, final ChannelPromise promise) {
public final Future<Void> handshake(Channel channel, FullHttpRequest req,
HttpHeaders responseHeaders, final Promise<Void> promise) {
if (logger.isDebugEnabled()) {
logger.debug("{} WebSocket version {} server handshake", channel, version());
@ -222,11 +222,11 @@ public abstract class WebSocketServerHandshaker {
encoderName = p.context(HttpResponseEncoder.class).name();
p.addBefore(encoderName, "wsencoder", newWebSocketEncoder());
}
channel.writeAndFlush(response).addListener((ChannelFutureListener) future -> {
channel.writeAndFlush(response).addListener(channel, (ch, future) -> {
if (future.isSuccess()) {
ChannelPipeline p1 = future.channel().pipeline();
ChannelPipeline p1 = ch.pipeline();
p1.remove(encoderName);
promise.setSuccess();
promise.setSuccess(null);
} else {
promise.setFailure(future.cause());
}
@ -243,9 +243,9 @@ public abstract class WebSocketServerHandshaker {
* @param req
* HTTP Request
* @return future
* The {@link ChannelFuture} which is notified once the opening handshake completes
* The {@link Future} which is notified once the opening handshake completes
*/
public ChannelFuture handshake(Channel channel, HttpRequest req) {
public Future<Void> handshake(Channel channel, HttpRequest req) {
return handshake(channel, req, null, channel.newPromise());
}
@ -261,12 +261,12 @@ public abstract class WebSocketServerHandshaker {
* @param responseHeaders
* Extra headers to add to the handshake response or {@code null} if no extra headers should be added
* @param promise
* the {@link ChannelPromise} to be notified when the opening handshake is done
* the {@link Promise} to be notified when the opening handshake is done
* @return future
* the {@link ChannelFuture} which is notified when the opening handshake is done
* the {@link Future} which is notified when the opening handshake is done
*/
public final ChannelFuture handshake(final Channel channel, HttpRequest req,
final HttpHeaders responseHeaders, final ChannelPromise promise) {
public final Future<Void> handshake(final Channel channel, HttpRequest req,
final HttpHeaders responseHeaders, final Promise<Void> promise) {
if (req instanceof FullHttpRequest) {
return handshake(channel, (FullHttpRequest) req, responseHeaders, promise);
@ -340,7 +340,7 @@ public abstract class WebSocketServerHandshaker {
* @param frame
* Closing Frame that was received.
*/
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
public Future<Void> close(Channel channel, CloseWebSocketFrame frame) {
requireNonNull(channel, "channel");
return close(channel, frame, channel.newPromise());
}
@ -349,18 +349,18 @@ public abstract class WebSocketServerHandshaker {
* Performs the closing handshake.
*
* When called from within a {@link ChannelHandler} you most likely want to use
* {@link #close(ChannelHandlerContext, CloseWebSocketFrame, ChannelPromise)}.
* {@link #close(ChannelHandlerContext, CloseWebSocketFrame, Promise)}.
*
* @param channel
* the {@link Channel} to use.
* @param frame
* Closing Frame that was received.
* @param promise
* the {@link ChannelPromise} to be notified when the closing handshake is done
* the {@link Promise} to be notified when the closing handshake is done
*/
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame, ChannelPromise promise) {
public Future<Void> close(Channel channel, CloseWebSocketFrame frame, Promise<Void> promise) {
requireNonNull(channel, "channel");
return close0(channel, frame, promise);
return close0(channel, channel, frame, promise);
}
/**
@ -371,7 +371,7 @@ public abstract class WebSocketServerHandshaker {
* @param frame
* Closing Frame that was received.
*/
public ChannelFuture close(ChannelHandlerContext ctx, CloseWebSocketFrame frame) {
public Future<Void> close(ChannelHandlerContext ctx, CloseWebSocketFrame frame) {
requireNonNull(ctx, "ctx");
return close(ctx, frame, ctx.newPromise());
}
@ -384,15 +384,16 @@ public abstract class WebSocketServerHandshaker {
* @param frame
* Closing Frame that was received.
* @param promise
* the {@link ChannelPromise} to be notified when the closing handshake is done.
* the {@link Promise} to be notified when the closing handshake is done.
*/
public ChannelFuture close(ChannelHandlerContext ctx, CloseWebSocketFrame frame, ChannelPromise promise) {
public Future<Void> close(ChannelHandlerContext ctx, CloseWebSocketFrame frame, Promise<Void> promise) {
requireNonNull(ctx, "ctx");
return close0(ctx, frame, promise).addListener(ChannelFutureListener.CLOSE);
return close0(ctx, ctx.channel(), frame, promise);
}
private ChannelFuture close0(ChannelOutboundInvoker invoker, CloseWebSocketFrame frame, ChannelPromise promise) {
return invoker.writeAndFlush(frame, promise).addListener(ChannelFutureListener.CLOSE);
private static Future<Void> close0(ChannelOutboundInvoker invoker, Channel channel, CloseWebSocketFrame frame,
Promise<Void> promise) {
return invoker.writeAndFlush(frame, promise).addListener(channel, ChannelFutureListeners.CLOSE);
}
/**

View File

@ -18,9 +18,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -28,6 +26,8 @@ import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.util.regex.Pattern;
@ -204,10 +204,10 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
* @param frame
* Web Socket frame that was received.
* @param promise
* the {@link ChannelPromise} to be notified when the closing handshake is done.
* the {@link Promise} to be notified when the closing handshake is done.
*/
@Override
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame, ChannelPromise promise) {
public Future<Void> close(Channel channel, CloseWebSocketFrame frame, Promise<Void> promise) {
return channel.writeAndFlush(frame, promise);
}
@ -219,11 +219,10 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
* @param frame
* Closing Frame that was received.
* @param promise
* the {@link ChannelPromise} to be notified when the closing handshake is done.
* the {@link Promise} to be notified when the closing handshake is done.
*/
@Override
public ChannelFuture close(ChannelHandlerContext ctx, CloseWebSocketFrame frame,
ChannelPromise promise) {
public Future<Void> close(ChannelHandlerContext ctx, CloseWebSocketFrame frame, Promise<Void> promise) {
return ctx.writeAndFlush(frame, promise);
}

View File

@ -16,15 +16,15 @@
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.util.Objects;
@ -163,14 +163,14 @@ public class WebSocketServerHandshakerFactory {
/**
* Return that we need cannot not support the web socket version
*/
public static ChannelFuture sendUnsupportedVersionResponse(Channel channel) {
public static Future<Void> sendUnsupportedVersionResponse(Channel channel) {
return sendUnsupportedVersionResponse(channel, channel.newPromise());
}
/**
* Return that we need cannot not support the web socket version
*/
public static ChannelFuture sendUnsupportedVersionResponse(Channel channel, ChannelPromise promise) {
public static Future<Void> sendUnsupportedVersionResponse(Channel channel, Promise<Void> promise) {
HttpResponse res = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.UPGRADE_REQUIRED, channel.alloc().buffer(0));

View File

@ -17,16 +17,16 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.Promise;
import java.util.Objects;
@ -237,11 +237,11 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {
WebSocketServerHandshaker handshaker = getHandshaker(ctx.channel());
if (handshaker != null) {
frame.retain();
ChannelPromise promise = ctx.newPromise();
Promise<Void> promise = ctx.newPromise();
closeSent(promise);
handshaker.close(ctx, (CloseWebSocketFrame) frame, promise);
} else {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
}
return;
}
@ -258,7 +258,7 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {
if (cause instanceof WebSocketHandshakeException) {
FullHttpResponse response = new DefaultFullHttpResponse(
HTTP_1_1, HttpResponseStatus.BAD_REQUEST, Unpooled.wrappedBuffer(cause.getMessage().getBytes()));
ctx.channel().writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
ctx.channel().writeAndFlush(response).addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
} else {
ctx.fireExceptionCaught(cause);
ctx.close();

View File

@ -15,12 +15,10 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
@ -30,14 +28,15 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.Ser
import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import static io.netty.handler.codec.http.HttpMethod.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpUtil.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import static io.netty.handler.codec.http.HttpMethod.GET;
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
/**
* Handles the HTTP handshake (the HTTP Upgrade request) for {@link WebSocketServerProtocolHandler}.
@ -45,7 +44,7 @@ import static io.netty.handler.codec.http.HttpVersion.*;
class WebSocketServerProtocolHandshakeHandler implements ChannelHandler {
private final WebSocketServerProtocolConfig serverConfig;
private ChannelPromise handshakePromise;
private Promise<Void> handshakePromise;
WebSocketServerProtocolHandshakeHandler(WebSocketServerProtocolConfig serverConfig) {
this.serverConfig = Objects.requireNonNull(serverConfig, "serverConfig");
@ -74,7 +73,7 @@ class WebSocketServerProtocolHandshakeHandler implements ChannelHandler {
getWebSocketLocation(ctx.pipeline(), req, serverConfig.websocketPath()),
serverConfig.subprotocols(), serverConfig.decoderConfig());
final WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req);
final ChannelPromise localHandshakePromise = handshakePromise;
Promise<Void> localHandshakePromise = handshakePromise;
if (handshaker == null) {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
} else {
@ -85,13 +84,13 @@ class WebSocketServerProtocolHandshakeHandler implements ChannelHandler {
// See https://github.com/netty/netty/issues/9471.
WebSocketServerProtocolHandler.setHandshaker(ctx.channel(), handshaker);
final ChannelFuture handshakeFuture = handshaker.handshake(ctx.channel(), req);
handshakeFuture.addListener((ChannelFutureListener) future -> {
Future<Void> handshakeFuture = handshaker.handshake(ctx.channel(), req);
handshakeFuture.addListener(future -> {
if (!future.isSuccess()) {
localHandshakePromise.tryFailure(future.cause());
ctx.fireExceptionCaught(future.cause());
} else {
localHandshakePromise.trySuccess();
localHandshakePromise.trySuccess(null);
// Kept for compatibility
ctx.fireUserEventTriggered(
WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE);
@ -126,9 +125,9 @@ class WebSocketServerProtocolHandshakeHandler implements ChannelHandler {
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
ChannelFuture f = ctx.channel().writeAndFlush(res);
Future<Void> f = ctx.channel().writeAndFlush(res);
if (!isKeepAlive(req) || res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
f.addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
}
}
@ -143,7 +142,7 @@ class WebSocketServerProtocolHandshakeHandler implements ChannelHandler {
}
private void applyHandshakeTimeout(ChannelHandlerContext ctx) {
final ChannelPromise localHandshakePromise = handshakePromise;
Promise<Void> localHandshakePromise = handshakePromise;
final long handshakeTimeoutMillis = serverConfig.handshakeTimeoutMillis();
if (handshakeTimeoutMillis <= 0 || localHandshakePromise.isDone()) {
return;
@ -159,6 +158,6 @@ class WebSocketServerProtocolHandshakeHandler implements ChannelHandler {
}, handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
// Cancel the handshake timeout when handshake is finished.
localHandshakePromise.addListener((FutureListener<Void>) f -> timeoutFuture.cancel(false));
localHandshakePromise.addListener(f -> timeoutFuture.cancel(false));
}
}

View File

@ -15,21 +15,21 @@
*/
package io.netty.handler.codec.http.websocketx.extensions;
import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.CodecException;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.concurrent.Promise;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
/**
* This handler negotiates and initializes the WebSocket Extensions.
*
@ -56,7 +56,7 @@ public class WebSocketClientExtensionHandler implements ChannelHandler {
}
@Override
public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(final ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (msg instanceof HttpRequest && WebSocketExtensionUtil.isWebsocketUpgrade(((HttpRequest) msg).headers())) {
HttpRequest request = (HttpRequest) msg;
String headerValue = request.headers().getAsString(HttpHeaderNames.SEC_WEBSOCKET_EXTENSIONS);

View File

@ -15,23 +15,22 @@
*/
package io.netty.handler.codec.http.websocketx.extensions;
import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.concurrent.Promise;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
/**
* This handler negotiates and initializes the WebSocket Extensions.
*
@ -99,7 +98,7 @@ public class WebSocketServerExtensionHandler implements ChannelHandler {
}
@Override
public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(final ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (msg instanceof HttpResponse) {
HttpResponse httpResponse = (HttpResponse) msg;
//checking the status is faster than looking at headers
@ -113,7 +112,7 @@ public class WebSocketServerExtensionHandler implements ChannelHandler {
}
private void handlePotentialUpgrade(final ChannelHandlerContext ctx,
ChannelPromise promise, HttpResponse httpResponse) {
Promise<Void> promise, HttpResponse httpResponse) {
HttpHeaders headers = httpResponse.headers();
if (WebSocketExtensionUtil.isWebsocketUpgrade(headers)) {
if (validExtensions != null) {
@ -125,7 +124,7 @@ public class WebSocketServerExtensionHandler implements ChannelHandler {
}
String newHeaderValue = WebSocketExtensionUtil
.computeMergeExtensionsHeaderValue(headerValue, extraExtensions);
promise.addListener((ChannelFutureListener) future -> {
promise.addListener(future -> {
if (future.isSuccess()) {
for (WebSocketServerExtension extension : validExtensions) {
WebSocketExtensionDecoder decoder = extension.newExtensionDecoder();
@ -143,9 +142,9 @@ public class WebSocketServerExtensionHandler implements ChannelHandler {
headers.set(HttpHeaderNames.SEC_WEBSOCKET_EXTENSIONS, newHeaderValue);
}
}
promise.addListener((ChannelFutureListener) future -> {
promise.addListener(future -> {
if (future.isSuccess()) {
ctx.pipeline().remove(WebSocketServerExtensionHandler.this);
ctx.pipeline().remove(this);
}
});
}

View File

@ -20,7 +20,6 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
@ -156,12 +155,12 @@ public class HttpClientCodecTest {
sChannel.writeAndFlush(Unpooled.wrappedBuffer(("HTTP/1.0 200 OK\r\n" +
"Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n" +
"Content-Type: text/html\r\n\r\n").getBytes(CharsetUtil.ISO_8859_1)))
.addListener((ChannelFutureListener) future -> {
.addListener(future -> {
assertTrue(future.isSuccess());
sChannel.writeAndFlush(Unpooled.wrappedBuffer(
"<html><body>hello half closed!</body></html>\r\n"
.getBytes(CharsetUtil.ISO_8859_1)))
.addListener((ChannelFutureListener) future1 -> {
.addListener(future1 -> {
assertTrue(future1.isSuccess());
sChannel.shutdownOutput();
});

View File

@ -15,22 +15,21 @@
*/
package io.netty.handler.codec.http;
import java.util.Collection;
import java.util.Collections;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodec;
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodecFactory;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.Test;
import java.util.Collection;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -94,13 +93,13 @@ public class HttpServerUpgradeHandlerTest {
}
@Override
public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) {
public void write(final ChannelHandlerContext ctx, final Object msg, final Promise<Void> promise) {
// We ensure that we're in the read call and defer the write so we can
// make sure the pipeline was reformed irrespective of the flush completing.
assertTrue(inReadCall);
writeUpgradeMessage = true;
ctx.channel().eventLoop().execute(() -> ctx.write(msg, promise));
promise.addListener((ChannelFutureListener) future -> writeFlushed = true);
promise.addListener(future -> writeFlushed = true);
}
};

View File

@ -17,7 +17,6 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
@ -28,13 +27,13 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler.ClientHandshakeStateEvent;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.ServerHandshakeStateEvent;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.net.URI;
import java.util.concurrent.CompletionException;
import org.junit.jupiter.api.Timeout;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -244,7 +243,7 @@ public class WebSocketHandshakeHandOverTest {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt == ClientHandshakeStateEvent.HANDSHAKE_COMPLETE) {
ctx.channel().closeFuture().addListener((ChannelFutureListener) future -> clientForceClosed = true);
ctx.channel().closeFuture().addListener(future -> clientForceClosed = true);
handshaker.close(ctx.channel(), new CloseWebSocketFrame());
}
}

View File

@ -18,13 +18,13 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.flow.FlowControlHandler;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
@ -153,18 +153,18 @@ public class WebSocketProtocolHandlerTest {
@Test
public void testTimeout() throws Exception {
final AtomicReference<ChannelPromise> ref = new AtomicReference<ChannelPromise>();
final AtomicReference<Promise<Void>> ref = new AtomicReference<>();
WebSocketProtocolHandler handler = new WebSocketProtocolHandler(
false, WebSocketCloseStatus.NORMAL_CLOSURE, 1) { };
EmbeddedChannel channel = new EmbeddedChannel(new ChannelOutboundHandlerAdapter() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
ref.set(promise);
ReferenceCountUtil.release(msg);
}
}, handler);
ChannelFuture future = channel.writeAndFlush(new CloseWebSocketFrame());
Future<Void> future = channel.writeAndFlush(new CloseWebSocketFrame());
ChannelHandlerContext ctx = channel.pipeline().context(WebSocketProtocolHandler.class);
handler.close(ctx, ctx.newPromise());

View File

@ -18,30 +18,30 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayDeque;
import java.util.Queue;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -354,7 +354,7 @@ public class WebSocketServerProtocolHandlerTest {
assertFalse(client.isOpen());
assertFalse(server.isOpen());
CloseWebSocketFrame closeMessage = decode(server.<ByteBuf>readOutbound(), CloseWebSocketFrame.class);
CloseWebSocketFrame closeMessage = decode(server.readOutbound(), CloseWebSocketFrame.class);
assertEquals(closeMessage.statusCode(), closeStatus.code());
closeMessage.release();
@ -378,7 +378,7 @@ public class WebSocketServerProtocolHandlerTest {
assertFalse(client.isOpen());
assertFalse(server.isOpen());
CloseWebSocketFrame closeMessage = decode(server.<ByteBuf>readOutbound(), CloseWebSocketFrame.class);
CloseWebSocketFrame closeMessage = decode(server.readOutbound(), CloseWebSocketFrame.class);
assertEquals(closeMessage, new CloseWebSocketFrame(WebSocketCloseStatus.NORMAL_CLOSURE));
closeMessage.release();
@ -459,9 +459,9 @@ public class WebSocketServerProtocolHandlerTest {
private class MockOutboundHandler implements ChannelHandler {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
responses.add((FullHttpResponse) msg);
promise.setSuccess();
promise.setSuccess(null);
}
@Override

View File

@ -15,25 +15,34 @@
*/
package io.netty.handler.codec.http.websocketx.extensions;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.*;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.Dummy2Decoder;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.Dummy2Encoder;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.DummyDecoder;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.DummyEncoder;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.newUpgradeRequest;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.newUpgradeResponse;
import static io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionTestUtil.webSocketExtensionDataMatcher;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class WebSocketServerExtensionHandlerTest {
@ -209,7 +218,7 @@ public class WebSocketServerExtensionHandlerTest {
when(mainHandshakerMock.handshakeExtension(webSocketExtensionDataMatcher("main")))
.thenReturn(mainExtensionMock);
when(mainExtensionMock.newResponseData()).thenReturn(
new WebSocketExtensionData("main", Collections.<String, String>emptyMap()));
new WebSocketExtensionData("main", Collections.emptyMap()));
// execute
WebSocketServerExtensionHandler extensionHandler =
@ -220,7 +229,7 @@ public class WebSocketServerExtensionHandlerTest {
ch.writeInbound(req);
HttpResponse res = newUpgradeResponse(null);
ChannelPromise failurePromise = ch.newPromise();
Promise<Void> failurePromise = ch.newPromise();
ch.writeOneOutbound(res, failurePromise);
failurePromise.setFailure(new IOException("Cannot write response"));

View File

@ -18,15 +18,12 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.DefaultChannelPipeline;
import io.netty.channel.EventLoop;
@ -36,6 +33,8 @@ import io.netty.channel.WriteBufferWaterMark;
import io.netty.handler.codec.http2.Http2FrameCodec.DefaultHttp2FrameStream;
import io.netty.util.DefaultAttributeMap;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -97,7 +96,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
private static final AtomicIntegerFieldUpdater<AbstractHttp2StreamChannel> UNWRITABLE_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AbstractHttp2StreamChannel.class, "unwritable");
private static void windowUpdateFrameWriteComplete(ChannelFuture future, Channel streamChannel) {
private static void windowUpdateFrameWriteComplete(Channel streamChannel, Future<?> future) {
Throwable cause = future.cause();
if (cause != null) {
Throwable unwrappedCause;
@ -112,9 +111,6 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
}
private final ChannelFutureListener windowUpdateFrameWriteListener = future ->
windowUpdateFrameWriteComplete(future, AbstractHttp2StreamChannel.this);
/**
* The current status of the read-processing for a {@link AbstractHttp2StreamChannel}.
*/
@ -140,7 +136,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
private final ChannelId channelId;
private final ChannelPipeline pipeline;
private final DefaultHttp2FrameStream stream;
private final ChannelPromise closePromise;
private final Promise<Void> closePromise;
private volatile boolean registered;
@ -338,7 +334,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
@Override
public ChannelFuture closeFuture() {
public Future<Void> closeFuture() {
return closePromise;
}
@ -394,107 +390,107 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
public Future<Void> bind(SocketAddress localAddress) {
return pipeline().bind(localAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
public Future<Void> connect(SocketAddress remoteAddress) {
return pipeline().connect(remoteAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return pipeline().connect(remoteAddress, localAddress);
}
@Override
public ChannelFuture disconnect() {
public Future<Void> disconnect() {
return pipeline().disconnect();
}
@Override
public ChannelFuture close() {
public Future<Void> close() {
return pipeline().close();
}
@Override
public ChannelFuture register() {
public Future<Void> register() {
return pipeline().register();
}
@Override
public ChannelFuture deregister() {
public Future<Void> deregister() {
return pipeline().deregister();
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> bind(SocketAddress localAddress, Promise<Void> promise) {
return pipeline().bind(localAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
public Future<Void> connect(SocketAddress remoteAddress, Promise<Void> promise) {
return pipeline().connect(remoteAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress, Promise<Void> promise) {
return pipeline().connect(remoteAddress, localAddress, promise);
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
public Future<Void> disconnect(Promise<Void> promise) {
return pipeline().disconnect(promise);
}
@Override
public ChannelFuture close(ChannelPromise promise) {
public Future<Void> close(Promise<Void> promise) {
return pipeline().close(promise);
}
@Override
public ChannelFuture register(ChannelPromise promise) {
public Future<Void> register(Promise<Void> promise) {
return pipeline().register(promise);
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
public Future<Void> deregister(Promise<Void> promise) {
return pipeline().deregister(promise);
}
@Override
public ChannelFuture write(Object msg) {
public Future<Void> write(Object msg) {
return pipeline().write(msg);
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
public Future<Void> write(Object msg, Promise<Void> promise) {
return pipeline().write(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
public Future<Void> writeAndFlush(Object msg, Promise<Void> promise) {
return pipeline().writeAndFlush(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
public Future<Void> writeAndFlush(Object msg) {
return pipeline().writeAndFlush(msg);
}
@Override
public ChannelPromise newPromise() {
public Promise<Void> newPromise() {
return pipeline().newPromise();
}
@Override
public ChannelFuture newSucceededFuture() {
public Future<Void> newSucceededFuture() {
return pipeline().newSucceededFuture();
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
public Future<Void> newFailedFuture(Throwable cause) {
return pipeline().newFailedFuture(cause);
}
@ -568,7 +564,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
@Override
public void connect(final SocketAddress remoteAddress,
SocketAddress localAddress, final ChannelPromise promise) {
SocketAddress localAddress, Promise<Void> promise) {
if (!promise.setUncancellable()) {
return;
}
@ -595,7 +591,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
@Override
public void register(ChannelPromise promise) {
public void register(Promise<Void> promise) {
if (!promise.setUncancellable()) {
return;
}
@ -606,7 +602,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
registered = true;
promise.setSuccess();
promise.setSuccess(null);
pipeline().fireChannelRegistered();
if (isActive()) {
@ -618,7 +614,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
@Override
public void bind(SocketAddress localAddress, ChannelPromise promise) {
public void bind(SocketAddress localAddress, Promise<Void> promise) {
if (!promise.setUncancellable()) {
return;
}
@ -626,22 +622,22 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
@Override
public void disconnect(ChannelPromise promise) {
public void disconnect(Promise<Void> promise) {
close(promise);
}
@Override
public void close(final ChannelPromise promise) {
public void close(final Promise<Void> promise) {
if (!promise.setUncancellable()) {
return;
}
if (closeInitiated) {
if (closePromise.isDone()) {
// Closed already.
promise.setSuccess();
promise.setSuccess(null);
} else {
// This means close() was called before so we just register a listener and return
closePromise.addListener((ChannelFutureListener) future -> promise.setSuccess());
closePromise.addListener(promise, (p, future) -> p.setSuccess(null));
}
return;
}
@ -675,8 +671,8 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
// The promise should be notified before we call fireChannelInactive().
outboundClosed = true;
closePromise.setSuccess();
promise.setSuccess();
closePromise.setSuccess(null);
promise.setSuccess(null);
fireChannelInactiveAndDeregister(newPromise(), wasActive);
}
@ -687,18 +683,18 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
@Override
public void deregister(ChannelPromise promise) {
public void deregister(Promise<Void> promise) {
fireChannelInactiveAndDeregister(promise, false);
}
private void fireChannelInactiveAndDeregister(final ChannelPromise promise,
private void fireChannelInactiveAndDeregister(Promise<Void> promise,
final boolean fireChannelInactive) {
if (!promise.setUncancellable()) {
return;
}
if (!registered) {
promise.setSuccess();
promise.setSuccess(null);
return;
}
@ -723,8 +719,8 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
});
}
private void safeSetSuccess(ChannelPromise promise) {
if (!promise.trySuccess()) {
private void safeSetSuccess(Promise<Void> promise) {
if (!promise.trySuccess(null)) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
@ -813,7 +809,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
if (flowControlledBytes != 0) {
int bytes = flowControlledBytes;
flowControlledBytes = 0;
ChannelFuture future = write0(parentContext(), new DefaultHttp2WindowUpdateFrame(bytes).stream(stream));
Future<Void> future = write0(parentContext(), new DefaultHttp2WindowUpdateFrame(bytes).stream(stream));
// window update frames are commonly swallowed by the Http2FrameCodec and the promise is synchronously
// completed but the flow controller _may_ have generated a wire level WINDOW_UPDATE. Therefore we need,
// to assume there was a write done that needs to be flushed or we risk flow control starvation.
@ -823,9 +819,10 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
// already.
// See https://github.com/netty/netty/issues/9663
if (future.isDone()) {
windowUpdateFrameWriteComplete(future, AbstractHttp2StreamChannel.this);
windowUpdateFrameWriteComplete(AbstractHttp2StreamChannel.this, future);
} else {
future.addListener(windowUpdateFrameWriteListener);
future.addListener(AbstractHttp2StreamChannel.this,
AbstractHttp2StreamChannel::windowUpdateFrameWriteComplete);
}
}
}
@ -882,7 +879,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
@Override
public void write(Object msg, final ChannelPromise promise) {
public void write(Object msg, Promise<Void> promise) {
// After this point its not possible to cancel a write anymore.
if (!promise.setUncancellable()) {
ReferenceCountUtil.release(msg);
@ -913,7 +910,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
}
private void writeHttp2StreamFrame(Http2StreamFrame frame, final ChannelPromise promise) {
private void writeHttp2StreamFrame(Http2StreamFrame frame, Promise<Void> promise) {
if (!firstFrameWritten && !isStreamIdValid(stream().id()) && !(frame instanceof Http2HeadersFrame)) {
ReferenceCountUtil.release(frame);
promise.setFailure(
@ -929,7 +926,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
firstWrite = firstFrameWritten = true;
}
ChannelFuture f = write0(parentContext(), frame);
Future<Void> f = write0(parentContext(), frame);
if (f.isDone()) {
if (firstWrite) {
firstWriteComplete(f, promise);
@ -939,7 +936,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
} else {
final long bytes = FlowControlledFrameSizeEstimator.HANDLE_INSTANCE.size(frame);
incrementPendingOutboundBytes(bytes, false);
f.addListener((ChannelFutureListener) future -> {
f.addListener(future -> {
if (firstWrite) {
firstWriteComplete(future, promise);
} else {
@ -951,10 +948,10 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
}
private void firstWriteComplete(ChannelFuture future, ChannelPromise promise) {
private void firstWriteComplete(Future<?> future, Promise<Void> promise) {
Throwable cause = future.cause();
if (cause == null) {
promise.setSuccess();
promise.setSuccess(null);
} else {
// If the first write fails there is not much we can do, just close
closeForcibly();
@ -962,10 +959,10 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
}
}
private void writeComplete(ChannelFuture future, ChannelPromise promise) {
private void writeComplete(Future<?> future, Promise<Void> promise) {
Throwable cause = future.cause();
if (cause == null) {
promise.setSuccess();
promise.setSuccess(null);
} else {
Throwable error = wrapStreamClosedError(cause);
// To make it more consistent with AbstractChannel we handle all IOExceptions here.
@ -1011,7 +1008,7 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
// There is nothing to flush so this is a NOOP.
return;
}
// We need to set this to false before we call flush0(...) as ChannelFutureListener may produce more data
// We need to set this to false before we call flush0(...) as FutureListener may produce more data
// that are explicit flushed.
writeDoneAndNoFlush = false;
flush0(parentContext());
@ -1066,8 +1063,8 @@ abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements
ctx.flush();
}
protected ChannelFuture write0(ChannelHandlerContext ctx, Object msg) {
ChannelPromise promise = ctx.newPromise();
protected Future<Void> write0(ChannelHandlerContext ctx, Object msg) {
Promise<Void> promise = ctx.newPromise();
ctx.write(msg, promise);
return promise;
}

View File

@ -16,21 +16,21 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.compression.BrotliEncoder;
import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.codec.compression.BrotliOptions;
import io.netty.handler.codec.compression.CompressionOptions;
import io.netty.handler.codec.compression.DeflateOptions;
import io.netty.handler.codec.compression.GzipOptions;
import io.netty.handler.codec.compression.StandardCompressionOptions;
import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.codec.compression.ZstdEncoder;
import io.netty.handler.codec.compression.ZstdOptions;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.PromiseCombiner;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.UnstableApi;
@ -142,8 +142,8 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
}
@Override
public ChannelFuture writeData(final ChannelHandlerContext ctx, final int streamId, ByteBuf data, int padding,
final boolean endOfStream, ChannelPromise promise) {
public Future<Void> writeData(final ChannelHandlerContext ctx, final int streamId, ByteBuf data, int padding,
final boolean endOfStream, Promise<Void> promise) {
final Http2Stream stream = connection().stream(streamId);
final EmbeddedChannel channel = stream == null ? null : (EmbeddedChannel) stream.getProperty(propertyKey);
if (channel == null) {
@ -164,7 +164,7 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
true, promise);
}
// END_STREAM is not set and the assumption is data is still forthcoming.
promise.setSuccess();
promise.setSuccess(null);
return promise;
}
@ -177,7 +177,7 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
compressedEndOfStream = nextBuf == null;
}
ChannelPromise bufPromise = ctx.newPromise();
Promise<Void> bufPromise = ctx.newPromise();
combiner.add(bufPromise);
super.writeData(ctx, streamId, buf, padding, compressedEndOfStream, bufPromise);
if (nextBuf == null) {
@ -199,14 +199,14 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endStream, Promise<Void> promise) {
try {
// Determine if compression is required and sanitize the headers.
EmbeddedChannel compressor = newCompressor(ctx, headers, endStream);
// Write the headers and create the stream object.
ChannelFuture future = super.writeHeaders(ctx, streamId, headers, padding, endStream, promise);
Future<Void> future = super.writeHeaders(ctx, streamId, headers, padding, endStream, promise);
// After the stream object has been created, then attach the compressor as a property for data compression.
bindCompressorToStream(compressor, streamId);
@ -219,15 +219,15 @@ public class CompressorHttp2ConnectionEncoder extends DecoratingHttp2ConnectionE
}
@Override
public ChannelFuture writeHeaders(final ChannelHandlerContext ctx, final int streamId, final Http2Headers headers,
public Future<Void> writeHeaders(final ChannelHandlerContext ctx, final int streamId, final Http2Headers headers,
final int streamDependency, final short weight, final boolean exclusive, final int padding,
final boolean endOfStream, final ChannelPromise promise) {
final boolean endOfStream, final Promise<Void> promise) {
try {
// Determine if compression is required and sanitize the headers.
EmbeddedChannel compressor = newCompressor(ctx, headers, endOfStream);
// Write the headers and create the stream object.
ChannelFuture future = super.writeHeaders(ctx, streamId, headers, streamDependency, weight, exclusive,
Future<Void> future = super.writeHeaders(ctx, streamId, headers, streamDependency, weight, exclusive,
padding, endOfStream, promise);
// After the stream object has been created, then attach the compressor as a property for data compression.

View File

@ -15,9 +15,9 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import static java.util.Objects.requireNonNull;
@ -34,73 +34,73 @@ public class DecoratingHttp2FrameWriter implements Http2FrameWriter {
}
@Override
public ChannelFuture writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
boolean endStream, ChannelPromise promise) {
public Future<Void> writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
boolean endStream, Promise<Void> promise) {
return delegate.writeData(ctx, streamId, data, padding, endStream, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endStream, Promise<Void> promise) {
return delegate.writeHeaders(ctx, streamId, headers, padding, endStream, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int streamDependency, short weight, boolean exclusive, int padding,
boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int streamDependency, short weight, boolean exclusive, int padding,
boolean endStream, Promise<Void> promise) {
return delegate
.writeHeaders(ctx, streamId, headers, streamDependency, weight, exclusive, padding, endStream, promise);
}
@Override
public ChannelFuture writePriority(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
boolean exclusive, ChannelPromise promise) {
public Future<Void> writePriority(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
boolean exclusive, Promise<Void> promise) {
return delegate.writePriority(ctx, streamId, streamDependency, weight, exclusive, promise);
}
@Override
public ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise) {
public Future<Void> writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise) {
return delegate.writeRstStream(ctx, streamId, errorCode, promise);
}
@Override
public ChannelFuture writeSettings(ChannelHandlerContext ctx, Http2Settings settings, ChannelPromise promise) {
public Future<Void> writeSettings(ChannelHandlerContext ctx, Http2Settings settings, Promise<Void> promise) {
return delegate.writeSettings(ctx, settings, promise);
}
@Override
public ChannelFuture writeSettingsAck(ChannelHandlerContext ctx, ChannelPromise promise) {
public Future<Void> writeSettingsAck(ChannelHandlerContext ctx, Promise<Void> promise) {
return delegate.writeSettingsAck(ctx, promise);
}
@Override
public ChannelFuture writePing(ChannelHandlerContext ctx, boolean ack, long data, ChannelPromise promise) {
public Future<Void> writePing(ChannelHandlerContext ctx, boolean ack, long data, Promise<Void> promise) {
return delegate.writePing(ctx, ack, data, promise);
}
@Override
public ChannelFuture writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, ChannelPromise promise) {
public Future<Void> writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, Promise<Void> promise) {
return delegate.writePushPromise(ctx, streamId, promisedStreamId, headers, padding, promise);
}
@Override
public ChannelFuture writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData,
ChannelPromise promise) {
public Future<Void> writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData,
Promise<Void> promise) {
return delegate.writeGoAway(ctx, lastStreamId, errorCode, debugData, promise);
}
@Override
public ChannelFuture writeWindowUpdate(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement,
ChannelPromise promise) {
public Future<Void> writeWindowUpdate(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement,
Promise<Void> promise) {
return delegate.writeWindowUpdate(ctx, streamId, windowSizeIncrement, promise);
}
@Override
public ChannelFuture writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
ByteBuf payload, ChannelPromise promise) {
public Future<Void> writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
ByteBuf payload, Promise<Void> promise) {
return delegate.writeFrame(ctx, frameType, streamId, flags, payload, promise);
}

View File

@ -15,13 +15,14 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.CoalescingBufferQueue;
import io.netty.handler.codec.http.HttpStatusClass;
import io.netty.handler.codec.http2.Http2CodecUtil.SimpleChannelPromiseAggregator;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import java.util.ArrayDeque;
@ -118,8 +119,8 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
@Override
public ChannelFuture writeData(final ChannelHandlerContext ctx, final int streamId, ByteBuf data, int padding,
final boolean endOfStream, ChannelPromise promise) {
public Future<Void> writeData(final ChannelHandlerContext ctx, final int streamId, ByteBuf data, int padding,
final boolean endOfStream, Promise<Void> promise) {
final Http2Stream stream;
try {
stream = requireStream(streamId);
@ -140,13 +141,13 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
// Hand control of the frame to the flow controller.
flowController().addFlowControlled(stream,
new FlowControlledData(stream, data, padding, endOfStream, promise));
new FlowControlledData(stream, data, padding, endOfStream, promise, ctx.channel()));
return promise;
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding,
boolean endStream, Promise<Void> promise) {
return writeHeaders0(ctx, streamId, headers, false, 0, (short) 0, false, padding, endStream, promise);
}
@ -160,9 +161,10 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
@Override
public ChannelFuture writeHeaders(final ChannelHandlerContext ctx, final int streamId,
final Http2Headers headers, final int streamDependency, final short weight,
final boolean exclusive, final int padding, final boolean endOfStream, ChannelPromise promise) {
public Future<Void> writeHeaders(final ChannelHandlerContext ctx, final int streamId,
final Http2Headers headers, final int streamDependency, final short weight,
final boolean exclusive, final int padding, final boolean endOfStream,
Promise<Void> promise) {
return writeHeaders0(ctx, streamId, headers, true, streamDependency,
weight, exclusive, padding, endOfStream, promise);
}
@ -171,11 +173,11 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
* Write headers via {@link Http2FrameWriter}. If {@code hasPriority} is {@code false} it will ignore the
* {@code streamDependency}, {@code weight} and {@code exclusive} parameters.
*/
private static ChannelFuture sendHeaders(Http2FrameWriter frameWriter, ChannelHandlerContext ctx, int streamId,
private static Future<Void> sendHeaders(Http2FrameWriter frameWriter, ChannelHandlerContext ctx, int streamId,
Http2Headers headers, final boolean hasPriority,
int streamDependency, final short weight,
boolean exclusive, final int padding,
boolean endOfStream, ChannelPromise promise) {
boolean endOfStream, Promise<Void> promise) {
if (hasPriority) {
return frameWriter.writeHeaders(ctx, streamId, headers, streamDependency,
weight, exclusive, padding, endOfStream, promise);
@ -183,11 +185,11 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
return frameWriter.writeHeaders(ctx, streamId, headers, padding, endOfStream, promise);
}
private ChannelFuture writeHeaders0(final ChannelHandlerContext ctx, final int streamId,
private Future<Void> writeHeaders0(final ChannelHandlerContext ctx, final int streamId,
final Http2Headers headers, final boolean hasPriority,
final int streamDependency, final short weight,
final boolean exclusive, final int padding,
final boolean endOfStream, ChannelPromise promise) {
final boolean endOfStream, Promise<Void> promise) {
try {
Http2Stream stream = connection.stream(streamId);
if (stream == null) {
@ -228,7 +230,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
boolean isInformational = validateHeadersSentState(stream, headers, connection.isServer(), endOfStream);
ChannelFuture future = sendHeaders(frameWriter, ctx, streamId, headers, hasPriority, streamDependency,
Future<Void> future = sendHeaders(frameWriter, ctx, streamId, headers, hasPriority, streamDependency,
weight, exclusive, padding, endOfStream, promise);
// Writing headers may fail during the encode state if they violate HPACK limits.
@ -272,21 +274,21 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
@Override
public ChannelFuture writePriority(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
boolean exclusive, ChannelPromise promise) {
public Future<Void> writePriority(ChannelHandlerContext ctx, int streamId, int streamDependency, short weight,
boolean exclusive, Promise<Void> promise) {
return frameWriter.writePriority(ctx, streamId, streamDependency, weight, exclusive, promise);
}
@Override
public ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise) {
public Future<Void> writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise) {
// Delegate to the lifecycle manager for proper updating of connection state.
return lifecycleManager.resetStream(ctx, streamId, errorCode, promise);
}
@Override
public ChannelFuture writeSettings(ChannelHandlerContext ctx, Http2Settings settings,
ChannelPromise promise) {
public Future<Void> writeSettings(ChannelHandlerContext ctx, Http2Settings settings,
Promise<Void> promise) {
outstandingLocalSettingsQueue.add(settings);
try {
Boolean pushEnabled = settings.pushEnabled();
@ -301,17 +303,16 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
@Override
public ChannelFuture writeSettingsAck(ChannelHandlerContext ctx, ChannelPromise promise) {
public Future<Void> writeSettingsAck(ChannelHandlerContext ctx, Promise<Void> promise) {
if (outstandingRemoteSettingsQueue == null) {
return frameWriter.writeSettingsAck(ctx, promise);
}
Http2Settings settings = outstandingRemoteSettingsQueue.poll();
if (settings == null) {
return promise.setFailure(new Http2Exception(INTERNAL_ERROR, "attempted to write a SETTINGS ACK with no " +
" pending SETTINGS"));
" pending SETTINGS"));
}
SimpleChannelPromiseAggregator aggregator = new SimpleChannelPromiseAggregator(promise, ctx.channel(),
ctx.executor());
SimpleChannelPromiseAggregator aggregator = new SimpleChannelPromiseAggregator(promise, ctx.executor());
// Acknowledge receipt of the settings. We should do this before we process the settings to ensure our
// remote peer applies these settings before any subsequent frames that we may send which depend upon
// these new settings. See https://github.com/netty/netty/issues/6520.
@ -319,10 +320,10 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
// We create a "new promise" to make sure that status from both the write and the application are taken into
// account independently.
ChannelPromise applySettingsPromise = aggregator.newPromise();
Promise<Void> applySettingsPromise = aggregator.newPromise();
try {
remoteSettings(settings);
applySettingsPromise.setSuccess();
applySettingsPromise.setSuccess(null);
} catch (Throwable e) {
applySettingsPromise.setFailure(e);
lifecycleManager.onError(ctx, true, e);
@ -331,13 +332,13 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
@Override
public ChannelFuture writePing(ChannelHandlerContext ctx, boolean ack, long data, ChannelPromise promise) {
public Future<Void> writePing(ChannelHandlerContext ctx, boolean ack, long data, Promise<Void> promise) {
return frameWriter.writePing(ctx, ack, data, promise);
}
@Override
public ChannelFuture writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, ChannelPromise promise) {
public Future<Void> writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, Promise<Void> promise) {
try {
if (connection.goAwayReceived()) {
throw connectionError(PROTOCOL_ERROR, "Sending PUSH_PROMISE after GO_AWAY received.");
@ -347,7 +348,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
// Reserve the promised stream.
connection.local().reservePushStream(promisedStreamId, stream);
ChannelFuture future = frameWriter.writePushPromise(ctx, streamId, promisedStreamId, headers, padding,
Future<Void> future = frameWriter.writePushPromise(ctx, streamId, promisedStreamId, headers, padding,
promise);
// Writing headers may fail during the encode state if they violate HPACK limits.
Throwable failureCause = future.cause();
@ -372,21 +373,21 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
@Override
public ChannelFuture writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData,
ChannelPromise promise) {
public Future<Void> writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData,
Promise<Void> promise) {
return lifecycleManager.goAway(ctx, lastStreamId, errorCode, debugData, promise);
}
@Override
public ChannelFuture writeWindowUpdate(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement,
ChannelPromise promise) {
public Future<Void> writeWindowUpdate(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement,
Promise<Void> promise) {
return promise.setFailure(new UnsupportedOperationException("Use the Http2[Inbound|Outbound]FlowController" +
" objects to control window sizes"));
" objects to control window sizes"));
}
@Override
public ChannelFuture writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
ByteBuf payload, ChannelPromise promise) {
public Future<Void> writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId, Http2Flags flags,
ByteBuf payload, Promise<Void> promise) {
return frameWriter.writeFrame(ctx, frameType, streamId, flags, payload, promise);
}
@ -441,9 +442,9 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
private int dataSize;
FlowControlledData(Http2Stream stream, ByteBuf buf, int padding, boolean endOfStream,
ChannelPromise promise) {
Promise<Void> promise, Channel channel) {
super(stream, padding, endOfStream, promise);
queue = new CoalescingBufferQueue(promise.channel());
queue = new CoalescingBufferQueue(channel);
queue.add(buf, promise);
dataSize = queue.readableBytes();
}
@ -481,7 +482,8 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
// There's no need to write any data frames because there are only empty data frames in the
// queue and it is not end of stream yet. Just complete their promises by getting the buffer
// corresponding to 0 bytes and writing it to the channel (to preserve notification order).
ChannelPromise writePromise = ctx.newPromise().addListener(this);
Promise<Void> writePromise = ctx.newPromise();
writePromise.addListener(this);
ctx.write(queue.remove(0, writePromise), writePromise);
}
return;
@ -494,7 +496,8 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
// Determine how much data to write.
int writableData = min(queuedData, allowedBytes);
ChannelPromise writePromise = ctx.newPromise().addListener(this);
Promise<Void> writePromise = ctx.newPromise();
writePromise.addListener(this);
ByteBuf toWrite = queue.remove(writableData, writePromise);
dataSize = queue.readableBytes();
@ -523,8 +526,8 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
}
private void notifyLifecycleManagerOnError(ChannelFuture future, final ChannelHandlerContext ctx) {
future.addListener((ChannelFutureListener) future1 -> {
private void notifyLifecycleManagerOnError(Future<Void> future, final ChannelHandlerContext ctx) {
future.addListener(future1 -> {
Throwable cause = future1.cause();
if (cause != null) {
lifecycleManager.onError(ctx, true, cause);
@ -546,7 +549,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
FlowControlledHeaders(Http2Stream stream, Http2Headers headers, boolean hasPriority,
int streamDependency, short weight, boolean exclusive,
int padding, boolean endOfStream, ChannelPromise promise) {
int padding, boolean endOfStream, Promise<Void> promise) {
super(stream, padding, endOfStream, promise);
this.headers = headers;
this.hasPriority = hasPriority;
@ -575,8 +578,8 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
// closeStreamLocal().
promise.addListener(this);
ChannelFuture f = sendHeaders(frameWriter, ctx, stream.id(), headers, hasPriority, streamDependency,
weight, exclusive, padding, endOfStream, promise);
Future<Void> f = sendHeaders(frameWriter, ctx, stream.id(), headers, hasPriority, streamDependency,
weight, exclusive, padding, endOfStream, promise);
// Writing headers may fail during the encode state if they violate HPACK limits.
Throwable failureCause = f.cause();
if (failureCause == null) {
@ -595,15 +598,14 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
/**
* Common base type for payloads to deliver via flow-control.
*/
public abstract class FlowControlledBase implements Http2RemoteFlowController.FlowControlled,
ChannelFutureListener {
public abstract class FlowControlledBase implements Http2RemoteFlowController.FlowControlled, FutureListener<Void> {
protected final Http2Stream stream;
protected ChannelPromise promise;
protected Promise<Void> promise;
protected boolean endOfStream;
protected int padding;
FlowControlledBase(final Http2Stream stream, int padding, boolean endOfStream,
final ChannelPromise promise) {
final Promise<Void> promise) {
checkPositiveOrZero(padding, "padding");
this.padding = padding;
this.endOfStream = endOfStream;
@ -619,7 +621,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht
}
@Override
public void operationComplete(ChannelFuture future) throws Exception {
public void operationComplete(Future<? extends Void> future) throws Exception {
if (!future.isSuccess()) {
error(flowController().channelHandlerContext(), future.cause());
}

View File

@ -16,12 +16,12 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http2.Http2CodecUtil.SimpleChannelPromiseAggregator;
import io.netty.handler.codec.http2.Http2FrameWriter.Configuration;
import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import static io.netty.buffer.Unpooled.directBuffer;
@ -132,10 +132,10 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
public void close() { }
@Override
public ChannelFuture writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data,
int padding, boolean endStream, ChannelPromise promise) {
public Future<Void> writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data,
int padding, boolean endStream, Promise<Void> promise) {
final SimpleChannelPromiseAggregator promiseAggregator =
new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
new SimpleChannelPromiseAggregator(promise, ctx.executor());
ByteBuf frameHeader = null;
try {
verifyStreamId(streamId, STREAM_ID);
@ -254,23 +254,23 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int padding, boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int padding, boolean endStream, Promise<Void> promise) {
return writeHeadersInternal(ctx, streamId, headers, padding, endStream,
false, 0, (short) 0, false, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int streamDependency, short weight, boolean exclusive,
int padding, boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int streamDependency, short weight, boolean exclusive,
int padding, boolean endStream, Promise<Void> promise) {
return writeHeadersInternal(ctx, streamId, headers, padding, endStream,
true, streamDependency, weight, exclusive, promise);
}
@Override
public ChannelFuture writePriority(ChannelHandlerContext ctx, int streamId,
int streamDependency, short weight, boolean exclusive, ChannelPromise promise) {
public Future<Void> writePriority(ChannelHandlerContext ctx, int streamId,
int streamDependency, short weight, boolean exclusive, Promise<Void> promise) {
try {
verifyStreamId(streamId, STREAM_ID);
verifyStreamOrConnectionId(streamDependency, STREAM_DEPENDENCY);
@ -288,8 +288,8 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise) {
public Future<Void> writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise) {
try {
verifyStreamId(streamId, STREAM_ID);
verifyErrorCode(errorCode);
@ -304,8 +304,8 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writeSettings(ChannelHandlerContext ctx, Http2Settings settings,
ChannelPromise promise) {
public Future<Void> writeSettings(ChannelHandlerContext ctx, Http2Settings settings,
Promise<Void> promise) {
try {
requireNonNull(settings, "settings");
int payloadLength = SETTING_ENTRY_LENGTH * settings.size();
@ -322,7 +322,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writeSettingsAck(ChannelHandlerContext ctx, ChannelPromise promise) {
public Future<Void> writeSettingsAck(ChannelHandlerContext ctx, Promise<Void> promise) {
try {
ByteBuf buf = ctx.alloc().buffer(FRAME_HEADER_LENGTH);
writeFrameHeaderInternal(buf, 0, SETTINGS, new Http2Flags().ack(true), 0);
@ -333,7 +333,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writePing(ChannelHandlerContext ctx, boolean ack, long data, ChannelPromise promise) {
public Future<Void> writePing(ChannelHandlerContext ctx, boolean ack, long data, Promise<Void> promise) {
Http2Flags flags = ack ? new Http2Flags().ack(true) : new Http2Flags();
ByteBuf buf = ctx.alloc().buffer(FRAME_HEADER_LENGTH + PING_FRAME_PAYLOAD_LENGTH);
// Assume nothing below will throw until buf is written. That way we don't have to take care of ownership
@ -344,11 +344,10 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writePushPromise(ChannelHandlerContext ctx, int streamId,
int promisedStreamId, Http2Headers headers, int padding, ChannelPromise promise) {
public Future<Void> writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, Promise<Void> promise) {
ByteBuf headerBlock = null;
SimpleChannelPromiseAggregator promiseAggregator =
new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
SimpleChannelPromiseAggregator promiseAggregator = new SimpleChannelPromiseAggregator(promise, ctx.executor());
try {
verifyStreamId(streamId, STREAM_ID);
verifyStreamId(promisedStreamId, "Promised Stream ID");
@ -402,10 +401,9 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, ChannelPromise promise) {
SimpleChannelPromiseAggregator promiseAggregator =
new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
public Future<Void> writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, Promise<Void> promise) {
SimpleChannelPromiseAggregator promiseAggregator = new SimpleChannelPromiseAggregator(promise, ctx.executor());
try {
verifyStreamOrConnectionId(lastStreamId, "Last Stream ID");
verifyErrorCode(errorCode);
@ -437,8 +435,8 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writeWindowUpdate(ChannelHandlerContext ctx, int streamId,
int windowSizeIncrement, ChannelPromise promise) {
public Future<Void> writeWindowUpdate(ChannelHandlerContext ctx, int streamId,
int windowSizeIncrement, Promise<Void> promise) {
try {
verifyStreamOrConnectionId(streamId, STREAM_ID);
verifyWindowSizeIncrement(windowSizeIncrement);
@ -453,10 +451,9 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
@Override
public ChannelFuture writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, ChannelPromise promise) {
SimpleChannelPromiseAggregator promiseAggregator =
new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
public Future<Void> writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, Promise<Void> promise) {
SimpleChannelPromiseAggregator promiseAggregator = new SimpleChannelPromiseAggregator(promise, ctx.executor());
try {
verifyStreamOrConnectionId(streamId, STREAM_ID);
ByteBuf buf = ctx.alloc().buffer(FRAME_HEADER_LENGTH);
@ -481,12 +478,11 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
return promiseAggregator.doneAllocatingPromises();
}
private ChannelFuture writeHeadersInternal(ChannelHandlerContext ctx,
private Future<Void> writeHeadersInternal(ChannelHandlerContext ctx,
int streamId, Http2Headers headers, int padding, boolean endStream,
boolean hasPriority, int streamDependency, short weight, boolean exclusive, ChannelPromise promise) {
boolean hasPriority, int streamDependency, short weight, boolean exclusive, Promise<Void> promise) {
ByteBuf headerBlock = null;
SimpleChannelPromiseAggregator promiseAggregator =
new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
SimpleChannelPromiseAggregator promiseAggregator = new SimpleChannelPromiseAggregator(promise, ctx.executor());
try {
verifyStreamId(streamId, STREAM_ID);
if (hasPriority) {
@ -551,7 +547,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
/**
* Writes as many continuation frames as needed until {@code padding} and {@code headerBlock} are consumed.
*/
private ChannelFuture writeContinuationFrames(ChannelHandlerContext ctx, int streamId,
private Future<Void> writeContinuationFrames(ChannelHandlerContext ctx, int streamId,
ByteBuf headerBlock, SimpleChannelPromiseAggregator promiseAggregator) {
Http2Flags flags = new Http2Flags();

View File

@ -18,13 +18,12 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelPromise;
import io.netty.handler.ssl.ApplicationProtocolNames;
import io.netty.util.AsciiString;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import static io.netty.buffer.Unpooled.directBuffer;
@ -255,18 +254,18 @@ public final class Http2CodecUtil {
}
/**
* Provides the ability to associate the outcome of multiple {@link ChannelPromise}
* objects into a single {@link ChannelPromise} object.
* Provides the ability to associate the outcome of multiple {@link Promise}
* objects into a single {@link Promise} object.
*/
static final class SimpleChannelPromiseAggregator extends DefaultChannelPromise {
private final ChannelPromise promise;
static final class SimpleChannelPromiseAggregator extends DefaultPromise<Void> {
private final Promise<Void> promise;
private int expectedCount;
private int doneCount;
private Throwable aggregateFailure;
private boolean doneAllocating;
SimpleChannelPromiseAggregator(ChannelPromise promise, Channel c, EventExecutor e) {
super(c, e);
SimpleChannelPromiseAggregator(Promise<Void> promise, EventExecutor e) {
super(e);
assert promise != null && !promise.isDone();
this.promise = promise;
}
@ -276,7 +275,7 @@ public final class Http2CodecUtil {
* @return A new promise which will be aggregated.
* {@code null} if {@link #doneAllocatingPromises()} was previously called.
*/
public ChannelPromise newPromise() {
public Promise<Void> newPromise() {
assert !doneAllocating : "Done allocating. No more promises can be allocated.";
++expectedCount;
return this;
@ -287,7 +286,7 @@ public final class Http2CodecUtil {
* The aggregation can not be successful until this method is called.
* @return The promise that is the aggregation of all promises allocated with {@link #newPromise()}.
*/
public ChannelPromise doneAllocatingPromises() {
public Promise<Void> doneAllocatingPromises() {
if (!doneAllocating) {
doneAllocating = true;
if (doneCount == expectedCount || expectedCount == 0) {
@ -319,7 +318,7 @@ public final class Http2CodecUtil {
* because that may be expected.
*/
@Override
public ChannelPromise setFailure(Throwable cause) {
public Promise<Void> setFailure(Throwable cause) {
if (allowFailure()) {
++doneCount;
setAggregateFailure(cause);
@ -331,7 +330,7 @@ public final class Http2CodecUtil {
}
@Override
public ChannelPromise setSuccess(Void result) {
public Promise<Void> setSuccess(Void result) {
if (awaitingPromises()) {
++doneCount;
if (allPromisesDone()) {
@ -367,9 +366,9 @@ public final class Http2CodecUtil {
return doneCount == expectedCount && doneAllocating;
}
private ChannelPromise setPromise() {
private Promise<Void> setPromise() {
if (aggregateFailure == null) {
promise.setSuccess();
promise.setSuccess(null);
return super.setSuccess(null);
} else {
promise.setFailure(aggregateFailure);
@ -379,7 +378,7 @@ public final class Http2CodecUtil {
private boolean tryPromise() {
if (aggregateFailure == null) {
promise.trySuccess();
promise.trySuccess(null);
return super.trySuccess(null);
} else {
promise.tryFailure(aggregateFailure);

View File

@ -15,9 +15,9 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
@ -61,8 +61,9 @@ public interface Http2ConnectionEncoder extends Http2FrameWriter {
/**
* Writes the given data to the internal {@link Http2FrameWriter} without performing any
* state checks on the connection/stream.
* @return
*/
@Override
ChannelFuture writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, ChannelPromise promise);
Future<Void> writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, Promise<Void> promise);
}

View File

@ -17,15 +17,16 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http2.Http2Exception.CompositeStreamException;
import io.netty.handler.codec.http2.Http2Exception.StreamException;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.ScheduledFuture;
import io.netty.util.internal.UnstableApi;
import io.netty.util.internal.logging.InternalLogger;
@ -74,7 +75,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
private final Http2ConnectionEncoder encoder;
private final Http2Settings initialSettings;
private final boolean decoupleCloseAndGoAway;
private ChannelFutureListener closeListener;
private FutureListener<Object> closeListener;
private BaseDecoder byteDecoder;
private long gracefulShutdownTimeoutMillis;
@ -352,12 +353,12 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
final boolean isClient = !connection().isServer();
if (isClient) {
// Clients must send the preface string as the first bytes on the connection.
ctx.write(connectionPrefaceBuf()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
ctx.write(connectionPrefaceBuf()).addListener(ctx.channel(), ChannelFutureListeners.CLOSE_ON_FAILURE);
}
// Both client and server must send their initial settings.
encoder.writeSettings(ctx, initialSettings, ctx.newPromise()).addListener(
ChannelFutureListener.CLOSE_ON_FAILURE);
encoder.writeSettings(ctx, initialSettings, ctx.newPromise())
.addListener(ctx.channel(), ChannelFutureListeners.CLOSE_ON_FAILURE);
if (isClient) {
// If this handler is extended by the user and we directly fire the userEvent from this context then
@ -436,23 +437,23 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
}
@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, Promise<Void> promise) {
ctx.bind(localAddress, promise);
}
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) {
Promise<Void> promise) {
ctx.connect(remoteAddress, localAddress, promise);
}
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
public void disconnect(ChannelHandlerContext ctx, Promise<Void> promise) {
ctx.disconnect(promise);
}
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
public void close(ChannelHandlerContext ctx, Promise<Void> promise) {
if (decoupleCloseAndGoAway) {
ctx.close(promise);
return;
@ -468,21 +469,21 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
// a GO_AWAY has been sent we send a empty buffer just so we can wait to close until all other data has been
// flushed to the OS.
// https://github.com/netty/netty/issues/5307
ChannelFuture f = connection().goAwaySent() ? ctx.write(EMPTY_BUFFER) : goAway(ctx, null, ctx.newPromise());
Future<Void> f = connection().goAwaySent() ? ctx.write(EMPTY_BUFFER) : goAway(ctx, null, ctx.newPromise());
ctx.flush();
doGracefulShutdown(ctx, f, promise);
}
private ChannelFutureListener newClosingChannelFutureListener(
ChannelHandlerContext ctx, ChannelPromise promise) {
private FutureListener<Object> newClosingChannelFutureListener(
ChannelHandlerContext ctx, Promise<Void> promise) {
long gracefulShutdownTimeoutMillis = this.gracefulShutdownTimeoutMillis;
return gracefulShutdownTimeoutMillis < 0 ?
new ClosingChannelFutureListener(ctx, promise) :
new ClosingChannelFutureListener(ctx, promise, gracefulShutdownTimeoutMillis, MILLISECONDS);
}
private void doGracefulShutdown(ChannelHandlerContext ctx, ChannelFuture future, final ChannelPromise promise) {
final ChannelFutureListener listener = newClosingChannelFutureListener(ctx, promise);
private void doGracefulShutdown(ChannelHandlerContext ctx, Future<Void> future, final Promise<Void> promise) {
FutureListener<Object> listener = newClosingChannelFutureListener(ctx, promise);
if (isGracefulShutdownComplete()) {
// If there are no active streams, close immediately after the GO_AWAY write completes or the timeout
// elapsed.
@ -495,7 +496,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
if (closeListener == null) {
closeListener = listener;
} else if (promise != null) {
final ChannelFutureListener oldCloseListener = closeListener;
FutureListener<Object> oldCloseListener = closeListener;
closeListener = future1 -> {
try {
oldCloseListener.operationComplete(future1);
@ -508,12 +509,12 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
}
@Override
public void register(ChannelHandlerContext ctx, ChannelPromise promise) {
public void register(ChannelHandlerContext ctx, Promise<Void> promise) {
ctx.register(promise);
}
@Override
public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) {
public void deregister(ChannelHandlerContext ctx, Promise<Void> promise) {
ctx.deregister(promise);
}
@ -523,7 +524,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
ctx.write(msg, promise);
}
@ -574,7 +575,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
* @param future If closing, the future after which to close the channel.
*/
@Override
public void closeStreamLocal(Http2Stream stream, ChannelFuture future) {
public void closeStreamLocal(Http2Stream stream, Future<Void> future) {
switch (stream.state()) {
case HALF_CLOSED_LOCAL:
case OPEN:
@ -594,7 +595,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
* @param future If closing, the future after which to close the channel.
*/
@Override
public void closeStreamRemote(Http2Stream stream, ChannelFuture future) {
public void closeStreamRemote(Http2Stream stream, Future<Void> future) {
switch (stream.state()) {
case HALF_CLOSED_REMOTE:
case OPEN:
@ -607,13 +608,13 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
}
@Override
public void closeStream(final Http2Stream stream, ChannelFuture future) {
public void closeStream(final Http2Stream stream, Future<Void> future) {
stream.close();
if (future.isDone()) {
checkCloseConnection(future);
} else {
future.addListener((ChannelFutureListener) this::checkCloseConnection);
future.addListener(this::checkCloseConnection);
}
}
@ -661,8 +662,8 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
http2Ex = new Http2Exception(INTERNAL_ERROR, cause.getMessage(), cause);
}
ChannelPromise promise = ctx.newPromise();
ChannelFuture future = goAway(ctx, http2Ex, ctx.newPromise());
Promise<Void> promise = ctx.newPromise();
Future<Void> future = goAway(ctx, http2Ex, ctx.newPromise());
if (http2Ex.shutdownHint() == Http2Exception.ShutdownHint.GRACEFUL_SHUTDOWN) {
doGracefulShutdown(ctx, future, promise);
} else {
@ -743,20 +744,20 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
* triggered by the first frame of a stream being invalid. That is, there was an error reading the frame before
* we could create a new stream.
*/
private ChannelFuture resetUnknownStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise) {
ChannelFuture future = frameWriter().writeRstStream(ctx, streamId, errorCode, promise);
private Future<Void> resetUnknownStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise) {
Future<Void> future = frameWriter().writeRstStream(ctx, streamId, errorCode, promise);
if (future.isDone()) {
closeConnectionOnError(ctx, future);
} else {
future.addListener((ChannelFutureListener) future1 -> closeConnectionOnError(ctx, future1));
future.addListener(ctx, this::closeConnectionOnError);
}
return future;
}
@Override
public ChannelFuture resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise) {
public Future<Void> resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise) {
final Http2Stream stream = connection().stream(streamId);
if (stream == null) {
return resetUnknownStream(ctx, streamId, errorCode, promise);
@ -765,11 +766,11 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
return resetStream(ctx, stream, errorCode, promise);
}
private ChannelFuture resetStream(final ChannelHandlerContext ctx, final Http2Stream stream,
long errorCode, ChannelPromise promise) {
private Future<Void> resetStream(final ChannelHandlerContext ctx, final Http2Stream stream,
long errorCode, Promise<Void> promise) {
if (stream.isResetSent()) {
// Don't write a RST_STREAM frame if we have already written one.
return promise.setSuccess();
return promise.setSuccess(null);
}
// Synchronously set the resetSent flag to prevent any subsequent calls
// from resulting in multiple reset frames being sent.
@ -778,32 +779,32 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
// call resetStream(...) again.
stream.resetSent();
final ChannelFuture future;
final Future<Void> future;
// If the remote peer is not aware of the steam, then we are not allowed to send a RST_STREAM
// https://tools.ietf.org/html/rfc7540#section-6.4.
if (stream.state() == IDLE ||
connection().local().created(stream) && !stream.isHeadersSent() && !stream.isPushPromiseSent()) {
future = promise.setSuccess();
future = promise.setSuccess(null);
} else {
future = frameWriter().writeRstStream(ctx, stream.id(), errorCode, promise);
}
if (future.isDone()) {
processRstStreamWriteResult(ctx, stream, future);
} else {
future.addListener((ChannelFutureListener) future1 -> processRstStreamWriteResult(ctx, stream, future1));
future.addListener(future1 -> processRstStreamWriteResult(ctx, stream, future1));
}
return future;
}
@Override
public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
final ByteBuf debugData, ChannelPromise promise) {
public Future<Void> goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
final ByteBuf debugData, Promise<Void> promise) {
final Http2Connection connection = connection();
try {
if (!connection.goAwaySent(lastStreamId, errorCode, debugData)) {
debugData.release();
promise.trySuccess();
promise.trySuccess(null);
return promise;
}
} catch (Throwable cause) {
@ -815,12 +816,12 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
// Need to retain before we write the buffer because if we do it after the refCnt could already be 0 and
// result in an IllegalRefCountException.
debugData.retain();
ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise);
Future<Void> future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise);
if (future.isDone()) {
processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
} else {
future.addListener((ChannelFutureListener) future1 ->
future.addListener(future1 ->
processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future1));
}
@ -831,11 +832,11 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
* Closes the connection if the graceful shutdown process has completed.
* @param future Represents the status that will be passed to the {@link #closeListener}.
*/
private void checkCloseConnection(ChannelFuture future) {
private void checkCloseConnection(Future<?> future) {
// If this connection is closing and the graceful shutdown has completed, close the connection
// once this operation completes.
if (closeListener != null && isGracefulShutdownComplete()) {
ChannelFutureListener closeListener = this.closeListener;
FutureListener<Object> closeListener = this.closeListener;
// This method could be called multiple times
// and we don't want to notify the closeListener multiple times.
this.closeListener = null;
@ -851,7 +852,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
* Close the remote endpoint with with a {@code GO_AWAY} frame. Does <strong>not</strong> flush
* immediately, this is the responsibility of the caller.
*/
private ChannelFuture goAway(ChannelHandlerContext ctx, Http2Exception cause, ChannelPromise promise) {
private Future<Void> goAway(ChannelHandlerContext ctx, Http2Exception cause, Promise<Void> promise) {
long errorCode = cause != null ? cause.error().code() : NO_ERROR.code();
int lastKnownStream;
if (cause != null && cause.shutdownHint() == Http2Exception.ShutdownHint.HARD_SHUTDOWN) {
@ -866,16 +867,17 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
return goAway(ctx, lastKnownStream, errorCode, Http2CodecUtil.toByteBuf(ctx, cause), promise);
}
private void processRstStreamWriteResult(ChannelHandlerContext ctx, Http2Stream stream, ChannelFuture future) {
@SuppressWarnings("unchecked")
private void processRstStreamWriteResult(ChannelHandlerContext ctx, Http2Stream stream, Future<?> future) {
if (future.isSuccess()) {
closeStream(stream, future);
closeStream(stream, (Future<Void>) future);
} else {
// The connection will be closed and so no need to change the resetSent flag to false.
onConnectionError(ctx, true, future.cause(), null);
}
}
private void closeConnectionOnError(ChannelHandlerContext ctx, ChannelFuture future) {
private void closeConnectionOnError(ChannelHandlerContext ctx, Future<?> future) {
if (!future.isSuccess()) {
onConnectionError(ctx, true, future.cause(), null);
}
@ -889,7 +891,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
}
private static void processGoAwayWriteResult(final ChannelHandlerContext ctx, final int lastStreamId,
final long errorCode, final ByteBuf debugData, ChannelFuture future) {
final long errorCode, final ByteBuf debugData, Future<?> future) {
try {
if (future.isSuccess()) {
if (errorCode != NO_ERROR.code()) {
@ -917,19 +919,19 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
/**
* Closes the channel when the future completes.
*/
private static final class ClosingChannelFutureListener implements ChannelFutureListener {
private static final class ClosingChannelFutureListener implements FutureListener<Object> {
private final ChannelHandlerContext ctx;
private final ChannelPromise promise;
private final Promise<Void> promise;
private final ScheduledFuture<?> timeoutTask;
private boolean closed;
ClosingChannelFutureListener(ChannelHandlerContext ctx, ChannelPromise promise) {
ClosingChannelFutureListener(ChannelHandlerContext ctx, Promise<Void> promise) {
this.ctx = ctx;
this.promise = promise;
timeoutTask = null;
}
ClosingChannelFutureListener(final ChannelHandlerContext ctx, final ChannelPromise promise,
ClosingChannelFutureListener(final ChannelHandlerContext ctx, final Promise<Void> promise,
long timeout, TimeUnit unit) {
this.ctx = ctx;
this.promise = promise;
@ -937,7 +939,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
}
@Override
public void operationComplete(ChannelFuture sentGoAwayFuture) {
public void operationComplete(Future<?> sentGoAwayFuture) {
if (timeoutTask != null) {
timeoutTask.cancel(false);
}

View File

@ -14,10 +14,10 @@
*/
package io.netty.handler.codec.http2;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -31,14 +31,9 @@ final class Http2ControlFrameLimitEncoder extends DecoratingHttp2ConnectionEncod
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2ControlFrameLimitEncoder.class);
private final int maxOutstandingControlFrames;
private final ChannelFutureListener outstandingControlFramesListener = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
outstandingControlFrames--;
}
};
private Http2LifecycleManager lifecycleManager;
private int outstandingControlFrames;
private final FutureListener<Void> outstandingControlFramesListener = future -> outstandingControlFrames--;
private boolean limitReached;
Http2ControlFrameLimitEncoder(Http2ConnectionEncoder delegate, int maxOutstandingControlFrames) {
@ -54,8 +49,8 @@ final class Http2ControlFrameLimitEncoder extends DecoratingHttp2ConnectionEncod
}
@Override
public ChannelFuture writeSettingsAck(ChannelHandlerContext ctx, ChannelPromise promise) {
ChannelPromise newPromise = handleOutstandingControlFrames(ctx, promise);
public Future<Void> writeSettingsAck(ChannelHandlerContext ctx, Promise<Void> promise) {
Promise<Void> newPromise = handleOutstandingControlFrames(ctx, promise);
if (newPromise == null) {
return promise;
}
@ -63,10 +58,10 @@ final class Http2ControlFrameLimitEncoder extends DecoratingHttp2ConnectionEncod
}
@Override
public ChannelFuture writePing(ChannelHandlerContext ctx, boolean ack, long data, ChannelPromise promise) {
public Future<Void> writePing(ChannelHandlerContext ctx, boolean ack, long data, Promise<Void> promise) {
// Only apply the limit to ping acks.
if (ack) {
ChannelPromise newPromise = handleOutstandingControlFrames(ctx, promise);
Promise<Void> newPromise = handleOutstandingControlFrames(ctx, promise);
if (newPromise == null) {
return promise;
}
@ -76,16 +71,16 @@ final class Http2ControlFrameLimitEncoder extends DecoratingHttp2ConnectionEncod
}
@Override
public ChannelFuture writeRstStream(
ChannelHandlerContext ctx, int streamId, long errorCode, ChannelPromise promise) {
ChannelPromise newPromise = handleOutstandingControlFrames(ctx, promise);
public Future<Void> writeRstStream(
ChannelHandlerContext ctx, int streamId, long errorCode, Promise<Void> promise) {
Promise<Void> newPromise = handleOutstandingControlFrames(ctx, promise);
if (newPromise == null) {
return promise;
}
return super.writeRstStream(ctx, streamId, errorCode, newPromise);
}
private ChannelPromise handleOutstandingControlFrames(ChannelHandlerContext ctx, ChannelPromise promise) {
private Promise<Void> handleOutstandingControlFrames(ChannelHandlerContext ctx, Promise<Void> promise) {
if (!limitReached) {
if (outstandingControlFrames == maxOutstandingControlFrames) {
// Let's try to flush once as we may be able to flush some of the control frames.
@ -106,7 +101,7 @@ final class Http2ControlFrameLimitEncoder extends DecoratingHttp2ConnectionEncod
// We did not reach the limit yet, add the listener to decrement the number of outstanding control frames
// once the promise was completed
return promise.addListener(outstandingControlFramesListener);
promise.addListener(outstandingControlFramesListener);
}
return promise;
}

View File

@ -15,9 +15,9 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
/**
@ -40,6 +40,6 @@ public interface Http2DataWriter {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writeData(ChannelHandlerContext ctx, int streamId,
ByteBuf data, int padding, boolean endStream, ChannelPromise promise);
Future<Void> writeData(ChannelHandlerContext ctx, int streamId,
ByteBuf data, int padding, boolean endStream, Promise<Void> promise);
}

View File

@ -17,10 +17,8 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.UnsupportedMessageTypeException;
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeEvent;
import io.netty.handler.codec.http2.Http2Connection.PropertyKey;
@ -32,6 +30,7 @@ import io.netty.util.ReferenceCounted;
import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.collection.IntObjectMap;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import io.netty.util.internal.logging.InternalLogLevel;
import io.netty.util.internal.logging.InternalLogger;
@ -91,10 +90,10 @@ import static io.netty.handler.codec.http2.Http2Error.NO_ERROR;
*
* <pre>{@code
* final Http2Stream2 stream = handler.newStream();
* ctx.write(headersFrame.stream(stream)).addListener(new ChannelFutureListener() {
* ctx.write(headersFrame.stream(stream)).addListener(new FutureListener<Void>() {
*
* @Override
* public void operationComplete(ChannelFuture f) {
* public void operationComplete(Future<Void> f) {
* if (f.isSuccess()) {
* // Stream is active and stream.id() returns a valid stream identifier.
* System.out.println("New stream with id " + stream.id() + " created.");
@ -112,7 +111,7 @@ import static io.netty.handler.codec.http2.Http2Error.NO_ERROR;
* }
* }</pre>
*
* <p>If a new stream cannot be created due to stream id exhaustion of the endpoint, the {@link ChannelPromise} of the
* <p>If a new stream cannot be created due to stream id exhaustion of the endpoint, the {@link Promise} of the
* HEADERS frame will fail with a {@link Http2NoMoreStreamIdsException}.
*
* <p>The HTTP/2 standard allows for an endpoint to limit the maximum number of concurrently active streams via the
@ -193,7 +192,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
if (connection().numActiveStreams() > 0) {
connection().forEachActiveStream(stream -> {
try {
return streamVisitor.visit((Http2FrameStream) stream.getProperty(streamKey));
return streamVisitor.visit(stream.getProperty(streamKey));
} catch (Throwable cause) {
onError(ctx, false, cause);
return false;
@ -282,7 +281,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
* streams.
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (msg instanceof Http2DataFrame) {
Http2DataFrame dataFrame = (Http2DataFrame) msg;
encoder().writeData(ctx, dataFrame.stream().id(), dataFrame.content(),
@ -300,7 +299,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
} else {
consumeBytes(frameStream.id(), frame.windowSizeIncrement());
}
promise.setSuccess();
promise.setSuccess(null);
} catch (Throwable t) {
promise.setFailure(t);
}
@ -355,7 +354,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
Http2Stream stream = connection().stream(streamId);
// Upgraded requests are ineligible for stream control. We add the null check
// in case the stream has been deregistered.
if (stream != null && streamId == Http2CodecUtil.HTTP_UPGRADE_STREAM_ID) {
if (stream != null && streamId == HTTP_UPGRADE_STREAM_ID) {
Boolean upgraded = stream.getProperty(upgradeKey);
if (Boolean.TRUE.equals(upgraded)) {
return false;
@ -365,7 +364,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
return connection().local().flowController().consumeBytes(stream, bytes);
}
private void writeGoAwayFrame(ChannelHandlerContext ctx, Http2GoAwayFrame frame, ChannelPromise promise) {
private void writeGoAwayFrame(ChannelHandlerContext ctx, Http2GoAwayFrame frame, Promise<Void> promise) {
if (frame.lastStreamId() > -1) {
frame.release();
throw new IllegalArgumentException("Last stream id must not be set on GOAWAY frame");
@ -381,7 +380,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
}
private void writeHeadersFrame(final ChannelHandlerContext ctx, Http2HeadersFrame headersFrame,
final ChannelPromise promise) {
final Promise<Void> promise) {
if (isStreamIdValid(headersFrame.stream().id())) {
encoder().writeHeaders(ctx, headersFrame.stream().id(), headersFrame.headers(), headersFrame.padding(),
@ -408,7 +407,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
}
private void writePushPromise(final ChannelHandlerContext ctx, Http2PushPromiseFrame pushPromiseFrame,
final ChannelPromise promise) {
final Promise<Void> promise) {
if (isStreamIdValid(pushPromiseFrame.pushStream().id())) {
encoder().writePushPromise(ctx, pushPromiseFrame.stream().id(), pushPromiseFrame.pushStream().id(),
pushPromiseFrame.http2Headers(), pushPromiseFrame.padding(), promise);
@ -423,7 +422,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
numBufferedStreams++;
// Clean up the stream being initialized if writing the headers fails and also
// decrement the number of buffered streams.
promise.addListener((ChannelFuture f) -> {
promise.addListener(f -> {
numBufferedStreams--;
handleHeaderFuture(f, streamId);
});
@ -432,7 +431,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
}
private boolean initializeNewStream(ChannelHandlerContext ctx, DefaultHttp2FrameStream http2FrameStream,
ChannelPromise promise) {
Promise<Void> promise) {
final Http2Connection connection = connection();
final int streamId = connection.local().incrementAndGetNextStreamId();
if (streamId < 0) {
@ -467,7 +466,7 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
}
private void onStreamActive0(Http2Stream stream) {
if (stream.id() != Http2CodecUtil.HTTP_UPGRADE_STREAM_ID &&
if (stream.id() != HTTP_UPGRADE_STREAM_ID &&
connection().local().isValidStreamId(stream.id())) {
return;
}

View File

@ -16,9 +16,9 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import java.io.Closeable;
@ -64,8 +64,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* <p>
* If this call has <strong>NOT</strong> modified the HPACK header state you are free to throw a stream error.
*/
ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int padding, boolean endStream, ChannelPromise promise);
Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int padding, boolean endStream, Promise<Void> promise);
/**
* Writes a HEADERS frame with priority specified to the remote endpoint.
@ -90,9 +90,9 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* <p>
* If this call has <strong>NOT</strong> modified the HPACK header state you are free to throw a stream error.
*/
ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int streamDependency, short weight, boolean exclusive, int padding, boolean endStream,
ChannelPromise promise);
Promise<Void> promise);
/**
* Writes a PRIORITY frame to the remote endpoint.
@ -106,8 +106,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writePriority(ChannelHandlerContext ctx, int streamId, int streamDependency,
short weight, boolean exclusive, ChannelPromise promise);
Future<Void> writePriority(ChannelHandlerContext ctx, int streamId, int streamDependency,
short weight, boolean exclusive, Promise<Void> promise);
/**
* Writes a RST_STREAM frame to the remote endpoint.
@ -118,8 +118,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise);
Future<Void> writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise);
/**
* Writes a SETTINGS frame to the remote endpoint.
@ -129,8 +129,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writeSettings(ChannelHandlerContext ctx, Http2Settings settings,
ChannelPromise promise);
Future<Void> writeSettings(ChannelHandlerContext ctx, Http2Settings settings,
Promise<Void> promise);
/**
* Writes a SETTINGS acknowledgment to the remote endpoint.
@ -139,7 +139,7 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writeSettingsAck(ChannelHandlerContext ctx, ChannelPromise promise);
Future<Void> writeSettingsAck(ChannelHandlerContext ctx, Promise<Void> promise);
/**
* Writes a PING frame to the remote endpoint.
@ -151,8 +151,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writePing(ChannelHandlerContext ctx, boolean ack, long data,
ChannelPromise promise);
Future<Void> writePing(ChannelHandlerContext ctx, boolean ack, long data,
Promise<Void> promise);
/**
* Writes a PUSH_PROMISE frame to the remote endpoint.
@ -173,8 +173,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* <p>
* If this call has <strong>NOT</strong> modified the HPACK header state you are free to throw a stream error.
*/
ChannelFuture writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, ChannelPromise promise);
Future<Void> writePushPromise(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding, Promise<Void> promise);
/**
* Writes a GO_AWAY frame to the remote endpoint.
@ -186,8 +186,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, ChannelPromise promise);
Future<Void> writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, Promise<Void> promise);
/**
* Writes a WINDOW_UPDATE frame to the remote endpoint.
@ -199,8 +199,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writeWindowUpdate(ChannelHandlerContext ctx, int streamId,
int windowSizeIncrement, ChannelPromise promise);
Future<Void> writeWindowUpdate(ChannelHandlerContext ctx, int streamId,
int windowSizeIncrement, Promise<Void> promise);
/**
* Generic write method for any HTTP/2 frame. This allows writing of non-standard frames.
@ -213,8 +213,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param promise the promise for the write.
* @return the future for the write.
*/
ChannelFuture writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, ChannelPromise promise);
Future<Void> writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, Promise<Void> promise);
/**
* Get the configuration related elements for this {@link Http2FrameWriter}

View File

@ -15,9 +15,9 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
/**
@ -29,19 +29,19 @@ public interface Http2LifecycleManager {
/**
* Closes the local side of the {@code stream}. Depending on the {@code stream} state this may result in
* {@code stream} being closed. See {@link #closeStream(Http2Stream, ChannelFuture)}.
* {@code stream} being closed. See {@link #closeStream(Http2Stream, Future)}.
* @param stream the stream to be half closed.
* @param future See {@link #closeStream(Http2Stream, ChannelFuture)}.
* @param future See {@link #closeStream(Http2Stream, Future)}.
*/
void closeStreamLocal(Http2Stream stream, ChannelFuture future);
void closeStreamLocal(Http2Stream stream, Future<Void> future);
/**
* Closes the remote side of the {@code stream}. Depending on the {@code stream} state this may result in
* {@code stream} being closed. See {@link #closeStream(Http2Stream, ChannelFuture)}.
* {@code stream} being closed. See {@link #closeStream(Http2Stream, Future)}.
* @param stream the stream to be half closed.
* @param future See {@link #closeStream(Http2Stream, ChannelFuture)}.
* @param future See {@link #closeStream(Http2Stream, Future)}.
*/
void closeStreamRemote(Http2Stream stream, ChannelFuture future);
void closeStreamRemote(Http2Stream stream, Future<Void> future);
/**
* Closes and deactivates the given {@code stream}. A listener is also attached to {@code future} and upon
@ -50,7 +50,7 @@ public interface Http2LifecycleManager {
* @param future when completed if {@link Http2Connection#numActiveStreams()} is 0 then the underlying channel
* will be closed.
*/
void closeStream(Http2Stream stream, ChannelFuture future);
void closeStream(Http2Stream stream, Future<Void> future);
/**
* Ensure the stream identified by {@code streamId} is reset. If our local state does not indicate the stream has
@ -64,8 +64,8 @@ public interface Http2LifecycleManager {
* {@code RST_STREAM} frame has been sent to the peer. If the stream state has already been updated and a
* {@code RST_STREAM} frame has been sent then the return status may indicate success immediately.
*/
ChannelFuture resetStream(ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise);
Future<Void> resetStream(ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise);
/**
* Prevents the peer from creating streams and close the connection if {@code errorCode} is not
@ -83,15 +83,15 @@ public interface Http2LifecycleManager {
* {@code GO_AWAY} frame has been sent to the peer. If the stream state has already been updated and a
* {@code GO_AWAY} frame has been sent then the return status may indicate success immediately.
*/
ChannelFuture goAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, ChannelPromise promise);
Future<Void> goAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, Promise<Void> promise);
/**
* Processes the given error.
*
* @param ctx The context used for communication and buffer allocation if necessary.
* @param outbound {@code true} if the error was caused by an outbound operation and so the corresponding
* {@link ChannelPromise} was failed as well.
* {@link Promise} was failed as well.
* @param cause the error.
*/
void onError(ChannelHandlerContext ctx, boolean outbound, Throwable cause);

View File

@ -18,13 +18,12 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.util.ReferenceCounted;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import java.util.ArrayDeque;
@ -178,11 +177,11 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
streamChannel = new Http2MultiplexCodecStreamChannel(stream, inboundStreamHandler);
}
ChannelFuture future = streamChannel.register();
Future<Void> future = streamChannel.register();
if (future.isDone()) {
Http2MultiplexHandler.registerDone(future);
Http2MultiplexHandler.registerDone(streamChannel, future);
} else {
future.addListener(Http2MultiplexHandler.CHILD_CHANNEL_REGISTRATION_LISTENER);
future.addListener(streamChannel, Http2MultiplexHandler.CHILD_CHANNEL_REGISTRATION_LISTENER);
}
break;
case CLOSED:
@ -312,8 +311,8 @@ public class Http2MultiplexCodec extends Http2FrameCodec {
}
@Override
protected ChannelFuture write0(ChannelHandlerContext ctx, Object msg) {
ChannelPromise promise = ctx.newPromise();
protected Future<Void> write0(ChannelHandlerContext ctx, Object msg) {
Promise<Void> promise = ctx.newPromise();
Http2MultiplexCodec.this.write(ctx, msg, promise);
return promise;
}

View File

@ -18,8 +18,6 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
@ -27,6 +25,8 @@ import io.netty.channel.EventLoop;
import io.netty.channel.ServerChannel;
import io.netty.handler.codec.http2.Http2FrameCodec.DefaultHttp2FrameStream;
import io.netty.util.ReferenceCounted;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureContextListener;
import io.netty.util.internal.UnstableApi;
import javax.net.ssl.SSLException;
@ -86,7 +86,8 @@ import static io.netty.handler.codec.http2.Http2Exception.connectionError;
@UnstableApi
public final class Http2MultiplexHandler extends Http2ChannelDuplexHandler {
static final ChannelFutureListener CHILD_CHANNEL_REGISTRATION_LISTENER = Http2MultiplexHandler::registerDone;
static final FutureContextListener<Channel, Void> CHILD_CHANNEL_REGISTRATION_LISTENER =
Http2MultiplexHandler::registerDone;
private final ChannelHandler inboundStreamHandler;
private final ChannelHandler upgradeStreamHandler;
@ -124,12 +125,11 @@ public final class Http2MultiplexHandler extends Http2ChannelDuplexHandler {
this.upgradeStreamHandler = upgradeStreamHandler;
}
static void registerDone(ChannelFuture future) {
static void registerDone(Channel childChannel, Future<?> future) {
// Handle any errors that occurred on the local thread while registering. Even though
// failures can happen after this point, they will be handled by the channel by closing the
// childChannel.
if (!future.isSuccess()) {
Channel childChannel = future.channel();
if (childChannel.isRegistered()) {
childChannel.close();
} else {
@ -231,11 +231,11 @@ public final class Http2MultiplexHandler extends Http2ChannelDuplexHandler {
} else {
ch = new Http2MultiplexHandlerStreamChannel(stream, inboundStreamHandler);
}
ChannelFuture future = ch.register();
Future<Void> future = ch.register();
if (future.isDone()) {
registerDone(future);
registerDone(ch, future);
} else {
future.addListener(CHILD_CHANNEL_REGISTRATION_LISTENER);
future.addListener(ch, CHILD_CHANNEL_REGISTRATION_LISTENER);
}
break;
case CLOSED:

View File

@ -15,15 +15,15 @@
*/
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import static io.netty.handler.codec.http2.Http2FrameLogger.Direction.OUTBOUND;
import static java.util.Objects.requireNonNull;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.internal.UnstableApi;
/**
* Decorator around a {@link Http2FrameWriter} that logs all outbound frames before calling the
* writer.
@ -39,23 +39,23 @@ public class Http2OutboundFrameLogger implements Http2FrameWriter {
}
@Override
public ChannelFuture writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data,
int padding, boolean endStream, ChannelPromise promise) {
public Future<Void> writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data,
int padding, boolean endStream, Promise<Void> promise) {
logger.logData(OUTBOUND, ctx, streamId, data, padding, endStream);
return writer.writeData(ctx, streamId, data, padding, endStream, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int padding, boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int padding, boolean endStream, Promise<Void> promise) {
logger.logHeaders(OUTBOUND, ctx, streamId, headers, padding, endStream);
return writer.writeHeaders(ctx, streamId, headers, padding, endStream, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int streamDependency, short weight, boolean exclusive,
int padding, boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId,
Http2Headers headers, int streamDependency, short weight, boolean exclusive,
int padding, boolean endStream, Promise<Void> promise) {
logger.logHeaders(OUTBOUND, ctx, streamId, headers, streamDependency, weight, exclusive,
padding, endStream);
return writer.writeHeaders(ctx, streamId, headers, streamDependency, weight,
@ -63,35 +63,35 @@ public class Http2OutboundFrameLogger implements Http2FrameWriter {
}
@Override
public ChannelFuture writePriority(ChannelHandlerContext ctx, int streamId,
int streamDependency, short weight, boolean exclusive, ChannelPromise promise) {
public Future<Void> writePriority(ChannelHandlerContext ctx, int streamId,
int streamDependency, short weight, boolean exclusive, Promise<Void> promise) {
logger.logPriority(OUTBOUND, ctx, streamId, streamDependency, weight, exclusive);
return writer.writePriority(ctx, streamId, streamDependency, weight, exclusive, promise);
}
@Override
public ChannelFuture writeRstStream(ChannelHandlerContext ctx,
int streamId, long errorCode, ChannelPromise promise) {
public Future<Void> writeRstStream(ChannelHandlerContext ctx,
int streamId, long errorCode, Promise<Void> promise) {
logger.logRstStream(OUTBOUND, ctx, streamId, errorCode);
return writer.writeRstStream(ctx, streamId, errorCode, promise);
}
@Override
public ChannelFuture writeSettings(ChannelHandlerContext ctx,
Http2Settings settings, ChannelPromise promise) {
public Future<Void> writeSettings(ChannelHandlerContext ctx,
Http2Settings settings, Promise<Void> promise) {
logger.logSettings(OUTBOUND, ctx, settings);
return writer.writeSettings(ctx, settings, promise);
}
@Override
public ChannelFuture writeSettingsAck(ChannelHandlerContext ctx, ChannelPromise promise) {
public Future<Void> writeSettingsAck(ChannelHandlerContext ctx, Promise<Void> promise) {
logger.logSettingsAck(OUTBOUND, ctx);
return writer.writeSettingsAck(ctx, promise);
}
@Override
public ChannelFuture writePing(ChannelHandlerContext ctx, boolean ack,
long data, ChannelPromise promise) {
public Future<Void> writePing(ChannelHandlerContext ctx, boolean ack,
long data, Promise<Void> promise) {
if (ack) {
logger.logPingAck(OUTBOUND, ctx, data);
} else {
@ -101,29 +101,30 @@ public class Http2OutboundFrameLogger implements Http2FrameWriter {
}
@Override
public ChannelFuture writePushPromise(ChannelHandlerContext ctx, int streamId,
int promisedStreamId, Http2Headers headers, int padding, ChannelPromise promise) {
public Future<Void> writePushPromise(ChannelHandlerContext ctx, int streamId,
int promisedStreamId, Http2Headers headers, int padding,
Promise<Void> promise) {
logger.logPushPromise(OUTBOUND, ctx, streamId, promisedStreamId, headers, padding);
return writer.writePushPromise(ctx, streamId, promisedStreamId, headers, padding, promise);
}
@Override
public ChannelFuture writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, ChannelPromise promise) {
public Future<Void> writeGoAway(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
ByteBuf debugData, Promise<Void> promise) {
logger.logGoAway(OUTBOUND, ctx, lastStreamId, errorCode, debugData);
return writer.writeGoAway(ctx, lastStreamId, errorCode, debugData, promise);
}
@Override
public ChannelFuture writeWindowUpdate(ChannelHandlerContext ctx,
int streamId, int windowSizeIncrement, ChannelPromise promise) {
public Future<Void> writeWindowUpdate(ChannelHandlerContext ctx,
int streamId, int windowSizeIncrement, Promise<Void> promise) {
logger.logWindowsUpdate(OUTBOUND, ctx, streamId, windowSizeIncrement);
return writer.writeWindowUpdate(ctx, streamId, windowSizeIncrement, promise);
}
@Override
public ChannelFuture writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, ChannelPromise promise) {
public Future<Void> writeFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
Http2Flags flags, ByteBuf payload, Promise<Void> promise) {
logger.logUnknownFrame(OUTBOUND, ctx, frameType, streamId, flags, payload);
return writer.writeFrame(ctx, frameType, streamId, flags, payload, promise);
}

View File

@ -15,11 +15,7 @@
*/
package io.netty.handler.codec.http2;
import static java.util.Objects.requireNonNull;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
@ -38,6 +34,8 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.Objects.requireNonNull;
@UnstableApi
public final class Http2StreamChannelBootstrap {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2StreamChannelBootstrap.class);
@ -186,8 +184,8 @@ public final class Http2StreamChannelBootstrap {
return;
}
ChannelFuture future = streamChannel.register();
future.addListener((ChannelFutureListener) future1 -> {
Future<Void> future = streamChannel.register();
future.addListener(future1 -> {
if (future1.isSuccess()) {
promise.setSuccess(streamChannel);
} else if (future1.isCancelled()) {

View File

@ -17,7 +17,6 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.EmptyHttpHeaders;
import io.netty.handler.codec.http.FullHttpMessage;
import io.netty.handler.codec.http.HttpContent;
@ -27,6 +26,7 @@ import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http2.Http2CodecUtil.SimpleChannelPromiseAggregator;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
/**
@ -77,7 +77,7 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
* Handles conversion of {@link HttpMessage} and {@link HttpContent} to HTTP/2 frames.
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (!(msg instanceof HttpMessage || msg instanceof HttpContent)) {
ctx.write(msg, promise);
@ -86,7 +86,7 @@ public class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {
boolean release = true;
SimpleChannelPromiseAggregator promiseAggregator =
new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
new SimpleChannelPromiseAggregator(promise, ctx.executor());
try {
Http2ConnectionEncoder encoder = encoder();
boolean endStream = false;

View File

@ -17,10 +17,10 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import java.util.ArrayDeque;
@ -153,16 +153,16 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int padding, boolean endStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int padding, boolean endStream, Promise<Void> promise) {
return writeHeaders(ctx, streamId, headers, 0, Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT,
false, padding, endStream, promise);
}
@Override
public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int streamDependency, short weight, boolean exclusive,
int padding, boolean endOfStream, ChannelPromise promise) {
public Future<Void> writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
int streamDependency, short weight, boolean exclusive,
int padding, boolean endOfStream, Promise<Void> promise) {
if (closed) {
return promise.setFailure(new Http2ChannelClosedException());
}
@ -184,8 +184,8 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
}
@Override
public ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
ChannelPromise promise) {
public Future<Void> writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
Promise<Void> promise) {
if (isExistingStream(streamId)) {
return super.writeRstStream(ctx, streamId, errorCode, promise);
}
@ -198,7 +198,7 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
// about the stream anymore and thus there is not point in failing the promises and invoking
// error handling routines.
stream.close(null);
promise.setSuccess();
promise.setSuccess(null);
} else {
promise.setFailure(connectionError(PROTOCOL_ERROR, "Stream does not exist %d", streamId));
}
@ -206,8 +206,8 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
}
@Override
public ChannelFuture writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data,
int padding, boolean endOfStream, ChannelPromise promise) {
public Future<Void> writeData(ChannelHandlerContext ctx, int streamId, ByteBuf data,
int padding, boolean endOfStream, Promise<Void> promise) {
if (isExistingStream(streamId)) {
return super.writeData(ctx, streamId, data, padding, endOfStream, promise);
}
@ -311,9 +311,9 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
}
private abstract static class Frame {
final ChannelPromise promise;
final Promise<Void> promise;
Frame(ChannelPromise promise) {
Frame(Promise<Void> promise) {
this.promise = promise;
}
@ -322,7 +322,7 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
*/
void release(Throwable t) {
if (t == null) {
promise.setSuccess();
promise.setSuccess(null);
} else {
promise.setFailure(t);
}
@ -340,7 +340,7 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
final boolean endOfStream;
HeadersFrame(Http2Headers headers, int streamDependency, short weight, boolean exclusive,
int padding, boolean endOfStream, ChannelPromise promise) {
int padding, boolean endOfStream, Promise<Void> promise) {
super(promise);
this.headers = headers;
this.streamDependency = streamDependency;
@ -361,7 +361,7 @@ public class StreamBufferingEncoder extends DecoratingHttp2ConnectionEncoder {
final int padding;
final boolean endOfStream;
DataFrame(ByteBuf data, int padding, boolean endOfStream, ChannelPromise promise) {
DataFrame(ByteBuf data, int padding, boolean endOfStream, Promise<Void> promise) {
super(promise);
this.data = data;
this.padding = padding;

View File

@ -23,7 +23,6 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MultithreadEventLoopGroup;
import io.netty.channel.nio.NioHandler;
import io.netty.channel.socket.nio.NioServerSocketChannel;
@ -34,6 +33,7 @@ import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import io.netty.util.NetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -432,7 +432,7 @@ public class DataCompressionHttp2Test {
return clientChannel.pipeline().firstContext();
}
private ChannelPromise newPromiseClient() {
private Promise<Void> newPromiseClient() {
return ctxClient().newPromise();
}
}

View File

@ -17,13 +17,13 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelPromise;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import junit.framework.AssertionFailedError;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -35,7 +35,6 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@ -48,11 +47,9 @@ import static io.netty.handler.codec.http2.Http2Stream.State.IDLE;
import static io.netty.handler.codec.http2.Http2Stream.State.OPEN;
import static io.netty.handler.codec.http2.Http2Stream.State.RESERVED_REMOTE;
import static io.netty.util.CharsetUtil.UTF_8;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -82,7 +79,7 @@ public class DefaultHttp2ConnectionDecoderTest {
private static final int STATE_RECV_TRAILERS = 1 << 1;
private Http2ConnectionDecoder decoder;
private ChannelPromise promise;
private Promise<Void> promise;
@Mock
private Http2Connection connection;
@ -106,7 +103,7 @@ public class DefaultHttp2ConnectionDecoderTest {
private Channel channel;
@Mock
private ChannelFuture future;
private Future<Void> future;
@Mock
private Http2Stream stream;
@ -133,7 +130,7 @@ public class DefaultHttp2ConnectionDecoderTest {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
promise = new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
promise = new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
final AtomicInteger headersReceivedState = new AtomicInteger();
when(channel.isActive()).thenReturn(true);
@ -623,6 +620,7 @@ public class DefaultHttp2ConnectionDecoderTest {
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true));
}
@SuppressWarnings("unchecked")
@Test
public void headersDependencyNotCreatedShouldCreateAndSucceed() throws Exception {
final short weight = 1;
@ -631,7 +629,7 @@ public class DefaultHttp2ConnectionDecoderTest {
verify(listener).onHeadersRead(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(STREAM_DEPENDENCY_ID),
eq(weight), eq(true), eq(0), eq(true));
verify(remoteFlow).updateDependencyTree(eq(STREAM_ID), eq(STREAM_DEPENDENCY_ID), eq(weight), eq(true));
verify(lifecycleManager).closeStreamRemote(eq(stream), any(ChannelFuture.class));
verify(lifecycleManager).closeStreamRemote(eq(stream), any(Future.class));
}
@Test

View File

@ -20,16 +20,16 @@ import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.DefaultChannelPromise;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http2.Http2RemoteFlowController.FlowControlled;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import junit.framework.AssertionFailedError;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -49,8 +49,8 @@ import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
import static io.netty.handler.codec.http2.Http2Stream.State.HALF_CLOSED_REMOTE;
import static io.netty.handler.codec.http2.Http2Stream.State.RESERVED_LOCAL;
import static io.netty.util.CharsetUtil.UTF_8;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -76,6 +76,7 @@ import static org.mockito.Mockito.when;
/**
* Tests for {@link DefaultHttp2ConnectionEncoder}
*/
@SuppressWarnings("unchecked")
public class DefaultHttp2ConnectionEncoderTest {
private static final int STREAM_ID = 2;
private static final int PUSH_STREAM_ID = 4;
@ -131,19 +132,19 @@ public class DefaultHttp2ConnectionEncoderTest {
when(writer.configuration()).thenReturn(writerConfig);
when(writerConfig.frameSizePolicy()).thenReturn(frameSizePolicy);
when(frameSizePolicy.maxFrameSize()).thenReturn(64);
doAnswer((Answer<ChannelFuture>) in -> ((ChannelPromise) in.getArguments()[2])
.setSuccess()).when(writer).writeSettings(eq(ctx), any(Http2Settings.class), any(ChannelPromise.class));
doAnswer((Answer<ChannelFuture>) in -> {
doAnswer((Answer<Future<Void>>) in -> ((Promise<Void>) in.getArguments()[2])
.setSuccess(null)).when(writer).writeSettings(eq(ctx), any(Http2Settings.class), any(Promise.class));
doAnswer((Answer<Future<Void>>) in -> {
((ByteBuf) in.getArguments()[3]).release();
return ((ChannelPromise) in.getArguments()[4]).setSuccess();
}).when(writer).writeGoAway(eq(ctx), anyInt(), anyInt(), any(ByteBuf.class), any(ChannelPromise.class));
return ((Promise<Void>) in.getArguments()[4]).setSuccess(null);
}).when(writer).writeGoAway(eq(ctx), anyInt(), anyInt(), any(ByteBuf.class), any(Promise.class));
writtenData = new ArrayList<>();
writtenPadding = new ArrayList<>();
when(writer.writeData(eq(ctx), anyInt(), any(ByteBuf.class), anyInt(), anyBoolean(),
any(ChannelPromise.class))).then((Answer<ChannelFuture>) in -> {
any(Promise.class))).then((Answer<Future<Void>>) in -> {
// Make sure we only receive stream closure on the last frame and that void promises
// are used for all writes except the last one.
ChannelPromise promise = (ChannelPromise) in.getArguments()[5];
Promise<Void> promise = (Promise<Void>) in.getArguments()[5];
if (streamClosed) {
fail("Stream already closed");
} else {
@ -155,36 +156,36 @@ public class DefaultHttp2ConnectionEncoderTest {
// Release the buffer just as DefaultHttp2FrameWriter does
data.release();
// Let the promise succeed to trigger listeners.
return promise.setSuccess();
return promise.setSuccess(null);
});
when(writer.writeHeaders(eq(ctx), anyInt(), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(),
anyInt(), anyBoolean(), any(ChannelPromise.class)))
.then((Answer<ChannelFuture>) invocationOnMock -> {
ChannelPromise promise = invocationOnMock.getArgument(8);
anyInt(), anyBoolean(), any(Promise.class)))
.then((Answer<Future<Void>>) invocationOnMock -> {
Promise<Void> promise = invocationOnMock.getArgument(8);
if (streamClosed) {
fail("Stream already closed");
} else {
streamClosed = (Boolean) invocationOnMock.getArguments()[5];
}
return promise.setSuccess();
return promise.setSuccess(null);
});
when(writer.writeHeaders(eq(ctx), anyInt(), any(Http2Headers.class),
anyInt(), anyBoolean(), any(ChannelPromise.class)))
.then((Answer<ChannelFuture>) invocationOnMock -> {
ChannelPromise promise = invocationOnMock.getArgument(5);
anyInt(), anyBoolean(), any(Promise.class)))
.then((Answer<Future<Void>>) invocationOnMock -> {
Promise<Void> promise = invocationOnMock.getArgument(5);
if (streamClosed) {
fail("Stream already closed");
} else {
streamClosed = invocationOnMock.getArgument(4);
}
return promise.setSuccess();
return promise.setSuccess(null);
});
payloadCaptor = ArgumentCaptor.forClass(Http2RemoteFlowController.FlowControlled.class);
doNothing().when(remoteFlow).addFlowControlled(any(Http2Stream.class), payloadCaptor.capture());
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
when(ctx.channel()).thenReturn(channel);
doAnswer((Answer<ChannelPromise>) in -> newPromise()).when(ctx).newPromise();
doAnswer((Answer<ChannelFuture>) in -> newSucceededFuture()).when(ctx).newSucceededFuture();
doAnswer((Answer<Promise<Void>>) in -> newPromise()).when(ctx).newPromise();
doAnswer((Answer<Future<Void>>) in -> newSucceededFuture()).when(ctx).newSucceededFuture();
when(ctx.flush()).thenThrow(new AssertionFailedError("forbidden"));
when(channel.alloc()).thenReturn(PooledByteBufAllocator.DEFAULT);
@ -209,7 +210,7 @@ public class DefaultHttp2ConnectionEncoderTest {
private void dataWriteShouldSignalThatFrameWasConsumedOnError0(boolean endOfStream) throws Exception {
createStream(STREAM_ID, false);
final ByteBuf data = dummyData();
ChannelPromise p = newPromise();
Promise<Void> p = newPromise();
encoder.writeData(ctx, STREAM_ID, data, 0, endOfStream, p);
FlowControlled controlled = payloadCaptor.getValue();
@ -230,7 +231,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void dataWriteShouldSucceed() throws Exception {
createStream(STREAM_ID, false);
final ByteBuf data = dummyData();
ChannelPromise p = newPromise();
Promise<Void> p = newPromise();
encoder.writeData(ctx, STREAM_ID, data, 0, true, p);
assertEquals(8, payloadCaptor.getValue().size());
payloadCaptor.getValue().write(ctx, 8);
@ -245,9 +246,9 @@ public class DefaultHttp2ConnectionEncoderTest {
createStream(STREAM_ID, false);
final ByteBuf data = dummyData().retain();
ChannelPromise promise1 = newPromise();
Promise<Void> promise1 = newPromise();
encoder.writeData(ctx, STREAM_ID, data, 0, true, promise1);
ChannelPromise promise2 = newPromise();
Promise<Void> promise2 = newPromise();
encoder.writeData(ctx, STREAM_ID, data, 0, true, promise2);
// Now merge the two payloads.
@ -288,7 +289,7 @@ public class DefaultHttp2ConnectionEncoderTest {
private void assertSplitPaddingOnEmptyBuffer(ByteBuf data) throws Exception {
createStream(STREAM_ID, false);
when(frameSizePolicy.maxFrameSize()).thenReturn(5);
ChannelPromise p = newPromise();
Promise<Void> p = newPromise();
encoder.writeData(ctx, STREAM_ID, data, 10, true, p);
assertEquals(10, payloadCaptor.getValue().size());
payloadCaptor.getValue().write(ctx, 10);
@ -304,7 +305,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void headersWriteForUnknownStreamShouldCreateStream() throws Exception {
writeAllFlowControlledFrames();
final int streamId = 6;
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise);
verify(writer).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0),
eq(false), eq(promise));
@ -317,7 +318,7 @@ public class DefaultHttp2ConnectionEncoderTest {
Http2Stream parent = createStream(STREAM_ID, false);
reservePushStream(PUSH_STREAM_ID, parent);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, PUSH_STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, false, promise);
assertEquals(HALF_CLOSED_REMOTE, stream(PUSH_STREAM_ID).state());
verify(writer).writeHeaders(eq(ctx), eq(PUSH_STREAM_ID), eq(EmptyHttp2Headers.INSTANCE),
@ -328,11 +329,11 @@ public class DefaultHttp2ConnectionEncoderTest {
public void trailersDoNotEndStreamThrows() {
writeAllFlowControlledFrames();
final int streamId = 6;
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise);
ChannelPromise promise2 = newPromise();
ChannelFuture future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise2);
Promise<Void> promise2 = newPromise();
Future<Void> future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise2);
assertTrue(future.isDone());
assertFalse(future.isSuccess());
@ -344,14 +345,14 @@ public class DefaultHttp2ConnectionEncoderTest {
public void trailersDoNotEndStreamWithDataThrows() {
writeAllFlowControlledFrames();
final int streamId = 6;
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise);
Http2Stream stream = connection.stream(streamId);
when(remoteFlow.hasFlowControlled(eq(stream))).thenReturn(true);
ChannelPromise promise2 = newPromise();
ChannelFuture future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise2);
Promise<Void> promise2 = newPromise();
Future<Void> future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise2);
assertTrue(future.isDone());
assertFalse(future.isSuccess());
@ -372,13 +373,13 @@ public class DefaultHttp2ConnectionEncoderTest {
private void tooManyHeadersThrows(boolean eos) {
writeAllFlowControlledFrames();
final int streamId = 6;
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise);
ChannelPromise promise2 = newPromise();
Promise<Void> promise2 = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, true, promise2);
ChannelPromise promise3 = newPromise();
ChannelFuture future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
Promise<Void> promise3 = newPromise();
Future<Void> future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
assertTrue(future.isDone());
assertFalse(future.isSuccess());
@ -415,16 +416,16 @@ public class DefaultHttp2ConnectionEncoderTest {
for (int i = 0; i < infoHeaderCount; ++i) {
encoder.writeHeaders(ctx, streamId, infoHeaders, 0, false, newPromise());
}
ChannelPromise promise2 = newPromise();
Promise<Void> promise2 = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise2);
ChannelPromise promise3 = newPromise();
ChannelFuture future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
Promise<Void> promise3 = newPromise();
Future<Void> future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
assertTrue(future.isDone());
assertEquals(eos, future.isSuccess());
verify(writer, times(infoHeaderCount)).writeHeaders(eq(ctx), eq(streamId), eq(infoHeaders),
eq(0), eq(false), any(ChannelPromise.class));
eq(0), eq(false), any(Promise.class));
verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE),
eq(0), eq(false), eq(promise2));
if (eos) {
@ -452,17 +453,17 @@ public class DefaultHttp2ConnectionEncoderTest {
private void tooManyHeadersWithDataThrows(boolean eos) {
writeAllFlowControlledFrames();
final int streamId = 6;
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise);
Http2Stream stream = connection.stream(streamId);
when(remoteFlow.hasFlowControlled(eq(stream))).thenReturn(true);
ChannelPromise promise2 = newPromise();
Promise<Void> promise2 = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, true, promise2);
ChannelPromise promise3 = newPromise();
ChannelFuture future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
Promise<Void> promise3 = newPromise();
Future<Void> future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
assertTrue(future.isDone());
assertFalse(future.isSuccess());
@ -503,16 +504,16 @@ public class DefaultHttp2ConnectionEncoderTest {
Http2Stream stream = connection.stream(streamId);
when(remoteFlow.hasFlowControlled(eq(stream))).thenReturn(true);
ChannelPromise promise2 = newPromise();
Promise<Void> promise2 = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise2);
ChannelPromise promise3 = newPromise();
ChannelFuture future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
Promise<Void> promise3 = newPromise();
Future<Void> future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
assertTrue(future.isDone());
assertEquals(eos, future.isSuccess());
verify(writer, times(infoHeaderCount)).writeHeaders(eq(ctx), eq(streamId), eq(infoHeaders),
eq(0), eq(false), any(ChannelPromise.class));
eq(0), eq(false), any(Promise.class));
verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE),
eq(0), eq(false), eq(promise2));
if (eos) {
@ -525,7 +526,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void pushPromiseWriteAfterGoAwayReceivedShouldFail() throws Exception {
createStream(STREAM_ID, false);
goAwayReceived(0);
ChannelFuture future = encoder.writePushPromise(ctx, STREAM_ID, PUSH_STREAM_ID, EmptyHttp2Headers.INSTANCE, 0,
Future<Void> future = encoder.writePushPromise(ctx, STREAM_ID, PUSH_STREAM_ID, EmptyHttp2Headers.INSTANCE, 0,
newPromise());
assertTrue(future.isDone());
assertFalse(future.isSuccess());
@ -534,7 +535,7 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void pushPromiseWriteShouldReserveStream() throws Exception {
createStream(STREAM_ID, false);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writePushPromise(ctx, STREAM_ID, PUSH_STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, promise);
assertEquals(RESERVED_LOCAL, stream(PUSH_STREAM_ID).state());
verify(writer).writePushPromise(eq(ctx), eq(STREAM_ID), eq(PUSH_STREAM_ID),
@ -545,14 +546,14 @@ public class DefaultHttp2ConnectionEncoderTest {
public void priorityWriteAfterGoAwayShouldSucceed() throws Exception {
createStream(STREAM_ID, false);
goAwayReceived(Integer.MAX_VALUE);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writePriority(ctx, STREAM_ID, 0, (short) 255, true, promise);
verify(writer).writePriority(eq(ctx), eq(STREAM_ID), eq(0), eq((short) 255), eq(true), eq(promise));
}
@Test
public void priorityWriteShouldSetPriorityForStream() throws Exception {
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
short weight = 255;
encoder.writePriority(ctx, STREAM_ID, 0, weight, true, promise);
@ -566,7 +567,7 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void priorityWriteOnPreviouslyExistingStreamShouldSucceed() throws Exception {
createStream(STREAM_ID, false).close();
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
short weight = 255;
encoder.writePriority(ctx, STREAM_ID, 0, weight, true, promise);
verify(writer).writePriority(eq(ctx), eq(STREAM_ID), eq(0), eq(weight), eq(true), eq(promise));
@ -578,7 +579,7 @@ public class DefaultHttp2ConnectionEncoderTest {
createStream(STREAM_ID, false);
createStream(parentStreamId, false).close();
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
short weight = 255;
encoder.writePriority(ctx, STREAM_ID, parentStreamId, weight, true, promise);
verify(writer).writePriority(eq(ctx), eq(STREAM_ID), eq(parentStreamId), eq(weight), eq(true), eq(promise));
@ -586,7 +587,7 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void rstStreamWriteForUnknownStreamShouldIgnore() throws Exception {
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeRstStream(ctx, 5, PROTOCOL_ERROR.code(), promise);
verify(writer, never()).writeRstStream(eq(ctx), anyInt(), anyLong(), eq(promise));
}
@ -599,14 +600,14 @@ public class DefaultHttp2ConnectionEncoderTest {
// Now verify that a stream reset is performed.
stream(STREAM_ID);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
verify(lifecycleManager).resetStream(eq(ctx), eq(STREAM_ID), anyLong(), eq(promise));
}
@Test
public void pingWriteAfterGoAwayShouldSucceed() throws Exception {
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
goAwayReceived(0);
encoder.writePing(ctx, false, 0L, promise);
verify(writer).writePing(eq(ctx), eq(false), eq(0L), eq(promise));
@ -614,7 +615,7 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void pingWriteShouldSucceed() throws Exception {
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writePing(ctx, false, 0L, promise);
verify(writer).writePing(eq(ctx), eq(false), eq(0L), eq(promise));
}
@ -622,7 +623,7 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void settingsWriteAfterGoAwayShouldSucceed() throws Exception {
goAwayReceived(0);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeSettings(ctx, new Http2Settings(), promise);
verify(writer).writeSettings(eq(ctx), any(Http2Settings.class), eq(promise));
}
@ -634,7 +635,7 @@ public class DefaultHttp2ConnectionEncoderTest {
settings.maxConcurrentStreams(1000);
settings.headerTableSize(2000);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeSettings(ctx, settings, promise);
verify(writer).writeSettings(eq(ctx), eq(settings), eq(promise));
}
@ -645,7 +646,7 @@ public class DefaultHttp2ConnectionEncoderTest {
Http2Stream stream = createStream(STREAM_ID, false);
ByteBuf data = dummyData();
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeData(ctx, STREAM_ID, data.retain(), 0, true, promise);
assertTrue(promise.isSuccess());
verify(remoteFlow).addFlowControlled(eq(stream), any(FlowControlled.class));
@ -658,7 +659,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void headersWriteShouldHalfCloseStream() throws Exception {
writeAllFlowControlledFrames();
createStream(STREAM_ID, false);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, true, promise);
assertTrue(promise.isSuccess());
@ -670,7 +671,7 @@ public class DefaultHttp2ConnectionEncoderTest {
writeAllFlowControlledFrames();
Http2Stream parent = createStream(STREAM_ID, false);
Http2Stream stream = reservePushStream(PUSH_STREAM_ID, parent);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, PUSH_STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, true, promise);
assertEquals(HALF_CLOSED_REMOTE, stream.state());
assertTrue(promise.isSuccess());
@ -679,11 +680,11 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void headersWriteShouldHalfCloseAfterOnErrorForPreCreatedStream() throws Exception {
final ChannelPromise promise = newPromise();
final Promise<Void> promise = newPromise();
final Throwable ex = new RuntimeException();
// Fake an encoding error, like HPACK's HeaderListSizeException
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(true), eq(promise)))
.thenAnswer((Answer<ChannelFuture>) invocation -> {
.thenAnswer((Answer<Future<Void>>) invocation -> {
promise.setFailure(ex);
return promise;
});
@ -702,11 +703,11 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void headersWriteShouldHalfCloseAfterOnErrorForImplicitlyCreatedStream() throws Exception {
final ChannelPromise promise = newPromise();
final Promise<Void> promise = newPromise();
final Throwable ex = new RuntimeException();
// Fake an encoding error, like HPACK's HeaderListSizeException
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(true), eq(promise)))
.thenAnswer((Answer<ChannelFuture>) invocation -> {
.thenAnswer((Answer<Future<Void>>) invocation -> {
promise.setFailure(ex);
return promise;
});
@ -724,7 +725,7 @@ public class DefaultHttp2ConnectionEncoderTest {
@Test
public void encoderDelegatesGoAwayToLifeCycleManager() {
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeGoAway(ctx, STREAM_ID, Http2Error.INTERNAL_ERROR.code(), null, promise);
verify(lifecycleManager).goAway(eq(ctx), eq(STREAM_ID), eq(Http2Error.INTERNAL_ERROR.code()),
eq((ByteBuf) null), eq(promise));
@ -735,7 +736,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void dataWriteToClosedStreamShouldFail() throws Exception {
createStream(STREAM_ID, false).close();
ByteBuf data = mock(ByteBuf.class);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeData(ctx, STREAM_ID, data, 0, false, promise);
assertTrue(promise.isDone());
assertFalse(promise.isSuccess());
@ -747,7 +748,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void dataWriteToHalfClosedLocalStreamShouldFail() throws Exception {
createStream(STREAM_ID, true);
ByteBuf data = mock(ByteBuf.class);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeData(ctx, STREAM_ID, data, 0, false, promise);
assertTrue(promise.isDone());
assertFalse(promise.isSuccess());
@ -769,7 +770,7 @@ public class DefaultHttp2ConnectionEncoderTest {
writeAllFlowControlledFrames();
createStream(STREAM_ID, false);
goAwaySent(0);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, false, promise);
verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE),
eq(0), eq(false), eq(promise));
@ -788,7 +789,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void canWriteHeaderFrameAfterGoAwayReceived() throws Http2Exception {
writeAllFlowControlledFrames();
goAwayReceived(STREAM_ID);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, false, promise);
verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE),
eq(0), eq(false), eq(promise));
@ -798,7 +799,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void headersWithNoPriority() {
writeAllFlowControlledFrames();
final int streamId = 6;
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise);
verify(writer).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE),
eq(0), eq(false), eq(promise));
@ -808,7 +809,7 @@ public class DefaultHttp2ConnectionEncoderTest {
public void headersWithPriority() {
writeAllFlowControlledFrames();
final int streamId = 6;
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 10, DEFAULT_PRIORITY_WEIGHT,
true, 1, false, promise);
verify(writer).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(10),
@ -844,12 +845,12 @@ public class DefaultHttp2ConnectionEncoderTest {
connection.goAwaySent(lastStreamId, 0, EMPTY_BUFFER);
}
private ChannelPromise newPromise() {
return new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
private static Promise<Void> newPromise() {
return new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
}
private ChannelFuture newSucceededFuture() {
return newPromise().setSuccess();
private static Future<Void> newSucceededFuture() {
return newPromise().setSuccess(null);
}
private static ByteBuf dummyData() {

View File

@ -18,18 +18,17 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelPromise;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.ByteArrayOutputStream;
@ -38,11 +37,13 @@ import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.when;
/**
* Tests for {@link DefaultHttp2FrameWriter}.
*/
@SuppressWarnings("unchecked")
public class DefaultHttp2FrameWriterTest {
private DefaultHttp2FrameWriter frameWriter;
@ -50,7 +51,7 @@ public class DefaultHttp2FrameWriterTest {
private ByteBuf expectedOutbound;
private ChannelPromise promise;
private Promise<Void> promise;
private Http2HeadersEncoder http2HeadersEncoder;
@ -58,7 +59,7 @@ public class DefaultHttp2FrameWriterTest {
private Channel channel;
@Mock
private ChannelFuture future;
private Future<Void> future;
@Mock
private ChannelHandlerContext ctx;
@ -76,7 +77,7 @@ public class DefaultHttp2FrameWriterTest {
expectedOutbound = Unpooled.EMPTY_BUFFER;
promise = new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
promise = new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
Answer<Object> answer = var1 -> {
Object msg = var1.getArgument(0);
@ -87,7 +88,7 @@ public class DefaultHttp2FrameWriterTest {
return future;
};
when(ctx.write(any())).then(answer);
when(ctx.write(any(), any(ChannelPromise.class))).then(answer);
when(ctx.write(any(), any(Promise.class))).then(answer);
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
when(ctx.channel()).thenReturn(channel);
when(ctx.executor()).thenReturn(ImmediateEventExecutor.INSTANCE);

View File

@ -15,6 +15,20 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http2.Http2Stream.State;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Promise;
import junit.framework.AssertionFailedError;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import static io.netty.handler.codec.http2.DefaultHttp2LocalFlowController.DEFAULT_WINDOW_UPDATE_RATIO;
import static io.netty.handler.codec.http2.Http2CodecUtil.CONNECTION_STREAM_ID;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_WINDOW_SIZE;
@ -32,20 +46,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http2.Http2Stream.State;
import io.netty.util.concurrent.EventExecutor;
import junit.framework.AssertionFailedError;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
/**
* Tests for {@link DefaultHttp2LocalFlowController}.
*/
@ -64,7 +64,7 @@ public class DefaultHttp2LocalFlowControllerTest {
private EventExecutor executor;
@Mock
private ChannelPromise promise;
private Promise<Void> promise;
private DefaultHttp2Connection connection;
@ -424,9 +424,10 @@ public class DefaultHttp2LocalFlowControllerTest {
verify(frameWriter, never()).writeWindowUpdate(eq(ctx), eq(streamId), anyInt(), eq(promise));
}
@SuppressWarnings("unchecked")
private void verifyWindowUpdateNotSent() {
verify(frameWriter, never()).writeWindowUpdate(any(ChannelHandlerContext.class), anyInt(), anyInt(),
any(ChannelPromise.class));
any(Promise.class));
}
private int window(int streamId) {

View File

@ -19,8 +19,6 @@ import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
@ -33,7 +31,6 @@ import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -97,9 +94,7 @@ public class DefaultHttp2PushPromiseFrameTest {
@Test
public void send() {
connectionFuture.addListener((GenericFutureListener<Future<Channel>>) future -> {
clientHandler.write();
});
connectionFuture.addListener(future -> clientHandler.write());
}
@AfterEach
@ -126,30 +121,24 @@ public class DefaultHttp2PushPromiseFrameTest {
Http2PushPromiseFrame pushPromiseFrame = new DefaultHttp2PushPromiseFrame(pushRequestHeaders);
pushPromiseFrame.stream(receivedFrame.stream());
pushPromiseFrame.pushStream(newPushFrameStream);
ctx.writeAndFlush(pushPromiseFrame).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
contentMap.put(newPushFrameStream.id(), "Meow, I am Pushed via HTTP/2");
ctx.writeAndFlush(pushPromiseFrame).addListener(future -> {
contentMap.put(newPushFrameStream.id(), "Meow, I am Pushed via HTTP/2");
// Write headers for actual request
Http2Headers http2Headers = new DefaultHttp2Headers();
http2Headers.status("200");
http2Headers.add("push", "false");
Http2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(http2Headers, false);
headersFrame.stream(receivedFrame.stream());
ChannelFuture channelFuture = ctx.writeAndFlush(headersFrame);
// Write headers for actual request
Http2Headers http2Headers = new DefaultHttp2Headers();
http2Headers.status("200");
http2Headers.add("push", "false");
Http2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(http2Headers, false);
headersFrame.stream(receivedFrame.stream());
Future<Void> channelFuture = ctx.writeAndFlush(headersFrame);
// Write Data of actual request
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Http2DataFrame dataFrame = new DefaultHttp2DataFrame(
Unpooled.wrappedBuffer("Meow".getBytes()), true);
dataFrame.stream(receivedFrame.stream());
ctx.writeAndFlush(dataFrame);
}
});
}
// Write Data of actual request
channelFuture.addListener(fut -> {
Http2DataFrame dataFrame = new DefaultHttp2DataFrame(
Unpooled.wrappedBuffer("Meow".getBytes()), true);
dataFrame.stream(receivedFrame.stream());
ctx.writeAndFlush(dataFrame);
});
});
} else if (msg instanceof Http2PriorityFrame) {
Http2PriorityFrame priorityFrame = (Http2PriorityFrame) msg;
@ -177,7 +166,7 @@ public class DefaultHttp2PushPromiseFrameTest {
private static final class ClientHandler extends Http2ChannelDuplexHandler {
private ChannelHandlerContext ctx;
private volatile ChannelHandlerContext ctx;
@Override
public void channelActive(ChannelHandlerContext ctx) throws InterruptedException {

View File

@ -18,14 +18,13 @@ package io.netty.handler.codec.http2;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.opentest4j.AssertionFailedError;
@ -80,7 +79,7 @@ public abstract class DefaultHttp2RemoteFlowControllerTest {
private EventExecutor executor;
@Mock
private ChannelPromise promise;
private Promise<Void> promise;
@Mock
private Http2RemoteFlowController.Listener listener;

View File

@ -71,7 +71,10 @@ public class Http2ClientUpgradeCodecTest {
// Flush the channel to ensure we write out all buffered data
channel.flush();
codec.upgradeTo(ctx, null);
channel.eventLoop().submit(() -> {
codec.upgradeTo(ctx, null);
return null;
}).sync();
assertNotNull(channel.pipeline().get("connectionHandler"));
if (multiplexer != null) {

View File

@ -19,19 +19,17 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.DefaultChannelPromise;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http2.Http2Exception.ShutdownHint;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
@ -78,12 +76,13 @@ import static org.mockito.Mockito.when;
/**
* Tests for {@link Http2ConnectionHandler}
*/
@SuppressWarnings("unchecked")
public class Http2ConnectionHandlerTest {
private static final int STREAM_ID = 1;
private static final int NON_EXISTANT_STREAM_ID = 13;
private Http2ConnectionHandler handler;
private ChannelPromise promise;
private Promise<Void> promise;
@Mock
private Http2Connection connection;
@ -119,7 +118,7 @@ public class Http2ConnectionHandlerTest {
private ChannelPipeline pipeline;
@Mock
private ChannelFuture future;
private Future<Void> future;
@Mock
private Http2Stream stream;
@ -140,7 +139,7 @@ public class Http2ConnectionHandlerTest {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
promise = new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
promise = new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
when(channel.metadata()).thenReturn(new ChannelMetadata(false));
DefaultChannelConfig config = new DefaultChannelConfig(channel);
@ -152,22 +151,21 @@ public class Http2ConnectionHandlerTest {
when(encoder.frameWriter()).thenReturn(frameWriter);
when(encoder.flowController()).thenReturn(remoteFlow);
when(decoder.flowController()).thenReturn(localFlow);
doAnswer((Answer<ChannelFuture>) invocation -> {
doAnswer((Answer<Future<Void>>) invocation -> {
ByteBuf buf = invocation.getArgument(3);
goAwayDebugCap = buf.toString(UTF_8);
buf.release();
return future;
}).when(frameWriter).writeGoAway(
any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class), any(ChannelPromise.class));
doAnswer((Answer<ChannelFuture>) invocation -> {
any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class), any(Promise.class));
doAnswer((Answer<Future<Void>>) invocation -> {
Object o = invocation.getArguments()[0];
if (o instanceof ChannelFutureListener) {
((ChannelFutureListener) o).operationComplete(future);
if (o instanceof FutureListener) {
((FutureListener<Void>) o).operationComplete(future);
}
return future;
}).when(future).addListener(any(GenericFutureListener.class));
}).when(future).addListener(any(FutureListener.class));
when(future.cause()).thenReturn(fakeException);
when(future.channel()).thenReturn(channel);
when(channel.isActive()).thenReturn(true);
when(channel.pipeline()).thenReturn(pipeline);
when(connection.remote()).thenReturn(remote);
@ -252,7 +250,7 @@ public class Http2ConnectionHandlerTest {
final Answer<Object> verifier = in -> {
assertEquals(in.getArgument(0), evt); // sanity check...
verify(ctx).write(eq(connectionPrefaceBuf()));
verify(encoder).writeSettings(eq(ctx), any(Http2Settings.class), any(ChannelPromise.class));
verify(encoder).writeSettings(eq(ctx), any(Http2Settings.class), any(Promise.class));
verified.set(true);
return null;
};
@ -526,13 +524,13 @@ public class Http2ConnectionHandlerTest {
handler = newHandler();
when(stream.id()).thenReturn(STREAM_ID);
when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID),
anyLong(), any(ChannelPromise.class))).thenReturn(future);
anyLong(), any(Promise.class))).thenReturn(future);
when(stream.state()).thenReturn(CLOSED);
when(stream.isHeadersSent()).thenReturn(true);
// The stream is "closed" but is still known about by the connection (connection().stream(..)
// will return the stream). We should still write a RST_STREAM frame in this scenario.
handler.resetStream(ctx, STREAM_ID, STREAM_CLOSED.code(), promise);
verify(frameWriter).writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(ChannelPromise.class));
verify(frameWriter).writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(Promise.class));
}
@Test
@ -540,7 +538,7 @@ public class Http2ConnectionHandlerTest {
handler = newHandler();
when(stream.state()).thenReturn(IDLE);
handler.resetStream(ctx, STREAM_ID, STREAM_CLOSED.code(), promise);
verify(frameWriter, never()).writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(ChannelPromise.class));
verify(frameWriter, never()).writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(Promise.class));
verify(stream).close();
}
@ -550,9 +548,9 @@ public class Http2ConnectionHandlerTest {
handler = newHandler();
when(future.isDone()).thenReturn(true);
when(future.isSuccess()).thenReturn(true);
doAnswer((Answer<ChannelFuture>) invocation -> {
doAnswer((Answer<Future<Void>>) invocation -> {
Object[] args = invocation.getArguments();
GenericFutureListener<ChannelFuture> listener = (GenericFutureListener<ChannelFuture>) args[0];
FutureListener<Void> listener = (FutureListener<Void>) args[0];
// Simulate that all streams have become inactive by the time the future completes.
doAnswer((Answer<Http2Stream>) in -> null).when(connection).forEachActiveStream(
any(Http2StreamVisitor.class));
@ -560,7 +558,7 @@ public class Http2ConnectionHandlerTest {
// Simulate the future being completed.
listener.operationComplete(future);
return future;
}).when(future).addListener(any(GenericFutureListener.class));
}).when(future).addListener(any(FutureListener.class));
handler.close(ctx, promise);
if (future.isDone()) {
when(connection.numActiveStreams()).thenReturn(0);
@ -568,7 +566,7 @@ public class Http2ConnectionHandlerTest {
handler.closeStream(stream, future);
// Simulate another stream close call being made after the context should already be closed.
handler.closeStream(stream, future);
verify(ctx, times(1)).close(any(ChannelPromise.class));
verify(ctx, times(1)).close(any(Promise.class));
}
@SuppressWarnings("unchecked")
@ -579,9 +577,9 @@ public class Http2ConnectionHandlerTest {
when(future.isDone()).thenReturn(true);
when(future.isSuccess()).thenReturn(true);
doAnswer((Answer<Void>) invocation -> {
((GenericFutureListener) invocation.getArgument(0)).operationComplete(future);
((FutureListener<Void>) invocation.getArgument(0)).operationComplete(future);
return null;
}).when(future).addListener(any(GenericFutureListener.class));
}).when(future).addListener(any(FutureListener.class));
handler = newHandler();
handler.goAway(ctx, STREAM_ID, errorCode, data, promise);
@ -602,7 +600,7 @@ public class Http2ConnectionHandlerTest {
verify(frameWriter).writeGoAway(eq(ctx), eq(STREAM_ID + 2), eq(errorCode), eq(data),
eq(promise));
verify(connection).goAwaySent(eq(STREAM_ID + 2), eq(errorCode), eq(data));
promise = new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
promise = new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
handler.goAway(ctx, STREAM_ID, errorCode, data, promise);
verify(frameWriter).writeGoAway(eq(ctx), eq(STREAM_ID), eq(errorCode), eq(data), eq(promise));
verify(connection).goAwaySent(eq(STREAM_ID), eq(errorCode), eq(data));
@ -655,9 +653,9 @@ public class Http2ConnectionHandlerTest {
when(channel.isActive()).thenReturn(false);
handler.channelInactive(ctx);
verify(frameWriter, never()).writeGoAway(any(ChannelHandlerContext.class), anyInt(), anyLong(),
any(ByteBuf.class), any(ChannelPromise.class));
any(ByteBuf.class), any(Promise.class));
verify(frameWriter, never()).writeRstStream(any(ChannelHandlerContext.class), anyInt(), anyLong(),
any(ChannelPromise.class));
any(Promise.class));
}
@Test
@ -727,21 +725,20 @@ public class Http2ConnectionHandlerTest {
return stream;
});
when(stream.isResetSent()).then((Answer<Boolean>) invocationOnMock -> resetSent.get());
when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(ChannelPromise.class)))
.then((Answer<ChannelFuture>) invocationOnMock -> {
ChannelPromise promise = invocationOnMock.getArgument(3);
return promise.setSuccess();
when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(Promise.class)))
.then((Answer<Future<Void>>) invocationOnMock -> {
Promise<Void> promise = invocationOnMock.getArgument(3);
return promise.setSuccess(null);
});
ChannelPromise promise =
new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
final ChannelPromise promise2 =
new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
promise.addListener((ChannelFutureListener) future ->
handler.resetStream(ctx, STREAM_ID, STREAM_CLOSED.code(), promise2));
Promise<Void> promise =
new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
final Promise<Void> promise2 =
new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
promise.addListener(future -> handler.resetStream(ctx, STREAM_ID, STREAM_CLOSED.code(), promise2));
handler.resetStream(ctx, STREAM_ID, CANCEL.code(), promise);
verify(frameWriter).writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(ChannelPromise.class));
verify(frameWriter).writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(Promise.class));
assertTrue(promise.isSuccess());
assertTrue(promise2.isSuccess());
}

View File

@ -21,13 +21,10 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MultithreadEventLoopGroup;
import io.netty.channel.local.LocalAddress;
import io.netty.channel.local.LocalChannel;
@ -38,6 +35,7 @@ import io.netty.util.AsciiString;
import io.netty.util.IllegalReferenceCountException;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -261,10 +259,10 @@ public class Http2ConnectionRoundtripTest {
runInChannel(clientChannel, () -> {
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, false, newPromise())
.addListener((ChannelFutureListener) future -> clientHeadersWriteException.set(future.cause()));
.addListener(future -> clientHeadersWriteException.set(future.cause()));
// It is expected that this write should fail locally and the remote peer will never see this.
http2Client.encoder().writeData(ctx(), 3, Unpooled.buffer(), 0, true, newPromise())
.addListener((ChannelFutureListener) future -> {
.addListener(future -> {
clientDataWriteException.set(future.cause());
clientDataWrite.countDown();
});
@ -289,7 +287,7 @@ public class Http2ConnectionRoundtripTest {
runInChannel(clientChannel, () -> {
http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, true,
newPromise()).addListener((ChannelFutureListener) future -> {
newPromise()).addListener(future -> {
clientHeadersWriteException2.set(future.cause());
clientHeadersLatch.countDown();
});
@ -481,7 +479,7 @@ public class Http2ConnectionRoundtripTest {
// Now have the server attempt to send a headers frame simulating some asynchronous work.
runInChannel(serverConnectedChannel, () -> {
http2Server.encoder().writeHeaders(serverCtx(), streamId, headers, 0, true, serverNewPromise())
.addListener((ChannelFutureListener) future -> {
.addListener(future -> {
serverWriteHeadersCauseRef.set(future.cause());
serverWriteHeadersLatch.countDown();
});
@ -507,7 +505,7 @@ public class Http2ConnectionRoundtripTest {
// Create a latch to track when the close occurs.
final CountDownLatch closeLatch = new CountDownLatch(1);
clientChannel.closeFuture().addListener((ChannelFutureListener) future -> closeLatch.countDown());
clientChannel.closeFuture().addListener(future -> closeLatch.countDown());
// Create a single stream by sending a HEADERS frame to the server.
final Http2Headers headers = dummyHeaders();
@ -545,7 +543,7 @@ public class Http2ConnectionRoundtripTest {
// Create a latch to track when the close occurs.
final CountDownLatch closeLatch = new CountDownLatch(1);
clientChannel.closeFuture().addListener((ChannelFutureListener) future -> closeLatch.countDown());
clientChannel.closeFuture().addListener(future -> closeLatch.countDown());
// Create a single stream by sending a HEADERS frame to the server.
runInChannel(clientChannel, () -> {
@ -594,7 +592,7 @@ public class Http2ConnectionRoundtripTest {
throws Exception {
bootstrapEnv(1, 1, 2, 1);
final ChannelPromise emptyDataPromise = newPromise();
final Promise<Void> emptyDataPromise = newPromise();
runInChannel(clientChannel, () -> {
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, false,
newPromise());
@ -639,15 +637,15 @@ public class Http2ConnectionRoundtripTest {
throws Exception {
bootstrapEnv(1, 1, 2, 1);
final ChannelPromise dataPromise = newPromise();
final ChannelPromise assertPromise = newPromise();
final Promise<Void> dataPromise = newPromise();
final Promise<Void> assertPromise = newPromise();
runInChannel(clientChannel, () -> {
http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, false,
newPromise());
clientChannel.pipeline().addFirst(new ChannelHandler() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
ReferenceCountUtil.release(msg);
try {
@ -673,7 +671,7 @@ public class Http2ConnectionRoundtripTest {
// The Frame should have been removed after the write failed.
assertFalse(http2Client.encoder().flowController()
.hasFlowControlled(http2Client.connection().stream(3)));
assertPromise.setSuccess();
assertPromise.setSuccess(null);
} catch (Throwable error) {
assertPromise.setFailure(error);
}
@ -695,7 +693,7 @@ public class Http2ConnectionRoundtripTest {
// Create a latch to track when the close occurs.
final CountDownLatch closeLatch = new CountDownLatch(1);
clientChannel.closeFuture().addListener((ChannelFutureListener) future -> closeLatch.countDown());
clientChannel.closeFuture().addListener(future -> closeLatch.countDown());
// Create a single stream by sending a HEADERS frame to the server.
final Http2Headers headers = dummyHeaders();
@ -790,20 +788,20 @@ public class Http2ConnectionRoundtripTest {
verify(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), eq(3), eq(NO_ERROR.code()),
any(ByteBuf.class));
final AtomicReference<ChannelFuture> clientWriteAfterGoAwayFutureRef = new AtomicReference<>();
final AtomicReference<Future<Void>> clientWriteAfterGoAwayFutureRef = new AtomicReference<>();
final CountDownLatch clientWriteAfterGoAwayLatch = new CountDownLatch(1);
runInChannel(clientChannel, () -> {
ChannelFuture f = http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0,
Future<Void> f = http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0,
true, newPromise());
clientWriteAfterGoAwayFutureRef.set(f);
http2Client.flush(ctx());
f.addListener((ChannelFutureListener) future -> clientWriteAfterGoAwayLatch.countDown());
f.addListener(future -> clientWriteAfterGoAwayLatch.countDown());
});
// Wait for the client's write operation to complete.
assertTrue(clientWriteAfterGoAwayLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
ChannelFuture clientWriteAfterGoAwayFuture = clientWriteAfterGoAwayFutureRef.get();
Future<Void> clientWriteAfterGoAwayFuture = clientWriteAfterGoAwayFutureRef.get();
assertNotNull(clientWriteAfterGoAwayFuture);
Throwable clientCause = clientWriteAfterGoAwayFuture.cause();
assertThat(clientCause, is(instanceOf(Http2Exception.StreamException.class)));
@ -1106,11 +1104,11 @@ public class Http2ConnectionRoundtripTest {
return serverConnectedChannel.pipeline().firstContext();
}
private ChannelPromise newPromise() {
private Promise<Void> newPromise() {
return ctx().newPromise();
}
private ChannelPromise serverNewPromise() {
private Promise<Void> serverNewPromise() {
return serverCtx().newPromise();
}

View File

@ -19,15 +19,15 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelPromise;
import io.netty.channel.DefaultMessageSizeEstimator;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -36,20 +36,30 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.ArrayDeque;
import java.util.Queue;
import static io.netty.handler.codec.http2.Http2CodecUtil.*;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_FRAME_SIZE;
import static io.netty.handler.codec.http2.Http2Error.CANCEL;
import static io.netty.handler.codec.http2.Http2Error.ENHANCE_YOUR_CALM;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests for {@link Http2ControlFrameLimitEncoder}.
*/
@SuppressWarnings("unchecked")
public class Http2ControlFrameLimitEncoderTest {
private Http2ControlFrameLimitEncoder encoder;
@ -74,7 +84,7 @@ public class Http2ControlFrameLimitEncoderTest {
private int numWrites;
private final Queue<ChannelPromise> goAwayPromises = new ArrayDeque<ChannelPromise>();
private final Queue<Promise<Void>> goAwayPromises = new ArrayDeque<Promise<Void>>();
/**
* Init fields and do mocking.
@ -91,22 +101,22 @@ public class Http2ControlFrameLimitEncoderTest {
when(configuration.frameSizePolicy()).thenReturn(frameSizePolicy);
when(frameSizePolicy.maxFrameSize()).thenReturn(DEFAULT_MAX_FRAME_SIZE);
when(writer.writeRstStream(eq(ctx), anyInt(), anyLong(), any(ChannelPromise.class)))
.thenAnswer((Answer<ChannelFuture>) invocationOnMock -> handlePromise(invocationOnMock, 3));
when(writer.writeSettingsAck(any(ChannelHandlerContext.class), any(ChannelPromise.class)))
.thenAnswer((Answer<ChannelFuture>) invocationOnMock -> handlePromise(invocationOnMock, 1));
when(writer.writePing(any(ChannelHandlerContext.class), anyBoolean(), anyLong(), any(ChannelPromise.class)))
.thenAnswer((Answer<ChannelFuture>) invocationOnMock -> {
ChannelPromise promise = handlePromise(invocationOnMock, 3);
when(writer.writeRstStream(eq(ctx), anyInt(), anyLong(), any(Promise.class)))
.thenAnswer((Answer<Future<Void>>) invocationOnMock -> handlePromise(invocationOnMock, 3));
when(writer.writeSettingsAck(any(ChannelHandlerContext.class), any(Promise.class)))
.thenAnswer((Answer<Future<Void>>) invocationOnMock -> handlePromise(invocationOnMock, 1));
when(writer.writePing(any(ChannelHandlerContext.class), anyBoolean(), anyLong(), any(Promise.class)))
.thenAnswer((Answer<Future<Void>>) invocationOnMock -> {
Promise<Void> promise = handlePromise(invocationOnMock, 3);
if (invocationOnMock.getArgument(1) == Boolean.FALSE) {
promise.trySuccess();
promise.trySuccess(null);
}
return promise;
});
when(writer.writeGoAway(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class),
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock -> {
any(Promise.class))).thenAnswer((Answer<Future<Void>>) invocationOnMock -> {
ReferenceCountUtil.release(invocationOnMock.getArgument(3));
ChannelPromise promise = invocationOnMock.getArgument(4);
Promise<Void> promise = invocationOnMock.getArgument(4);
goAwayPromises.offer(promise);
return promise;
});
@ -128,7 +138,7 @@ public class Http2ControlFrameLimitEncoderTest {
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
when(channel.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
when(executor.inEventLoop()).thenReturn(true);
doAnswer((Answer<ChannelPromise>) invocation -> newPromise()).when(ctx).newPromise();
doAnswer((Answer<Promise>) invocation -> newPromise()).when(ctx).newPromise();
when(ctx.executor()).thenReturn(executor);
when(channel.isActive()).thenReturn(false);
when(channel.config()).thenReturn(config);
@ -142,10 +152,10 @@ public class Http2ControlFrameLimitEncoderTest {
handler.handlerAdded(ctx);
}
private ChannelPromise handlePromise(InvocationOnMock invocationOnMock, int promiseIdx) {
ChannelPromise promise = invocationOnMock.getArgument(promiseIdx);
private Promise<Void> handlePromise(InvocationOnMock invocationOnMock, int promiseIdx) {
Promise<Void> promise = invocationOnMock.getArgument(promiseIdx);
if (++numWrites == 2) {
promise.setSuccess();
promise.setSuccess(null);
}
return promise;
}
@ -155,14 +165,14 @@ public class Http2ControlFrameLimitEncoderTest {
// Close and release any buffered frames.
encoder.close();
// Notify all goAway ChannelPromise instances now as these will also release the retained ByteBuf for the
// Notify all goAway Promise instances now as these will also release the retained ByteBuf for the
// debugData.
for (;;) {
ChannelPromise promise = goAwayPromises.poll();
Promise<Void> promise = goAwayPromises.poll();
if (promise == null) {
break;
}
promise.setSuccess();
promise.setSuccess(null);
}
}
@ -246,11 +256,11 @@ public class Http2ControlFrameLimitEncoderTest {
verify(ctx, times(invocations)).close();
if (failed) {
verify(writer, times(1)).writeGoAway(eq(ctx), eq(Integer.MAX_VALUE), eq(ENHANCE_YOUR_CALM.code()),
any(ByteBuf.class), any(ChannelPromise.class));
any(ByteBuf.class), any(Promise.class));
}
}
private ChannelPromise newPromise() {
return new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
private static Promise<Void> newPromise() {
return new DefaultPromise<>(ImmediateEventExecutor.INSTANCE);
}
}

View File

@ -16,11 +16,8 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.UnsupportedMessageTypeException;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
@ -39,6 +36,7 @@ import io.netty.util.AsciiString;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.ReferenceCounted;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.ReflectionUtil;
@ -84,6 +82,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Unit tests for {@link Http2FrameCodec}.
*/
@SuppressWarnings("unchecked")
public class Http2FrameCodecTest {
// For verifying outbound frames
@ -384,7 +383,7 @@ public class Http2FrameCodecTest {
UnknownHttp2Frame frame = new UnknownHttp2Frame();
assertEquals(1, frame.refCnt());
ChannelFuture f = channel.write(frame);
Future<Void> f = channel.write(frame);
f.await();
assertTrue(f.isDone());
assertFalse(f.isSuccess());
@ -493,7 +492,7 @@ public class Http2FrameCodecTest {
Http2FrameStream stream2 = inboundHeaders.stream();
int before = connection.local().flowController().unconsumedBytes(stream);
ChannelFuture f = channel.write(new DefaultHttp2WindowUpdateFrame(100).stream(stream2));
Future<Void> f = channel.write(new DefaultHttp2WindowUpdateFrame(100).stream(stream2));
int after = connection.local().flowController().unconsumedBytes(stream);
assertEquals(100, before - after);
assertTrue(f.isSuccess());
@ -512,7 +511,7 @@ public class Http2FrameCodecTest {
Http2FrameStream stream2 = inboundHeaders.stream();
// Fails, cause trying to return too many bytes to the flow controller
ChannelFuture f = channel.write(new DefaultHttp2WindowUpdateFrame(100).stream(stream2));
Future<Void> f = channel.write(new DefaultHttp2WindowUpdateFrame(100).stream(stream2));
assertTrue(f.isDone());
assertFalse(f.isSuccess());
assertThat(f.cause(), instanceOf(Http2Exception.class));
@ -597,7 +596,7 @@ public class Http2FrameCodecTest {
channel.write(unknownFrame);
verify(frameWriter).writeFrame(any(ChannelHandlerContext.class), eq(unknownFrame.frameType()),
eq(unknownFrame.stream().id()), eq(unknownFrame.flags()), eq(buffer), any(ChannelPromise.class));
eq(unknownFrame.stream().id()), eq(unknownFrame.flags()), eq(buffer), any(Promise.class));
}
@Test
@ -605,7 +604,7 @@ public class Http2FrameCodecTest {
Http2Settings settings = new Http2Settings();
channel.write(new DefaultHttp2SettingsFrame(settings));
verify(frameWriter).writeSettings(any(ChannelHandlerContext.class), same(settings), any(ChannelPromise.class));
verify(frameWriter).writeSettings(any(ChannelHandlerContext.class), same(settings), any(Promise.class));
}
@Test
@ -619,14 +618,14 @@ public class Http2FrameCodecTest {
final Promise<Void> listenerExecuted = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers(), false).stream(stream))
.addListener((ChannelFutureListener) future -> {
.addListener(future -> {
assertTrue(future.isSuccess());
assertTrue(isStreamIdValid(stream.id()));
listenerExecuted.setSuccess(null);
}
);
ByteBuf data = Unpooled.buffer().writeZero(100);
ChannelFuture f = channel.writeAndFlush(new DefaultHttp2DataFrame(data).stream(stream));
Future<Void> f = channel.writeAndFlush(new DefaultHttp2DataFrame(data).stream(stream));
assertTrue(f.isSuccess());
listenerExecuted.syncUninterruptibly();
@ -641,8 +640,8 @@ public class Http2FrameCodecTest {
Http2FrameStream stream1 = frameCodec.newStream();
Http2FrameStream stream2 = frameCodec.newStream();
ChannelPromise promise1 = channel.newPromise();
ChannelPromise promise2 = channel.newPromise();
Promise<Void> promise1 = channel.newPromise();
Promise<Void> promise2 = channel.newPromise();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream1), promise1);
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2), promise2);
@ -672,9 +671,9 @@ public class Http2FrameCodecTest {
Http2FrameStream stream2 = frameCodec.newStream();
Http2FrameStream stream3 = frameCodec.newStream();
ChannelPromise promise1 = channel.newPromise();
ChannelPromise promise2 = channel.newPromise();
ChannelPromise promise3 = channel.newPromise();
Promise<Void> promise1 = channel.newPromise();
Promise<Void> promise2 = channel.newPromise();
Promise<Void> promise3 = channel.newPromise();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream1), promise1);
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2), promise2);
@ -712,8 +711,8 @@ public class Http2FrameCodecTest {
Http2FrameStream stream1 = frameCodec.newStream();
Http2FrameStream stream2 = frameCodec.newStream();
ChannelPromise stream1HeaderPromise = channel.newPromise();
ChannelPromise stream2HeaderPromise = channel.newPromise();
Promise<Void> stream1HeaderPromise = channel.newPromise();
Promise<Void> stream2HeaderPromise = channel.newPromise();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream1),
stream1HeaderPromise);
@ -733,15 +732,18 @@ public class Http2FrameCodecTest {
}
@Test
public void streamIdentifiersExhausted() throws Http2Exception {
public void streamIdentifiersExhausted() throws Exception {
int maxServerStreamId = Integer.MAX_VALUE - 1;
assertNotNull(frameCodec.connection().local().createStream(maxServerStreamId, false));
channel.eventLoop().submit(() -> {
assertNotNull(frameCodec.connection().local().createStream(maxServerStreamId, false));
return null;
}).sync();
Http2FrameStream stream = frameCodec.newStream();
assertNotNull(stream);
ChannelPromise writePromise = channel.newPromise();
Promise<Void> writePromise = channel.newPromise();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream), writePromise);
Http2GoAwayFrame goAwayFrame = inboundHandler.readInbound();
@ -866,7 +868,7 @@ public class Http2FrameCodecTest {
final AtomicBoolean listenerExecuted = new AtomicBoolean();
channel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()).stream(stream2))
.addListener((ChannelFutureListener) future -> {
.addListener(future -> {
assertTrue(future.isSuccess());
assertEquals(State.OPEN, stream2.state());
listenerExecuted.set(true);
@ -900,12 +902,12 @@ public class Http2FrameCodecTest {
// Simulate consuming the frame and update the flow-controller.
Http2DataFrame data = (Http2DataFrame) msg;
ctx.writeAndFlush(new DefaultHttp2WindowUpdateFrame(data.initialFlowControlledBytes())
.stream(data.stream())).addListener((ChannelFutureListener) future -> {
Throwable cause = future.cause();
if (cause != null) {
ctx.fireExceptionCaught(cause);
}
});
.stream(data.stream())).addListener(future -> {
Throwable cause = future.cause();
if (cause != null) {
ctx.fireExceptionCaught(cause);
}
});
}
ReferenceCountUtil.release(msg);
}

View File

@ -19,15 +19,15 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.net.SocketAddress;
@ -224,91 +224,91 @@ final class Http2FrameInboundWriter {
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
public Future<Void> bind(SocketAddress localAddress) {
return channel.bind(localAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
public Future<Void> connect(SocketAddress remoteAddress) {
return channel.connect(remoteAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return channel.connect(remoteAddress, localAddress);
}
@Override
public ChannelFuture disconnect() {
public Future<Void> disconnect() {
return channel.disconnect();
}
@Override
public ChannelFuture close() {
public Future<Void> close() {
return channel.close();
}
@Override
public ChannelFuture register() {
public Future<Void> register() {
return channel.register();
}
@Override
public ChannelFuture deregister() {
public Future<Void> deregister() {
return channel.deregister();
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> bind(SocketAddress localAddress, Promise<Void> promise) {
return channel.bind(localAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
public Future<Void> connect(SocketAddress remoteAddress, Promise<Void> promise) {
return channel.connect(remoteAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress, Promise<Void> promise) {
return channel.connect(remoteAddress, localAddress, promise);
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
public Future<Void> disconnect(Promise<Void> promise) {
return channel.disconnect(promise);
}
@Override
public ChannelFuture close(ChannelPromise promise) {
public Future<Void> close(Promise<Void> promise) {
return channel.close(promise);
}
@Override
public ChannelFuture register(ChannelPromise promise) {
public Future<Void> register(Promise<Void> promise) {
return channel.register(promise);
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
public Future<Void> deregister(Promise<Void> promise) {
return channel.deregister(promise);
}
@Override
public ChannelFuture write(Object msg) {
public Future<Void> write(Object msg) {
return write(msg, newPromise());
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
public Future<Void> write(Object msg, Promise<Void> promise) {
return writeAndFlush(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
public Future<Void> writeAndFlush(Object msg, Promise<Void> promise) {
try {
channel.writeInbound(msg);
channel.runPendingTasks();
promise.setSuccess();
promise.setSuccess(null);
} catch (Throwable cause) {
promise.setFailure(cause);
}
@ -316,22 +316,22 @@ final class Http2FrameInboundWriter {
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
public Future<Void> writeAndFlush(Object msg) {
return writeAndFlush(msg, newPromise());
}
@Override
public ChannelPromise newPromise() {
public Promise<Void> newPromise() {
return channel.newPromise();
}
@Override
public ChannelFuture newSucceededFuture() {
public Future<Void> newSucceededFuture() {
return channel.newSucceededFuture();
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
public Future<Void> newFailedFuture(Throwable cause) {
return channel.newFailedFuture(cause);
}
}

View File

@ -22,11 +22,11 @@ import io.netty.buffer.EmptyByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelPromise;
import io.netty.util.AsciiString;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -34,7 +34,6 @@ import org.junit.jupiter.api.function.Executable;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.LinkedList;
@ -55,10 +54,10 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyShort;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isA;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isA;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ -66,6 +65,7 @@ import static org.mockito.Mockito.when;
/**
* Tests encoding/decoding each HTTP2 frame type.
*/
@SuppressWarnings("unchecked")
public class Http2FrameRoundtripTest {
private static final byte[] MESSAGE = "hello world".getBytes(UTF_8);
private static final int STREAM_ID = 0x7FFFFFFF;
@ -100,8 +100,8 @@ public class Http2FrameRoundtripTest {
when(ctx.channel()).thenReturn(channel);
doAnswer((Answer<ByteBuf>) in -> Unpooled.buffer()).when(alloc).buffer();
doAnswer((Answer<ByteBuf>) in -> Unpooled.buffer((Integer) in.getArguments()[0])).when(alloc).buffer(anyInt());
doAnswer((Answer<ChannelPromise>) invocation ->
new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).when(ctx).newPromise();
doAnswer((Answer<Promise<Void>>) invocation ->
new DefaultPromise<Void>(GlobalEventExecutor.INSTANCE)).when(ctx).newPromise();
writer = new DefaultHttp2FrameWriter(new DefaultHttp2HeadersEncoder(NEVER_SENSITIVE, newTestEncoder()));
reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(false, newTestDecoder()));
@ -433,7 +433,7 @@ public class Http2FrameRoundtripTest {
private ByteBuf captureWrites() {
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
verify(ctx, atLeastOnce()).write(captor.capture(), isA(ChannelPromise.class));
verify(ctx, atLeastOnce()).write(captor.capture(), isA(Promise.class));
CompositeByteBuf composite = releaseLater(Unpooled.compositeBuffer());
for (ByteBuf buf : captor.getAllValues()) {
buf = releaseLater(buf.retain());

View File

@ -66,7 +66,10 @@ public abstract class Http2MultiplexClientUpgradeTest<C extends Http2FrameCodec>
C codec = newCodec(upgradeHandler);
EmbeddedChannel ch = new EmbeddedChannel(codec, newMultiplexer(upgradeHandler));
codec.onHttpClientUpgrade();
ch.eventLoop().submit(() -> {
codec.onHttpClientUpgrade();
return null;
}).sync();
assertFalse(upgradeHandler.stateOnActive.localSideOpen());
assertTrue(upgradeHandler.stateOnActive.remoteSideOpen());

View File

@ -17,11 +17,8 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.HttpHeaderNames;
@ -31,12 +28,12 @@ import io.netty.handler.codec.http2.Http2Exception.StreamException;
import io.netty.util.AsciiString;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.mockito.ArgumentMatcher;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@ -75,6 +72,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SuppressWarnings("unchecked")
public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
private final Http2Headers request = new DefaultHttp2Headers()
.method(HttpMethod.GET.asciiName()).scheme(HttpScheme.HTTPS.name())
@ -153,7 +151,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
assertTrue(childChannel.isActive());
verify(frameWriter).writeFrame(any(ChannelHandlerContext.class), eq((byte) 99), eqStreamId(childChannel),
any(Http2Flags.class), any(ByteBuf.class), any(ChannelPromise.class));
any(Http2Flags.class), any(ByteBuf.class), any(Promise.class));
}
private Http2StreamChannel newInboundStream(int streamId, boolean endStream, final ChannelHandler childHandler) {
@ -561,18 +559,18 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
public void outboundStreamShouldNotWriteResetFrameOnClose_IfStreamDidntExist() {
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
any(Http2Headers.class), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
any(Promise.class))).thenAnswer(new Answer<Future<Void>>() {
private boolean headersWritten;
@Override
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
public Future<Void> answer(InvocationOnMock invocationOnMock) {
// We want to fail to write the first headers frame. This is what happens if the connection
// refuses to allocate a new stream due to having received a GOAWAY.
if (!headersWritten) {
headersWritten = true;
return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(new Exception("boom"));
return ((Promise<Void>) invocationOnMock.getArgument(5)).setFailure(new Exception("boom"));
}
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
return ((Promise<Void>) invocationOnMock.getArgument(5)).setSuccess(null);
}
});
@ -636,11 +634,11 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
eq(headers), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(
any(Promise.class))).thenAnswer(invocationOnMock -> {
return ((Promise<Void>) invocationOnMock.getArgument(5)).setFailure(
new StreamException(childChannel.stream().id(), Http2Error.STREAM_CLOSED, "Stream Closed"));
});
final ChannelFuture future = childChannel.writeAndFlush(
final Future<Void> future = childChannel.writeAndFlush(
new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()));
parentChannel.flush();
@ -700,12 +698,12 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(
eq(headers), anyInt(), anyBoolean(), any(Promise.class))).thenAnswer(invocationOnMock -> {
return ((Promise<Void>) invocationOnMock.getArgument(5)).setFailure(
new Http2NoMoreStreamIdsException());
});
final ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
final Future<Void> future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
parentChannel.flush();
assertFalse(childChannel.isActive());
@ -735,10 +733,10 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
// Create a promise before actually doing the close, because otherwise we would be adding a listener to a future
// that is already completed because we are using EmbeddedChannel which executes code in the JUnit thread.
ChannelPromise p = childChannel.newPromise();
p.addListener((ChannelFutureListener) future -> {
channelOpen.set(future.channel().isOpen());
channelActive.set(future.channel().isActive());
Promise<Void> p = childChannel.newPromise();
p.addListener(childChannel, (channel, future) -> {
channelOpen.set(channel.isOpen());
channelActive.set(channel.isActive());
});
childChannel.close(p).syncUninterruptibly();
@ -758,9 +756,9 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
final AtomicBoolean channelOpen = new AtomicBoolean(true);
final AtomicBoolean channelActive = new AtomicBoolean(true);
childChannel.closeFuture().addListener((ChannelFutureListener) future -> {
channelOpen.set(future.channel().isOpen());
channelActive.set(future.channel().isActive());
childChannel.closeFuture().addListener(childChannel, (channel, future) -> {
channelOpen.set(channel.isOpen());
channelActive.set(channel.isActive());
});
childChannel.close().syncUninterruptibly();
@ -771,7 +769,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
@Test
public void channelClosedWhenWriteFutureFails() {
final Queue<ChannelPromise> writePromises = new ArrayDeque<ChannelPromise>();
final Queue<Promise<Void>> writePromises = new ArrayDeque<>();
LastInboundHandler inboundHandler = new LastInboundHandler();
Http2StreamChannel childChannel = newInboundStream(3, false, inboundHandler);
@ -785,20 +783,20 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
eq(headers), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
ChannelPromise promise = invocationOnMock.getArgument(5);
any(Promise.class))).thenAnswer(invocationOnMock -> {
Promise<Void> promise = invocationOnMock.getArgument(5);
writePromises.offer(promise);
return promise;
});
ChannelFuture f = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
Future<Void> f = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
assertFalse(f.isDone());
f.addListener((ChannelFutureListener) future-> {
channelOpen.set(future.channel().isOpen());
channelActive.set(future.channel().isActive());
f.addListener(childChannel, (channel, future)-> {
channelOpen.set(channel.isOpen());
channelActive.set(channel.isActive());
});
ChannelPromise first = writePromises.poll();
Promise<Void> first = writePromises.poll();
first.setFailure(new ClosedChannelException());
f.awaitUninterruptibly();
@ -885,7 +883,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
assertTrue(childChannel.isWritable());
assertEquals(bytesBeforeUnwritable, childChannel.bytesBeforeUnwritable());
ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2DataFrame(
Future<Void> future = childChannel.writeAndFlush(new DefaultHttp2DataFrame(
Unpooled.buffer().writeZero((int) bytesBeforeUnwritable)));
assertFalse(childChannel.isWritable());
assertTrue(parentChannel.isWritable());
@ -978,7 +976,7 @@ public abstract class Http2MultiplexTest<C extends Http2FrameCodec> {
Http2StreamChannel childChannel = newInboundStream(3, false, inboundHandler);
childChannel.unsafe().close(childChannel.newPromise());
ChannelPromise promise = childChannel.newPromise();
Promise<Void> promise = childChannel.newPromise();
childChannel.unsafe().close(promise);
promise.syncUninterruptibly();
childChannel.closeFuture().syncUninterruptibly();

View File

@ -19,7 +19,6 @@ import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
@ -44,8 +43,6 @@ import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.util.CharsetUtil;
import io.netty.util.NetUtil;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
@ -221,13 +218,12 @@ public class Http2MultiplexTransportTest {
if (msg instanceof Http2HeadersFrame && ((Http2HeadersFrame) msg).isEndStream()) {
executorService.schedule(() -> {
ctx.writeAndFlush(new DefaultHttp2HeadersFrame(
new DefaultHttp2Headers(), false)).addListener(
(ChannelFutureListener) future -> {
ctx.write(new DefaultHttp2DataFrame(
Unpooled.copiedBuffer("Hello World",
CharsetUtil.US_ASCII), true));
ctx.channel().eventLoop().execute(ctx::flush);
});
new DefaultHttp2Headers(), false)).addListener(future -> {
ctx.write(new DefaultHttp2DataFrame(
Unpooled.copiedBuffer("Hello World",
CharsetUtil.US_ASCII), true));
ctx.channel().eventLoop().execute(ctx::flush);
});
}, 500, MILLISECONDS);
}
ReferenceCountUtil.release(msg);
@ -406,15 +402,12 @@ public class Http2MultiplexTransportTest {
latch.countDown();
}
});
h2Bootstrap.open().addListener(new FutureListener<Channel>() {
@Override
public void operationComplete(Future<Channel> future) {
if (future.isSuccess()) {
future.getNow().writeAndFlush(new DefaultHttp2HeadersFrame(
new DefaultHttp2Headers(), false));
}
}
});
h2Bootstrap.open().addListener(future -> {
if (future.isSuccess()) {
future.getNow().writeAndFlush(new DefaultHttp2HeadersFrame(
new DefaultHttp2Headers(), false));
}
});
} else if (handshakeCompletionEvent.cause() instanceof SSLException) {
// In case of TLSv1.2 we should never see the handshake succeed as the alert for
@ -548,13 +541,10 @@ public class Http2MultiplexTransportTest {
ReferenceCountUtil.release(msg);
}
});
h2Bootstrap.open().addListener(new FutureListener<Channel>() {
@Override
public void operationComplete(Future<Channel> future) {
if (future.isSuccess()) {
future.getNow().writeAndFlush(new DefaultHttp2HeadersFrame(
new DefaultHttp2Headers(), true));
}
h2Bootstrap.open().addListener(future -> {
if (future.isSuccess()) {
future.getNow().writeAndFlush(new DefaultHttp2HeadersFrame(
new DefaultHttp2Headers(), true));
}
});
}

View File

@ -21,7 +21,6 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.EncoderException;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
@ -39,13 +38,14 @@ import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
@ -56,10 +56,10 @@ import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class Http2StreamFrameToHttpObjectCodecTest {
@ -454,7 +454,7 @@ public class Http2StreamFrameToHttpObjectCodecTest {
EmbeddedChannel ch = new EmbeddedChannel(ctx.newHandler(ByteBufAllocator.DEFAULT),
new ChannelHandler() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (msg instanceof Http2StreamFrame) {
frames.add((Http2StreamFrame) msg);
ctx.write(Unpooled.EMPTY_BUFFER, promise);
@ -884,10 +884,10 @@ public class Http2StreamFrameToHttpObjectCodecTest {
EmbeddedChannel tlsCh = new EmbeddedChannel(ctx.newHandler(ByteBufAllocator.DEFAULT),
new ChannelHandler() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (msg instanceof Http2StreamFrame) {
frames.add((Http2StreamFrame) msg);
promise.setSuccess();
promise.setSuccess(null);
} else {
ctx.write(msg, promise);
}
@ -897,10 +897,10 @@ public class Http2StreamFrameToHttpObjectCodecTest {
EmbeddedChannel plaintextCh = new EmbeddedChannel(
new ChannelHandler() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (msg instanceof Http2StreamFrame) {
frames.add((Http2StreamFrame) msg);
promise.setSuccess();
promise.setSuccess(null);
} else {
ctx.write(msg, promise);
}

View File

@ -19,19 +19,13 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelPromise;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.AsciiString;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor;
import junit.framework.AssertionFailedError;
import io.netty.util.concurrent.Promise;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Random;
@ -56,6 +50,7 @@ import static org.mockito.Mockito.when;
/**
* Utilities for the integration tests.
*/
@SuppressWarnings("unchecked")
public final class Http2TestUtil {
/**
* Interface that allows for running a operation that throws a {@link Http2Exception}.
@ -367,55 +362,55 @@ public final class Http2TestUtil {
when(frameWriter.configuration()).thenReturn(configuration);
when(frameWriter.writeSettings(any(ChannelHandlerContext.class), any(Http2Settings.class),
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
((ChannelPromise) invocationOnMock.getArgument(2)).setSuccess());
any(Promise.class))).thenAnswer((Answer<Future<Void>>) invocationOnMock ->
((Promise<Void>) invocationOnMock.getArgument(2)).setSuccess(null));
when(frameWriter.writeSettingsAck(any(ChannelHandlerContext.class), any(ChannelPromise.class)))
.thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
((ChannelPromise) invocationOnMock.getArgument(1)).setSuccess());
when(frameWriter.writeSettingsAck(any(ChannelHandlerContext.class), any(Promise.class)))
.thenAnswer((Answer<Future<Void>>) invocationOnMock ->
((Promise<Void>) invocationOnMock.getArgument(1)).setSuccess(null));
when(frameWriter.writeGoAway(any(ChannelHandlerContext.class), anyInt(),
anyLong(), any(ByteBuf.class), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
anyLong(), any(ByteBuf.class), any(Promise.class))).thenAnswer(invocationOnMock -> {
buffers.offer((ByteBuf) invocationOnMock.getArgument(3));
return ((ChannelPromise) invocationOnMock.getArgument(4)).setSuccess();
return ((Promise<Void>) invocationOnMock.getArgument(4)).setSuccess(null);
});
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class), anyInt(),
anyBoolean(), any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess());
anyBoolean(), any(Promise.class))).thenAnswer((Answer<Future<Void>>) invocationOnMock ->
((Promise<Void>) invocationOnMock.getArgument(5)).setSuccess(null));
when(frameWriter.writeHeaders(any(ChannelHandlerContext.class), anyInt(),
any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
((ChannelPromise) invocationOnMock.getArgument(8)).setSuccess());
any(Promise.class))).thenAnswer((Answer<Future<Void>>) invocationOnMock ->
((Promise<Void>) invocationOnMock.getArgument(8)).setSuccess(null));
when(frameWriter.writeData(any(ChannelHandlerContext.class), anyInt(), any(ByteBuf.class), anyInt(),
anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> {
anyBoolean(), any(Promise.class))).thenAnswer(invocationOnMock -> {
buffers.offer((ByteBuf) invocationOnMock.getArgument(2));
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
return ((Promise<Void>) invocationOnMock.getArgument(5)).setSuccess(null);
});
when(frameWriter.writeRstStream(any(ChannelHandlerContext.class), anyInt(),
anyLong(), any(ChannelPromise.class))).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
((ChannelPromise) invocationOnMock.getArgument(3)).setSuccess());
anyLong(), any(Promise.class))).thenAnswer((Answer<Future<Void>>) invocationOnMock ->
((Promise<Void>) invocationOnMock.getArgument(3)).setSuccess(null));
when(frameWriter.writeWindowUpdate(any(ChannelHandlerContext.class), anyInt(), anyInt(),
any(ChannelPromise.class))).then((Answer<ChannelFuture>) invocationOnMock ->
((ChannelPromise) invocationOnMock.getArgument(3)).setSuccess());
any(Promise.class))).then((Answer<Future<Void>>) invocationOnMock ->
((Promise<Void>) invocationOnMock.getArgument(3)).setSuccess(null));
when(frameWriter.writePushPromise(any(ChannelHandlerContext.class), anyInt(), anyInt(), any(Http2Headers.class),
anyInt(), anyChannelPromise())).thenAnswer((Answer<ChannelFuture>) invocationOnMock ->
((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess());
anyInt(), anyChannelPromise())).thenAnswer((Answer<Future<Void>>) invocationOnMock ->
((Promise<Void>) invocationOnMock.getArgument(5)).setSuccess(null));
when(frameWriter.writeFrame(any(ChannelHandlerContext.class), anyByte(), anyInt(), any(Http2Flags.class),
any(ByteBuf.class), anyChannelPromise())).thenAnswer(invocationOnMock -> {
buffers.offer((ByteBuf) invocationOnMock.getArgument(4));
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
return ((Promise<Void>) invocationOnMock.getArgument(5)).setSuccess(null);
});
return frameWriter;
}
static ChannelPromise anyChannelPromise() {
return any(ChannelPromise.class);
static Promise<Void> anyChannelPromise() {
return any(Promise.class);
}
static Http2Settings anyHttp2Settings() {

View File

@ -19,12 +19,10 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MultithreadEventLoopGroup;
import io.netty.channel.local.LocalAddress;
import io.netty.channel.local.LocalChannel;
@ -43,6 +41,7 @@ import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http2.Http2TestUtil.FrameCountDown;
import io.netty.util.AsciiString;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -146,7 +145,7 @@ public class HttpToHttp2ConnectionHandlerTest {
.add(new AsciiString("foo"), new AsciiString("goo2"))
.add(new AsciiString("foo2"), new AsciiString("goo2"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -169,7 +168,7 @@ public class HttpToHttp2ConnectionHandlerTest {
.add(new AsciiString("foo"), new AsciiString("goo2"))
.add(new AsciiString("foo2"), new AsciiString("goo2"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -190,7 +189,7 @@ public class HttpToHttp2ConnectionHandlerTest {
.add(HttpHeaderNames.COOKIE, "c=d")
.add(HttpHeaderNames.COOKIE, "e=f");
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -206,7 +205,7 @@ public class HttpToHttp2ConnectionHandlerTest {
.path(new AsciiString("/where?q=now&f=then#section1"))
.scheme(new AsciiString("http"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -223,7 +222,7 @@ public class HttpToHttp2ConnectionHandlerTest {
.path(new AsciiString("/where%2B0?q=now%2B0&f=then%2B0#section1%2B0"))
.scheme(new AsciiString("http"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -241,7 +240,7 @@ public class HttpToHttp2ConnectionHandlerTest {
.path(new AsciiString("/pub/WWW/TheProject.html"))
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("https"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -257,7 +256,7 @@ public class HttpToHttp2ConnectionHandlerTest {
.path(new AsciiString("/pub/WWW/TheProject.html"))
.authority(new AsciiString("www.example.org:5555")).scheme(new AsciiString("http"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -271,7 +270,7 @@ public class HttpToHttp2ConnectionHandlerTest {
new DefaultHttp2Headers().method(new AsciiString("CONNECT")).path(new AsciiString("/"))
.scheme(new AsciiString("http")).authority(new AsciiString("www.example.com:80"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -287,7 +286,7 @@ public class HttpToHttp2ConnectionHandlerTest {
new DefaultHttp2Headers().method(new AsciiString("OPTIONS")).path(new AsciiString("*"))
.scheme(new AsciiString("http")).authority(new AsciiString("www.example.com:80"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -305,7 +304,7 @@ public class HttpToHttp2ConnectionHandlerTest {
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
.scheme(new AsciiString("http")).authority(new AsciiString("[::1]:80"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -321,7 +320,7 @@ public class HttpToHttp2ConnectionHandlerTest {
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
.scheme(new AsciiString("http")).authority(new AsciiString("localhost:80"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -337,7 +336,7 @@ public class HttpToHttp2ConnectionHandlerTest {
new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/"))
.scheme(new AsciiString("http")).authority(new AsciiString("1.2.3.4:80"));
ChannelPromise writePromise = newPromise();
Promise<Void> writePromise = newPromise();
verifyHeadersOnly(http2Headers, writePromise, clientChannel.writeAndFlush(request, writePromise));
}
@ -348,8 +347,8 @@ public class HttpToHttp2ConnectionHandlerTest {
final HttpHeaders httpHeaders = request.headers();
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
httpHeaders.set(HttpHeaderNames.HOST, "localhost");
ChannelPromise writePromise = newPromise();
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
Promise<Void> writePromise = newPromise();
Future<Void> writeFuture = clientChannel.writeAndFlush(request, writePromise);
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
assertTrue(writePromise.isDone());
@ -367,8 +366,8 @@ public class HttpToHttp2ConnectionHandlerTest {
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), -1);
httpHeaders.set(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), "http");
httpHeaders.set(HttpHeaderNames.HOST, "localhost");
ChannelPromise writePromise = newPromise();
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
Promise<Void> writePromise = newPromise();
Future<Void> writeFuture = clientChannel.writeAndFlush(request, writePromise);
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
assertTrue(writePromise.isDone());
@ -406,8 +405,8 @@ public class HttpToHttp2ConnectionHandlerTest {
.add(new AsciiString("foo"), new AsciiString("goo"))
.add(new AsciiString("foo"), new AsciiString("goo2"))
.add(new AsciiString("foo2"), new AsciiString("goo2"));
ChannelPromise writePromise = newPromise();
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
Promise<Void> writePromise = newPromise();
Future<Void> writeFuture = clientChannel.writeAndFlush(request, writePromise);
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
assertTrue(writePromise.isSuccess());
@ -452,8 +451,8 @@ public class HttpToHttp2ConnectionHandlerTest {
final Http2Headers http2TrailingHeaders = new DefaultHttp2Headers()
.add(new AsciiString("trailing"), new AsciiString("bar"));
ChannelPromise writePromise = newPromise();
ChannelFuture writeFuture = clientChannel.writeAndFlush(request, writePromise);
Promise<Void> writePromise = newPromise();
Future<Void> writeFuture = clientChannel.writeAndFlush(request, writePromise);
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
assertTrue(writePromise.isSuccess());
@ -504,12 +503,12 @@ public class HttpToHttp2ConnectionHandlerTest {
final Http2Headers http2TrailingHeaders = new DefaultHttp2Headers()
.add(new AsciiString("trailing"), new AsciiString("bar"));
ChannelPromise writePromise = newPromise();
ChannelFuture writeFuture = clientChannel.write(request, writePromise);
ChannelPromise contentPromise = newPromise();
ChannelFuture contentFuture = clientChannel.write(httpContent, contentPromise);
ChannelPromise lastContentPromise = newPromise();
ChannelFuture lastContentFuture = clientChannel.write(lastHttpContent, lastContentPromise);
Promise<Void> writePromise = newPromise();
Future<Void> writeFuture = clientChannel.write(request, writePromise);
Promise<Void> contentPromise = newPromise();
Future<Void> contentFuture = clientChannel.write(httpContent, contentPromise);
Promise<Void> lastContentPromise = newPromise();
Future<Void> lastContentFuture = clientChannel.write(lastHttpContent, lastContentPromise);
clientChannel.flush();
@ -598,7 +597,7 @@ public class HttpToHttp2ConnectionHandlerTest {
assertTrue(serverChannelLatch.await(WAIT_TIME_SECONDS, SECONDS));
}
private void verifyHeadersOnly(Http2Headers expected, ChannelPromise writePromise, ChannelFuture writeFuture)
private void verifyHeadersOnly(Http2Headers expected, Promise<Void> writePromise, Future<Void> writeFuture)
throws Exception {
assertTrue(writePromise.awaitUninterruptibly(WAIT_TIME_SECONDS, SECONDS));
assertTrue(writePromise.isSuccess());
@ -623,7 +622,7 @@ public class HttpToHttp2ConnectionHandlerTest {
return clientChannel.pipeline().firstContext();
}
private ChannelPromise newPromise() {
private Promise<Void> newPromise() {
return ctx().newPromise();
}
}

View File

@ -23,7 +23,6 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.MultithreadEventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.local.LocalAddress;
@ -44,6 +43,7 @@ import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -732,7 +732,7 @@ public class InboundHttp2ToHttpAdapterTest {
return clientChannel.pipeline().firstContext();
}
private ChannelPromise newPromiseClient() {
private Promise<Void> newPromiseClient() {
return ctxClient().newPromise();
}
@ -740,7 +740,7 @@ public class InboundHttp2ToHttpAdapterTest {
return serverConnectedChannel.pipeline().firstContext();
}
private ChannelPromise newPromiseServer() {
private Promise<Void> newPromiseServer() {
return ctxServer().newPromise();
}

View File

@ -15,6 +15,34 @@
package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.DefaultMessageSizeEstimator;
import io.netty.handler.codec.http2.StreamBufferingEncoder.Http2GoAwayException;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.verification.VerificationMode;
import java.util.ArrayList;
import java.util.List;
import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_FRAME_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT;
@ -30,45 +58,18 @@ import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyShort;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelPromise;
import io.netty.channel.DefaultMessageSizeEstimator;
import io.netty.handler.codec.http2.StreamBufferingEncoder.Http2GoAwayException;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.ImmediateEventExecutor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.verification.VerificationMode;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for {@link StreamBufferingEncoder}.
*/
@SuppressWarnings("unchecked")
public class StreamBufferingEncoderTest {
private StreamBufferingEncoder encoder;
@ -106,16 +107,16 @@ public class StreamBufferingEncoderTest {
when(configuration.frameSizePolicy()).thenReturn(frameSizePolicy);
when(frameSizePolicy.maxFrameSize()).thenReturn(DEFAULT_MAX_FRAME_SIZE);
when(writer.writeData(any(ChannelHandlerContext.class), anyInt(), any(ByteBuf.class), anyInt(), anyBoolean(),
any(ChannelPromise.class))).thenAnswer(successAnswer());
when(writer.writeRstStream(eq(ctx), anyInt(), anyLong(), any(ChannelPromise.class))).thenAnswer(
any(Promise.class))).thenAnswer(successAnswer());
when(writer.writeRstStream(eq(ctx), anyInt(), anyLong(), any(Promise.class))).thenAnswer(
successAnswer());
when(writer.writeGoAway(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class),
any(ChannelPromise.class)))
any(Promise.class)))
.thenAnswer(successAnswer());
when(writer.writeHeaders(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(noopAnswer());
anyInt(), anyBoolean(), any(Promise.class))).thenAnswer(noopAnswer());
when(writer.writeHeaders(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class),
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(), any(ChannelPromise.class)))
anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(), any(Promise.class)))
.thenAnswer(noopAnswer());
connection = new DefaultHttp2Connection(false);
@ -136,7 +137,7 @@ public class StreamBufferingEncoderTest {
when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
when(channel.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT);
when(executor.inEventLoop()).thenReturn(true);
doAnswer((Answer<ChannelPromise>) invocation -> newPromise()).when(ctx).newPromise();
doAnswer((Answer<Promise<Void>>) invocation -> newPromise()).when(ctx).newPromise();
when(ctx.executor()).thenReturn(executor);
when(channel.isActive()).thenReturn(false);
when(channel.config()).thenReturn(config);
@ -172,7 +173,7 @@ public class StreamBufferingEncoderTest {
// Contiguous data writes are coalesced
ArgumentCaptor<ByteBuf> bufCaptor = ArgumentCaptor.forClass(ByteBuf.class);
verify(writer, times(1)).writeData(any(ChannelHandlerContext.class), eq(3),
bufCaptor.capture(), eq(0), eq(false), any(ChannelPromise.class));
bufCaptor.capture(), eq(0), eq(false), any(Promise.class));
assertEquals(expectedBytes, bufCaptor.getValue().readableBytes());
}
@ -228,7 +229,7 @@ public class StreamBufferingEncoderTest {
setMaxConcurrentStreams(0);
connection.goAwayReceived(1, 8, EMPTY_BUFFER);
ChannelPromise promise = newPromise();
Promise<Void> promise = newPromise();
encoderWriteHeaders(3, promise);
assertEquals(0, encoder.numBufferedStreams());
assertTrue(promise.isDone());
@ -241,7 +242,7 @@ public class StreamBufferingEncoderTest {
setMaxConcurrentStreams(5);
int streamId = 3;
List<ChannelFuture> futures = new ArrayList<>();
List<Future<Void>> futures = new ArrayList<>();
for (int i = 0; i < 9; i++) {
futures.add(encoderWriteHeaders(streamId, newPromise()));
streamId += 2;
@ -254,7 +255,7 @@ public class StreamBufferingEncoderTest {
assertEquals(5, connection.numActiveStreams());
assertEquals(0, encoder.numBufferedStreams());
int failCount = 0;
for (ChannelFuture f : futures) {
for (Future<Void> f : futures) {
if (f.cause() != null) {
assertTrue(f.cause() instanceof Http2GoAwayException);
failCount++;
@ -269,7 +270,7 @@ public class StreamBufferingEncoderTest {
setMaxConcurrentStreams(1);
encoderWriteHeaders(3, newPromise());
connection.goAwayReceived(11, 8, EMPTY_BUFFER);
ChannelFuture f = encoderWriteHeaders(5, newPromise());
Future<Void> f = encoderWriteHeaders(5, newPromise());
assertTrue(f.cause() instanceof Http2GoAwayException);
assertEquals(0, encoder.numBufferedStreams());
@ -281,15 +282,15 @@ public class StreamBufferingEncoderTest {
setMaxConcurrentStreams(1);
when(writer.writeHeaders(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class), anyInt(),
anyBoolean(), any(ChannelPromise.class))).thenAnswer(successAnswer());
anyBoolean(), any(Promise.class))).thenAnswer(successAnswer());
when(writer.writeHeaders(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class), anyInt(),
anyShort(), anyBoolean(), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(successAnswer());
anyShort(), anyBoolean(), anyInt(), anyBoolean(), any(Promise.class))).thenAnswer(successAnswer());
ChannelFuture f1 = encoderWriteHeaders(3, newPromise());
Future<Void> f1 = encoderWriteHeaders(3, newPromise());
assertEquals(0, encoder.numBufferedStreams());
ChannelFuture f2 = encoderWriteHeaders(5, newPromise());
Future<Void> f2 = encoderWriteHeaders(5, newPromise());
assertEquals(1, encoder.numBufferedStreams());
ChannelFuture f3 = encoderWriteHeaders(7, newPromise());
Future<Void> f3 = encoderWriteHeaders(7, newPromise());
assertEquals(2, encoder.numBufferedStreams());
ByteBuf empty = Unpooled.buffer(0);
@ -333,7 +334,7 @@ public class StreamBufferingEncoderTest {
encoderWriteHeaders(3, newPromise());
assertEquals(1, encoder.numBufferedStreams());
ChannelPromise rstStreamPromise = newPromise();
Promise<Void> rstStreamPromise = newPromise();
encoder.writeRstStream(ctx, 3, CANCEL.code(), rstStreamPromise);
assertTrue(rstStreamPromise.isSuccess());
assertEquals(0, encoder.numBufferedStreams());
@ -457,7 +458,7 @@ public class StreamBufferingEncoderTest {
setMaxConcurrentStreams(0);
// Simulate numeric overflow for the next stream ID.
ChannelFuture f = encoderWriteHeaders(-1, newPromise());
Future<Void> f = encoderWriteHeaders(-1, newPromise());
// Verify that the write fails.
assertNotNull(f.cause());
@ -468,15 +469,15 @@ public class StreamBufferingEncoderTest {
encoder.writeSettingsAck(ctx, newPromise());
setMaxConcurrentStreams(0);
ByteBuf data = mock(ByteBuf.class);
ChannelFuture f1 = encoderWriteHeaders(3, newPromise());
Future<Void> f1 = encoderWriteHeaders(3, newPromise());
assertEquals(1, encoder.numBufferedStreams());
ChannelFuture f2 = encoder.writeData(ctx, 3, data, 0, false, newPromise());
Future<Void> f2 = encoder.writeData(ctx, 3, data, 0, false, newPromise());
ChannelPromise rstPromise = mock(ChannelPromise.class);
Promise<Void> rstPromise = mock(Promise.class);
encoder.writeRstStream(ctx, 3, CANCEL.code(), rstPromise);
assertEquals(0, encoder.numBufferedStreams());
verify(rstPromise).setSuccess();
verify(rstPromise).setSuccess(null);
assertTrue(f1.isSuccess());
assertTrue(f2.isSuccess());
verify(data).release();
@ -487,9 +488,9 @@ public class StreamBufferingEncoderTest {
encoder.writeSettingsAck(ctx, newPromise());
connection.local().maxActiveStreams(0);
ChannelFuture f1 = encoderWriteHeaders(3, newPromise());
ChannelFuture f2 = encoderWriteHeaders(5, newPromise());
ChannelFuture f3 = encoderWriteHeaders(7, newPromise());
Future<Void> f1 = encoderWriteHeaders(3, newPromise());
Future<Void> f2 = encoderWriteHeaders(5, newPromise());
Future<Void> f3 = encoderWriteHeaders(7, newPromise());
encoder.close();
assertNotNull(f1.cause());
@ -502,7 +503,7 @@ public class StreamBufferingEncoderTest {
encoder.writeSettingsAck(ctx, newPromise());
encoder.close();
ChannelFuture f = encoderWriteHeaders(3, newPromise());
Future<Void> f = encoderWriteHeaders(3, newPromise());
assertNotNull(f.cause());
}
@ -516,7 +517,7 @@ public class StreamBufferingEncoderTest {
}
}
private ChannelFuture encoderWriteHeaders(int streamId, ChannelPromise promise) {
private Future<Void> encoderWriteHeaders(int streamId, Promise<Void> promise) {
encoder.writeHeaders(ctx, streamId, new DefaultHttp2Headers(), 0, DEFAULT_PRIORITY_WEIGHT,
false, 0, false, promise);
try {
@ -530,28 +531,28 @@ public class StreamBufferingEncoderTest {
private void writeVerifyWriteHeaders(VerificationMode mode, int streamId) {
verify(writer, mode).writeHeaders(eq(ctx), eq(streamId), any(Http2Headers.class), eq(0),
eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0),
eq(false), any(ChannelPromise.class));
eq(false), any(Promise.class));
}
private Answer<ChannelFuture> successAnswer() {
private static Answer<Future<Void>> successAnswer() {
return invocation -> {
for (Object a : invocation.getArguments()) {
ReferenceCountUtil.safeRelease(a);
}
ChannelPromise future = newPromise();
future.setSuccess();
Promise<Void> future = newPromise();
future.setSuccess(null);
return future;
};
}
private Answer<ChannelFuture> noopAnswer() {
return new Answer<ChannelFuture>() {
private static Answer<Future<Void>> noopAnswer() {
return new Answer<Future<Void>>() {
@Override
public ChannelFuture answer(InvocationOnMock invocation) throws Throwable {
public Future<Void> answer(InvocationOnMock invocation) throws Throwable {
for (Object a : invocation.getArguments()) {
if (a instanceof ChannelPromise) {
return (ChannelFuture) a;
if (a instanceof Promise) {
return (Future<Void>) a;
}
}
return newPromise();
@ -559,8 +560,8 @@ public class StreamBufferingEncoderTest {
};
}
private ChannelPromise newPromise() {
return new DefaultChannelPromise(channel, ImmediateEventExecutor.INSTANCE);
private static Promise<Void> newPromise() {
return new DefaultPromise<Void>(ImmediateEventExecutor.INSTANCE);
}
private static ByteBuf data() {

View File

@ -18,17 +18,17 @@ package io.netty.handler.codec.memcache.binary;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.CombinedChannelDuplexHandler;
import io.netty.handler.codec.PrematureChannelClosureException;
import io.netty.handler.codec.memcache.LastMemcacheContent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.UnstableApi;
import java.net.SocketAddress;
@ -108,52 +108,63 @@ public final class BinaryMemcacheClientCodec extends
return ctx.channel();
}
@Override
public EventExecutor executor() {
return ctx.executor();
}
@Override
public String name() {
return ctx.name();
}
@Override
public ChannelHandler handler() {
return ctx.handler();
}
@Override
public boolean isRemoved() {
return ctx.isRemoved();
}
@Override
public ChannelHandlerContext fireChannelRegistered() {
ctx.fireChannelRegistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelUnregistered() {
ctx.fireChannelUnregistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelActive() {
ctx.fireChannelActive();
return this;
}
@Override
public ChannelHandlerContext fireChannelInactive() {
ctx.fireChannelInactive();
return this;
}
@Override
public ChannelHandlerContext fireExceptionCaught(Throwable cause) {
ctx.fireExceptionCaught(cause);
return this;
}
@Override
public ChannelHandlerContext fireUserEventTriggered(Object evt) {
ctx.fireUserEventTriggered(evt);
return this;
}
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
if (failOnMissingResponse && msg instanceof LastMemcacheContent) {
requestResponseCounter.decrementAndGet();
@ -162,128 +173,155 @@ public final class BinaryMemcacheClientCodec extends
return this;
}
@Override
public ChannelHandlerContext fireChannelReadComplete() {
ctx.fireChannelReadComplete();
return this;
}
@Override
public ChannelHandlerContext fireChannelWritabilityChanged() {
ctx.fireChannelWritabilityChanged();
return this;
}
@Override
public ChannelHandlerContext read() {
ctx.read();
return this;
}
@Override
public ChannelHandlerContext flush() {
ctx.flush();
return this;
}
@Override
public ChannelPipeline pipeline() {
return ctx.pipeline();
}
@Override
public ByteBufAllocator alloc() {
return ctx.alloc();
}
@Override
@Deprecated
public <T> Attribute<T> attr(AttributeKey<T> key) {
return ctx.attr(key);
}
@Override
@Deprecated
public <T> boolean hasAttr(AttributeKey<T> key) {
return ctx.hasAttr(key);
}
public ChannelFuture bind(SocketAddress localAddress) {
@Override
public Future<Void> bind(SocketAddress localAddress) {
return ctx.bind(localAddress);
}
public ChannelFuture connect(SocketAddress remoteAddress) {
@Override
public Future<Void> connect(SocketAddress remoteAddress) {
return ctx.connect(remoteAddress);
}
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
@Override
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return ctx.connect(remoteAddress, localAddress);
}
public ChannelFuture disconnect() {
@Override
public Future<Void> disconnect() {
return ctx.disconnect();
}
public ChannelFuture close() {
@Override
public Future<Void> close() {
return ctx.close();
}
public ChannelFuture deregister() {
@Override
public Future<Void> deregister() {
return ctx.deregister();
}
@Override
public ChannelFuture register() {
public Future<Void> register() {
return ctx.register();
}
@Override
public ChannelFuture register(ChannelPromise promise) {
public Future<Void> register(Promise<Void> promise) {
return ctx.register(promise);
}
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
@Override
public Future<Void> bind(SocketAddress localAddress, Promise<Void> promise) {
return ctx.bind(localAddress, promise);
}
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
@Override
public Future<Void> connect(SocketAddress remoteAddress, Promise<Void> promise) {
return ctx.connect(remoteAddress, promise);
}
public ChannelFuture connect(
SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
@Override
public Future<Void> connect(
SocketAddress remoteAddress, SocketAddress localAddress, Promise<Void> promise) {
return ctx.connect(remoteAddress, localAddress, promise);
}
public ChannelFuture disconnect(ChannelPromise promise) {
@Override
public Future<Void> disconnect(Promise<Void> promise) {
return ctx.disconnect(promise);
}
public ChannelFuture close(ChannelPromise promise) {
@Override
public Future<Void> close(Promise<Void> promise) {
return ctx.close(promise);
}
public ChannelFuture deregister(ChannelPromise promise) {
@Override
public Future<Void> deregister(Promise<Void> promise) {
return ctx.deregister(promise);
}
public ChannelFuture write(Object msg) {
@Override
public Future<Void> write(Object msg) {
return ctx.write(msg);
}
public ChannelFuture write(Object msg, ChannelPromise promise) {
@Override
public Future<Void> write(Object msg, Promise<Void> promise) {
return ctx.write(msg, promise);
}
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
@Override
public Future<Void> writeAndFlush(Object msg, Promise<Void> promise) {
return ctx.writeAndFlush(msg, promise);
}
public ChannelFuture writeAndFlush(Object msg) {
@Override
public Future<Void> writeAndFlush(Object msg) {
return ctx.writeAndFlush(msg);
}
public ChannelPromise newPromise() {
@Override
public Promise<Void> newPromise() {
return ctx.newPromise();
}
public ChannelFuture newSucceededFuture() {
@Override
public Future<Void> newSucceededFuture() {
return ctx.newSucceededFuture();
}
public ChannelFuture newFailedFuture(Throwable cause) {
@Override
public Future<Void> newFailedFuture(Throwable cause) {
return ctx.newFailedFuture(cause);
}
};

View File

@ -18,7 +18,7 @@ package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.TypeParameterMatcher;
/**
@ -102,7 +102,7 @@ public abstract class ByteToMessageCodec<I> extends ChannelHandlerAdapter {
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
encoder.write(ctx, msg, promise);
}

View File

@ -15,31 +15,30 @@
*/
package io.netty.handler.codec;
import static io.netty.util.internal.ObjectUtil.checkPositive;
import static java.util.Objects.requireNonNull;
import io.netty.buffer.ByteBufConvertible;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufConvertible;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.ChannelInputShutdownEvent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.StringUtil;
import java.net.SocketAddress;
import static io.netty.util.internal.ObjectUtil.checkPositive;
import static java.lang.Integer.MAX_VALUE;
import static java.util.Objects.requireNonNull;
/**
* {@link ChannelHandler} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an
@ -137,7 +136,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
composite.capacity(composite.writerIndex());
}
} else {
composite = alloc.compositeBuffer(Integer.MAX_VALUE).addFlattenedComponents(true, cumulation);
composite = alloc.compositeBuffer(MAX_VALUE).addFlattenedComponents(true, cumulation);
}
composite.addFlattenedComponents(true, in);
in = null;
@ -235,8 +234,8 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
@Override
public final void handlerAdded(ChannelHandlerContext ctx) throws Exception {
this.context = new ByteToMessageDecoderContext(ctx);
handlerAdded0(this.context);
context = new ByteToMessageDecoderContext(ctx);
handlerAdded0(context);
}
protected void handlerAdded0(ChannelHandlerContext ctx) throws Exception {
@ -257,7 +256,7 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
buf.release();
}
}
handlerRemoved0(this.context);
handlerRemoved0(context);
}
/**
@ -635,107 +634,107 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter {
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
public Future<Void> bind(SocketAddress localAddress) {
return ctx.bind(localAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
public Future<Void> connect(SocketAddress remoteAddress) {
return ctx.connect(remoteAddress);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return ctx.connect(remoteAddress, localAddress);
}
@Override
public ChannelFuture disconnect() {
public Future<Void> disconnect() {
return ctx.disconnect();
}
@Override
public ChannelFuture close() {
public Future<Void> close() {
return ctx.close();
}
@Override
public ChannelFuture deregister() {
public Future<Void> deregister() {
return ctx.deregister();
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> bind(SocketAddress localAddress, Promise<Void> promise) {
return ctx.bind(localAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
public Future<Void> connect(SocketAddress remoteAddress, Promise<Void> promise) {
return ctx.connect(remoteAddress, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
public Future<Void> connect(SocketAddress remoteAddress, SocketAddress localAddress, Promise<Void> promise) {
return ctx.connect(remoteAddress, localAddress, promise);
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
public Future<Void> disconnect(Promise<Void> promise) {
return ctx.disconnect(promise);
}
@Override
public ChannelFuture close(ChannelPromise promise) {
public Future<Void> close(Promise<Void> promise) {
return ctx.close(promise);
}
@Override
public ChannelFuture register() {
public Future<Void> register() {
return ctx.register();
}
@Override
public ChannelFuture register(ChannelPromise promise) {
public Future<Void> register(Promise<Void> promise) {
return ctx.register(promise);
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
public Future<Void> deregister(Promise<Void> promise) {
return ctx.deregister(promise);
}
@Override
public ChannelFuture write(Object msg) {
public Future<Void> write(Object msg) {
return ctx.write(msg);
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
public Future<Void> write(Object msg, Promise<Void> promise) {
return ctx.write(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
public Future<Void> writeAndFlush(Object msg, Promise<Void> promise) {
return ctx.writeAndFlush(msg, promise);
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
public Future<Void> writeAndFlush(Object msg) {
return ctx.writeAndFlush(msg);
}
@Override
public ChannelPromise newPromise() {
public Promise<Void> newPromise() {
return ctx.newPromise();
}
@Override
public ChannelFuture newSucceededFuture() {
public Future<Void> newSucceededFuture() {
return ctx.newSucceededFuture();
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
public Future<Void> newFailedFuture(Throwable cause) {
return ctx.newFailedFuture(cause);
}
}

View File

@ -15,21 +15,21 @@
*/
package io.netty.handler.codec;
import static java.util.Objects.requireNonNull;
import io.netty.buffer.ByteBufConvertible;
import io.netty.channel.AddressedEnvelope;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.StringUtil;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import static java.util.Objects.requireNonNull;
/**
* An encoder that encodes the content in {@link AddressedEnvelope} to {@link DatagramPacket} using
* the specified message encoder. E.g.,
@ -91,29 +91,29 @@ public class DatagramPacketEncoder<M> extends MessageToMessageEncoder<AddressedE
}
@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, Promise<Void> promise) {
encoder.bind(ctx, localAddress, promise);
}
@Override
public void connect(
ChannelHandlerContext ctx, SocketAddress remoteAddress,
SocketAddress localAddress, ChannelPromise promise) {
SocketAddress localAddress, Promise<Void> promise) {
encoder.connect(ctx, remoteAddress, localAddress, promise);
}
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
public void disconnect(ChannelHandlerContext ctx, Promise<Void> promise) {
encoder.disconnect(ctx, promise);
}
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
public void close(ChannelHandlerContext ctx, Promise<Void> promise) {
encoder.close(ctx, promise);
}
@Override
public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) {
public void deregister(ChannelHandlerContext ctx, Promise<Void> promise) {
encoder.deregister(ctx, promise);
}

View File

@ -18,12 +18,13 @@ package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.CompositeByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFutureListeners;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureContextListener;
import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
@ -58,7 +59,7 @@ public abstract class MessageAggregator<I, S, C extends ByteBufHolder, O extends
private int maxCumulationBufferComponents = DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS;
private ChannelHandlerContext ctx;
private ChannelFutureListener continueResponseWriteListener;
private FutureContextListener<ChannelHandlerContext, Void> continueResponseWriteListener;
private boolean aggregating;
@ -221,11 +222,11 @@ public abstract class MessageAggregator<I, S, C extends ByteBufHolder, O extends
Object continueResponse = newContinueResponse(m, maxContentLength, ctx.pipeline());
if (continueResponse != null) {
// Cache the write listener for reuse.
ChannelFutureListener listener = continueResponseWriteListener;
FutureContextListener<ChannelHandlerContext, Void> listener = continueResponseWriteListener;
if (listener == null) {
continueResponseWriteListener = listener = future -> {
continueResponseWriteListener = listener = (context, future) -> {
if (!future.isSuccess()) {
ctx.fireExceptionCaught(future.cause());
context.fireExceptionCaught(future.cause());
}
};
}
@ -234,10 +235,10 @@ public abstract class MessageAggregator<I, S, C extends ByteBufHolder, O extends
boolean closeAfterWrite = closeAfterContinueResponse(continueResponse);
handlingOversizedMessage = ignoreContentAfterContinueResponse(continueResponse);
final ChannelFuture future = ctx.writeAndFlush(continueResponse).addListener(listener);
Future<Void> future = ctx.writeAndFlush(continueResponse).addListener(ctx, listener);
if (closeAfterWrite) {
future.addListener(ChannelFutureListener.CLOSE);
future.addListener(ctx.channel(), ChannelFutureListeners.CLOSE);
return;
}
if (handlingOversizedMessage) {

View File

@ -21,8 +21,8 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.TypeParameterMatcher;
@ -96,7 +96,7 @@ public abstract class MessageToByteEncoder<I> extends ChannelHandlerAdapter {
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
ByteBuf buf = null;
try {
if (acceptOutboundMessage(msg)) {

View File

@ -17,8 +17,8 @@ package io.netty.handler.codec;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCounted;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.TypeParameterMatcher;
import java.util.List;
@ -112,7 +112,7 @@ public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN> extends Cha
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
encoder.write(ctx, msg, promise);
}

View File

@ -19,9 +19,9 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.ReferenceCounted;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.PromiseCombiner;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.TypeParameterMatcher;
@ -78,7 +78,7 @@ public abstract class MessageToMessageEncoder<I> extends ChannelHandlerAdapter {
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
CodecOutputList out = null;
try {
if (acceptOutboundMessage(msg)) {
@ -118,7 +118,7 @@ public abstract class MessageToMessageEncoder<I> extends ChannelHandlerAdapter {
}
}
private static void writePromiseCombiner(ChannelHandlerContext ctx, CodecOutputList out, ChannelPromise promise) {
private static void writePromiseCombiner(ChannelHandlerContext ctx, CodecOutputList out, Promise<Void> promise) {
final PromiseCombiner combiner = new PromiseCombiner(ctx.executor());
for (int i = 0; i < out.size(); i++) {
combiner.add(ctx.write(out.getUnsafe(i)));

View File

@ -16,18 +16,22 @@
package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.PromiseNotifier;
import java.util.concurrent.TimeUnit;
import static io.netty.handler.codec.compression.Bzip2Constants.*;
import static io.netty.handler.codec.compression.Bzip2Constants.BASE_BLOCK_SIZE;
import static io.netty.handler.codec.compression.Bzip2Constants.END_OF_STREAM_MAGIC_1;
import static io.netty.handler.codec.compression.Bzip2Constants.END_OF_STREAM_MAGIC_2;
import static io.netty.handler.codec.compression.Bzip2Constants.MAGIC_NUMBER;
import static io.netty.handler.codec.compression.Bzip2Constants.MAX_BLOCK_SIZE;
import static io.netty.handler.codec.compression.Bzip2Constants.MIN_BLOCK_SIZE;
/**
* Compresses a {@link ByteBuf} using the Bzip2 algorithm.
@ -167,25 +171,25 @@ public class Bzip2Encoder extends MessageToByteEncoder<ByteBuf> {
/**
* Close this {@link Bzip2Encoder} and so finish the encoding.
*
* The returned {@link ChannelFuture} will be notified once the operation completes.
* The returned {@link Future} will be notified once the operation completes.
*/
public ChannelFuture close() {
public Future<Void> close() {
return close(ctx().newPromise());
}
/**
* Close this {@link Bzip2Encoder} and so finish the encoding.
* The given {@link ChannelFuture} will be notified once the operation
* The given {@link Future} will be notified once the operation
* completes and will also be returned.
*/
public ChannelFuture close(final ChannelPromise promise) {
public Future<Void> close(Promise<Void> promise) {
ChannelHandlerContext ctx = ctx();
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
return finishEncode(ctx, promise);
} else {
executor.execute(() -> {
ChannelFuture f = finishEncode(ctx(), promise);
Future<Void> f = finishEncode(ctx(), promise);
PromiseNotifier.cascade(f, promise);
});
return promise;
@ -193,9 +197,9 @@ public class Bzip2Encoder extends MessageToByteEncoder<ByteBuf> {
}
@Override
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) {
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
f.addListener((ChannelFutureListener) f1 -> ctx.close(promise));
public void close(final ChannelHandlerContext ctx, Promise<Void> promise) {
Future<Void> f = finishEncode(ctx, ctx.newPromise());
f.addListener(f1 -> ctx.close(promise));
if (!f.isDone()) {
// Ensure the channel is closed even if the write operation completes in time.
@ -205,9 +209,9 @@ public class Bzip2Encoder extends MessageToByteEncoder<ByteBuf> {
}
}
private ChannelFuture finishEncode(final ChannelHandlerContext ctx, ChannelPromise promise) {
private Future<Void> finishEncode(final ChannelHandlerContext ctx, Promise<Void> promise) {
if (finished) {
promise.setSuccess();
promise.setSuccess(null);
return promise;
}
finished = true;

View File

@ -15,14 +15,11 @@
*/
package io.netty.handler.codec.compression;
import static java.util.Objects.requireNonNull;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.PromiseNotifier;
import java.nio.ByteBuffer;
@ -30,6 +27,8 @@ import java.util.concurrent.TimeUnit;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import static java.util.Objects.requireNonNull;
/**
* Compresses a {@link ByteBuf} using the deflate algorithm.
*/
@ -156,20 +155,20 @@ public class JdkZlibEncoder extends ZlibEncoder {
}
@Override
public ChannelFuture close() {
public Future<Void> close() {
return close(ctx().newPromise());
}
@Override
public ChannelFuture close(final ChannelPromise promise) {
public Future<Void> close(Promise<Void> promise) {
ChannelHandlerContext ctx = ctx();
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
return finishEncode(ctx, promise);
} else {
final ChannelPromise p = ctx.newPromise();
Promise<Void> p = ctx.newPromise();
executor.execute(() -> {
ChannelFuture f = finishEncode(ctx(), p);
Future<Void> f = finishEncode(ctx(), p);
PromiseNotifier.cascade(f, promise);
});
return p;
@ -262,9 +261,9 @@ public class JdkZlibEncoder extends ZlibEncoder {
}
@Override
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) {
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
f.addListener((ChannelFutureListener) f1 -> ctx.close(promise));
public void close(final ChannelHandlerContext ctx, Promise<Void> promise) {
Future<Void> f = finishEncode(ctx, ctx.newPromise());
f.addListener(f1 -> ctx.close(promise));
if (!f.isDone()) {
// Ensure the channel is closed even if the write operation completes in time.
@ -274,9 +273,9 @@ public class JdkZlibEncoder extends ZlibEncoder {
}
}
private ChannelFuture finishEncode(final ChannelHandlerContext ctx, ChannelPromise promise) {
private Future<Void> finishEncode(final ChannelHandlerContext ctx, Promise<Void> promise) {
if (finished) {
promise.setSuccess();
promise.setSuccess(null);
return promise;
}

View File

@ -18,14 +18,13 @@ package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.EncoderException;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.PromiseNotifier;
import io.netty.util.internal.ObjectUtil;
import net.jpountz.lz4.LZ4Compressor;
@ -49,7 +48,6 @@ import static io.netty.handler.codec.compression.Lz4Constants.MAGIC_NUMBER;
import static io.netty.handler.codec.compression.Lz4Constants.MAX_BLOCK_SIZE;
import static io.netty.handler.codec.compression.Lz4Constants.MIN_BLOCK_SIZE;
import static io.netty.handler.codec.compression.Lz4Constants.TOKEN_OFFSET;
import static java.util.Objects.requireNonNull;
/**
@ -306,9 +304,9 @@ public class Lz4FrameEncoder extends MessageToByteEncoder<ByteBuf> {
ctx.flush();
}
private ChannelFuture finishEncode(final ChannelHandlerContext ctx, ChannelPromise promise) {
private Future<Void> finishEncode(final ChannelHandlerContext ctx, Promise<Void> promise) {
if (finished) {
promise.setSuccess();
promise.setSuccess(null);
return promise;
}
finished = true;
@ -340,25 +338,25 @@ public class Lz4FrameEncoder extends MessageToByteEncoder<ByteBuf> {
/**
* Close this {@link Lz4FrameEncoder} and so finish the encoding.
*
* The returned {@link ChannelFuture} will be notified once the operation completes.
* The returned {@link java.util.concurrent.Future} will be notified once the operation completes.
*/
public ChannelFuture close() {
public Future<Void> close() {
return close(ctx().newPromise());
}
/**
* Close this {@link Lz4FrameEncoder} and so finish the encoding.
* The given {@link ChannelFuture} will be notified once the operation
* The given {@link java.util.concurrent.Future} will be notified once the operation
* completes and will also be returned.
*/
public ChannelFuture close(final ChannelPromise promise) {
public Future<Void> close(Promise<Void> promise) {
ChannelHandlerContext ctx = ctx();
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
return finishEncode(ctx, promise);
} else {
executor.execute(() -> {
ChannelFuture f = finishEncode(ctx(), promise);
Future<Void> f = finishEncode(ctx(), promise);
PromiseNotifier.cascade(f, promise);
});
return promise;
@ -366,9 +364,9 @@ public class Lz4FrameEncoder extends MessageToByteEncoder<ByteBuf> {
}
@Override
public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) {
ChannelFuture f = finishEncode(ctx, ctx.newPromise());
f.addListener((ChannelFutureListener) f1 -> ctx.close(promise));
public void close(final ChannelHandlerContext ctx, Promise<Void> promise) {
Future<Void> f = finishEncode(ctx, ctx.newPromise());
f.addListener(f1 -> ctx.close(promise));
if (!f.isDone()) {
// Ensure the channel is closed even if the write operation completes in time.

View File

@ -16,9 +16,9 @@
package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
/**
* Compresses a {@link ByteBuf} using the deflate algorithm.
@ -42,16 +42,16 @@ public abstract class ZlibEncoder extends MessageToByteEncoder<ByteBuf> {
/**
* Close this {@link ZlibEncoder} and so finish the encoding.
*
* The returned {@link ChannelFuture} will be notified once the
* The returned {@link Future} will be notified once the
* operation completes.
*/
public abstract ChannelFuture close();
public abstract Future<Void> close();
/**
* Close this {@link ZlibEncoder} and so finish the encoding.
* The given {@link ChannelFuture} will be notified once the operation
* The given {@link Future} will be notified once the operation
* completes and will also be returned.
*/
public abstract ChannelFuture close(ChannelPromise promise);
public abstract Future<Void> close(Promise<Void> promise);
}

View File

@ -15,19 +15,19 @@
*/
package io.netty.handler.codec;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
public class MessageToMessageEncoderTest {
/**
@ -59,7 +59,7 @@ public class MessageToMessageEncoderTest {
ChannelHandler writeThrower = new ChannelHandler() {
private boolean firstWritten;
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
public void write(ChannelHandlerContext ctx, Object msg, Promise<Void> promise) {
if (firstWritten) {
ctx.write(msg, promise);
} else {
@ -71,7 +71,7 @@ public class MessageToMessageEncoderTest {
EmbeddedChannel channel = new EmbeddedChannel(writeThrower, encoder);
Object msg = new Object();
ChannelFuture write = channel.writeAndFlush(msg);
Future<Void> write = channel.writeAndFlush(msg);
assertSame(firstWriteException, write.cause());
assertSame(msg, channel.readOutbound());
assertFalse(channel.finish());

View File

@ -22,7 +22,6 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
@ -278,13 +277,13 @@ public class Lz4FrameEncoderTest extends AbstractEncoderTest {
final int size = 27;
ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(size, size);
finalClientChannel.writeAndFlush(buf.writerIndex(buf.writerIndex() + size))
.addListener((ChannelFutureListener) future -> {
try {
writeFailCauseRef.set(future.cause());
} finally {
latch.countDown();
}
});
.addListener(future -> {
try {
writeFailCauseRef.set(future.cause());
} finally {
latch.countDown();
}
});
});
latch.await();
Throwable writeFailCause = writeFailCauseRef.get();

View File

@ -82,12 +82,12 @@ public abstract class AbstractEventExecutor extends AbstractExecutorService impl
@Override
public <V> Future<V> newSucceededFuture(V result) {
return new SucceededFuture<>(this, result);
return DefaultPromise.newSuccessfulPromise(this, result);
}
@Override
public <V> Future<V> newFailedFuture(Throwable cause) {
return new FailedFuture<>(this, cause);
return DefaultPromise.newFailedPromise(this, cause);
}
@Override
@ -107,12 +107,12 @@ public abstract class AbstractEventExecutor extends AbstractExecutorService impl
@Override
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return newRunnableFuture(this.newPromise(), runnable, value);
return newRunnableFuture(newPromise(), runnable, value);
}
@Override
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return newRunnableFuture(this.newPromise(), callable);
return newRunnableFuture(newPromise(), callable);
}
/**

View File

@ -38,6 +38,8 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
private static final Comparator<RunnableScheduledFutureNode<?>> SCHEDULED_FUTURE_TASK_COMPARATOR =
Comparable::compareTo;
private static final RunnableScheduledFutureNode<?>[]
EMPTY_RUNNABLE_SCHEDULED_FUTURE_NODES = new RunnableScheduledFutureNode<?>[0];
private PriorityQueue<RunnableScheduledFutureNode<?>> scheduledTaskQueue;
@ -88,7 +90,7 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
}
final RunnableScheduledFutureNode<?>[] scheduledTasks =
scheduledTaskQueue.toArray(new RunnableScheduledFutureNode<?>[0]);
scheduledTaskQueue.toArray(EMPTY_RUNNABLE_SCHEDULED_FUTURE_NODES);
for (RunnableScheduledFutureNode<?> task: scheduledTasks) {
task.cancel(false);
@ -145,11 +147,7 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
if (scheduledTaskQueue == null) {
return null;
}
RunnableScheduledFutureNode<?> node = scheduledTaskQueue.peek();
if (node == null) {
return null;
}
return node;
return scheduledTaskQueue.peek();
}
/**
@ -236,9 +234,9 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
}
private <V> void add0(RunnableScheduledFuture<V> task) {
final RunnableScheduledFutureNode node;
final RunnableScheduledFutureNode<V> node;
if (task instanceof RunnableScheduledFutureNode) {
node = (RunnableScheduledFutureNode) task;
node = (RunnableScheduledFutureNode<V>) task;
} else {
node = new DefaultRunnableScheduledFutureNode<V>(task);
}
@ -270,7 +268,7 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
*/
protected <V> RunnableScheduledFuture<V> newScheduledTaskFor(
Callable<V> callable, long deadlineNanos, long period) {
return newRunnableScheduledFuture(this, this.newPromise(), callable, deadlineNanos, period);
return newRunnableScheduledFuture(this, newPromise(), callable, deadlineNanos, period);
}
interface RunnableScheduledFutureNode<V> extends PriorityQueueNode, RunnableScheduledFuture<V> { }
@ -304,12 +302,18 @@ public abstract class AbstractScheduledEventExecutor extends AbstractEventExecut
}
@Override
public RunnableScheduledFuture<V> addListener(
GenericFutureListener<? extends Future<? super V>> listener) {
public RunnableScheduledFuture<V> addListener(FutureListener<? super V> listener) {
future.addListener(listener);
return this;
}
@Override
public <C> RunnableScheduledFuture<V> addListener(C context,
FutureContextListener<? super C, ? super V> listener) {
future.addListener(context, listener);
return this;
}
@Override
public boolean isPeriodic() {
return future.isPeriodic();

View File

@ -1,140 +0,0 @@
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you 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:
*
* https://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 io.netty.util.concurrent;
import static java.util.Objects.requireNonNull;
import java.util.concurrent.TimeUnit;
/**
* A skeletal {@link Future} implementation which represents a {@link Future} which has been completed already.
*/
public abstract class CompleteFuture<V> implements Future<V> {
private final EventExecutor executor;
// It is fine to not make this volatile as even if we override the value in there it does not matter as
// DefaultFutureCompletionStage has no state itself and is just a wrapper around this CompletableFuture instance.
private DefaultFutureCompletionStage<V> stage;
/**
* Creates a new instance.
*
* @param executor the {@link EventExecutor} associated with this future
*/
protected CompleteFuture(EventExecutor executor) {
this.executor = executor;
}
/**
* Return the {@link EventExecutor} which is used by this {@link CompleteFuture}.
*/
@Override
public EventExecutor executor() {
return executor;
}
@Override
public Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
requireNonNull(listener, "listener");
DefaultPromise.safeExecute(executor(), () -> DefaultPromise.notifyListener0(this, listener));
return this;
}
@Override
public Future<V> await() throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
return this;
}
@Override
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
return true;
}
@Override
public Future<V> sync() throws InterruptedException {
return this;
}
@Override
public Future<V> syncUninterruptibly() {
return this;
}
@Override
public boolean await(long timeoutMillis) throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
return true;
}
@Override
public Future<V> awaitUninterruptibly() {
return this;
}
@Override
public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
return true;
}
@Override
public boolean awaitUninterruptibly(long timeoutMillis) {
return true;
}
@Override
public boolean isDone() {
return true;
}
@Override
public boolean isCancellable() {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
/**
* {@inheritDoc}
*
* @param mayInterruptIfRunning this value has no effect in this implementation.
*/
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public FutureCompletionStage<V> asStage() {
DefaultFutureCompletionStage<V> stageAdapter = stage;
if (stageAdapter == null) {
stage = stageAdapter = new DefaultFutureCompletionStage<>(this);
}
return stageAdapter;
}
}

View File

@ -28,7 +28,7 @@ import java.util.function.Function;
import static java.util.Objects.requireNonNull;
/**
* Wraps a {@link io.netty.util.concurrent.Future} and provides a {@link FutureCompletionStage} implementation
* Wraps a {@link Future} and provides a {@link FutureCompletionStage} implementation
* on top of it.
*
* @param <V> the value type.
@ -41,7 +41,7 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
// Just a marker
private static final Executor SAME_AS_FUTURE = task -> {
throw new UnsupportedOperationException("Only a marker, should never been called!");
throw new UnsupportedOperationException("Marker executor. Should never be called!");
};
private final Future<V> future;
@ -191,7 +191,7 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
future.addListener(future -> {
Throwable cause = future.cause();
if (cause == null) {
@SuppressWarnings("unchecked") V value = (V) future.getNow();
V value = future.getNow();
if (executeDirectly(executor)) {
thenApplyAsync0(promise, value, fn);
} else {
@ -224,7 +224,7 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
future.addListener(future -> {
Throwable cause = future.cause();
if (cause == null) {
@SuppressWarnings("unchecked") V value = (V) future.getNow();
V value = future.getNow();
if (executeDirectly(executor)) {
thenAcceptAsync0(promise, value, action);
} else {
@ -333,6 +333,8 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
Promise<U> promise = executor().newPromise();
BiConsumer<V, Throwable> consumer = new AtomicBiConsumer<V, U>(promise) {
private static final long serialVersionUID = -8454630185124276599L;
@Override
protected U apply(V value) {
return fn.apply(value);
@ -351,6 +353,8 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
Promise<Void> promise = executor().newPromise();
BiConsumer<V, Throwable> consumer = new AtomicBiConsumer<V, Void>(promise) {
private static final long serialVersionUID = -8429618092318150682L;
@Override
protected Void apply(V value) {
action.accept(value);
@ -370,6 +374,8 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
Promise<Void> promise = executor().newPromise();
BiConsumer<Object, Throwable> consumer = new AtomicBiConsumer<Object, Void>(promise) {
private static final long serialVersionUID = 5994110691767731494L;
@Override
protected Void apply(Object value) {
action.run();
@ -391,7 +397,7 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
future.addListener(f -> {
Throwable cause = f.cause();
if (cause == null) {
@SuppressWarnings("unchecked") V value = (V) f.getNow();
V value = f.getNow();
if (executeDirectly(executor)) {
thenComposeAsync0(promise, fn, value);
} else {
@ -430,7 +436,7 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
future.addListener(f -> {
Throwable error = f.cause();
if (error == null) {
@SuppressWarnings("unchecked") V value = (V) f.getNow();
V value = f.getNow();
promise.setSuccess(value);
} else {
final V result;
@ -464,10 +470,9 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
}
private static <V> void whenCompleteAsync0(
Promise<V> promise, Future<? super V> f, BiConsumer<? super V, ? super Throwable> action) {
Promise<V> promise, Future<? extends V> f, BiConsumer<? super V, ? super Throwable> action) {
Throwable cause = f.cause();
@SuppressWarnings("unchecked") V value = cause == null ? (V) f.getNow() : null;
V value = cause == null ? f.getNow() : null;
try {
action.accept(value, cause);
} catch (Throwable error) {
@ -532,6 +537,7 @@ final class DefaultFutureCompletionStage<V> implements FutureCompletionStage<V>
private abstract static class AtomicBiConsumer<V, U> extends AtomicReference<Object>
implements BiConsumer<V, Throwable> {
private static final long serialVersionUID = 880039612531973027L;
private final Promise<U> promise;

View File

@ -15,53 +15,77 @@
*/
package io.netty.util.concurrent;
import io.netty.util.internal.logging.InternalLogger;
import java.util.Arrays;
import java.util.EventListener;
final class DefaultFutureListeners {
private GenericFutureListener<? extends Future<?>>[] listeners;
private Object[] listeners;
private int size;
@SuppressWarnings("unchecked")
DefaultFutureListeners(
GenericFutureListener<? extends Future<?>> first, GenericFutureListener<? extends Future<?>> second) {
listeners = new GenericFutureListener[2];
listeners[0] = first;
listeners[1] = second;
size = 2;
DefaultFutureListeners() {
listeners = new Object[4];
}
public void add(GenericFutureListener<? extends Future<?>> l) {
GenericFutureListener<? extends Future<?>>[] listeners = this.listeners;
final int size = this.size;
if (size == listeners.length) {
this.listeners = listeners = Arrays.copyOf(listeners, size << 1);
public void add(Object listener, Object context) {
Object[] listeners = this.listeners;
int index = size << 1;
if (index == listeners.length) {
this.listeners = listeners = Arrays.copyOf(listeners, listeners.length << 1);
}
listeners[size] = l;
this.size = size + 1;
listeners[index] = listener;
listeners[index + 1] = context;
size++;
}
public void remove(GenericFutureListener<? extends Future<?>> l) {
final GenericFutureListener<? extends Future<?>>[] listeners = this.listeners;
int size = this.size;
for (int i = 0; i < size; i ++) {
if (listeners[i] == l) {
int listenersToMove = size - i - 1;
public void remove(EventListener listener) {
final Object[] listeners = this.listeners;
for (int i = 0, len = listeners.length; i < len; i += 2) {
Object candidateListener = listeners[i]; // With associated context at listeners[i + 1]
if (candidateListener == listener) {
int listenersToMove = len - i - 2;
if (listenersToMove > 0) {
System.arraycopy(listeners, i + 1, listeners, i, listenersToMove);
System.arraycopy(listeners, i + 2, listeners, i, listenersToMove);
}
listeners[-- size] = null;
this.size = size;
listeners[len - 2] = null;
listeners[len - 1] = null;
size--;
return;
}
}
}
public GenericFutureListener<? extends Future<?>>[] listeners() {
return listeners;
}
public int size() {
return size;
@SuppressWarnings("unchecked")
public <V> void notifyListeners(DefaultPromise<V> promise, InternalLogger logger) {
int size = this.size;
Object[] listeners = this.listeners;
for (int i = 0, len = size << 1; i < len; i += 2) {
Object listener = listeners[i];
Object context = listeners[i + 1];
try {
// Since a listener could in theory be both a FutureListener and a FutureContextListener,
// we use the presence of a context object to determine which one was meant when the listener
// was added. The context reference will never be null if the FutureContextListener was intended,
// even if the context passed was null. In that case, the reference will point to the
// NULL_CONTEXT, and we have to convert it back to null here.
if (context != null) {
FutureContextListener<Object, V> fcl = (FutureContextListener<Object, V>) listener;
fcl.operationComplete(context == DefaultPromise.NULL_CONTEXT ? null : context, promise);
} else if (listener instanceof FutureListener) {
FutureListener<V> fl = (FutureListener<V>) listener;
fl.operationComplete(promise);
} else if (listener != null) {
logger.warn("Unknown future listener type: {} of type {}", listener, listener.getClass());
} else {
break; // Listeners are always densely packed in the array, so finding a null means we're done.
}
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
String className = listener.getClass().getName();
logger.warn("An exception was thrown by " + className + ".operationComplete()", t);
}
}
}
}
}

View File

@ -42,6 +42,7 @@ public class DefaultPromise<V> implements Promise<V> {
private static final CauseHolder CANCELLATION_CAUSE_HOLDER = new CauseHolder(
StacklessCancellationException.newInstance(DefaultPromise.class, "cancel(...)"));
private static final StackTraceElement[] CANCELLATION_STACK = CANCELLATION_CAUSE_HOLDER.cause.getStackTrace();
static final Object NULL_CONTEXT = new Object();
private volatile Object result;
private final EventExecutor executor;
@ -51,9 +52,12 @@ public class DefaultPromise<V> implements Promise<V> {
private DefaultFutureCompletionStage<V> stage;
/**
* One or more listeners. Can be a {@link GenericFutureListener} or a {@link DefaultFutureListeners}.
* One or more listeners. Can be a {@link FutureListener} or a {@link DefaultFutureListeners}.
* If {@code null}, it means either 1) no listeners were added yet or 2) all listeners were notified.
*
* <p>
* Note that if a {@link FutureContextListener} is added, we immediately upgrade to a {@link DefaultFutureListeners}
* as we otherwise wouldn't have room to store the associated context object.
* <p>
* Threading - synchronized(this). We must support adding listeners when there is no EventExecutor.
*/
private Object listeners;
@ -63,22 +67,61 @@ public class DefaultPromise<V> implements Promise<V> {
private short waiters;
/**
* Creates a new instance.
* Creates a new unfulfilled promise.
*
* It is preferable to use {@link EventExecutor#newPromise()} to create a new promise
*
* @param executor
* the {@link EventExecutor} which is used to notify the promise once it is complete.
* The {@link EventExecutor} which is used to notify the promise once it is complete.
* It is assumed this executor will protect against {@link StackOverflowError} exceptions.
* The executor may be used to avoid {@link StackOverflowError} by executing a {@link Runnable} if the stack
* depth exceeds a threshold.
*
*/
public DefaultPromise(EventExecutor executor) {
this.executor = requireNonNull(executor, "executor");
stage = new DefaultFutureCompletionStage<>(this);
}
/**
* Creates a new promise that has already been completed successfully.
*
* @param executor
* The {@link EventExecutor} which is used to notify the promise once it is complete.
* It is assumed this executor will protect against {@link StackOverflowError} exceptions.
* The executor may be used to avoid {@link StackOverflowError} by executing a {@link Runnable} if the stack
* depth exceeds a threshold.
* @param result The result of the successful promise.
*/
public static <V> Promise<V> newSuccessfulPromise(EventExecutor executor, V result) {
return new DefaultPromise<>(executor, result);
}
/**
* Creates a new promise that has already failed.
*
* @param executor
* The {@link EventExecutor} which is used to notify the promise once it is complete.
* It is assumed this executor will protect against {@link StackOverflowError} exceptions.
* The executor may be used to avoid {@link StackOverflowError} by executing a {@link Runnable} if the stack
* depth exceeds a threshold.
* @param cause The {@link Throwable} that caused the failure of the returned promise.
*/
public static <V> Promise<V> newFailedPromise(EventExecutor executor, Throwable cause) {
return new DefaultPromise<>(cause, executor);
}
private DefaultPromise(EventExecutor executor, Object result) {
this.executor = requireNonNull(executor, "executor");
this.result = result == null? SUCCESS : result;
stage = new DefaultFutureCompletionStage<>(this);
}
private DefaultPromise(Throwable cause, EventExecutor executor) {
this.executor = requireNonNull(executor, "executor");
result = new CauseHolder(requireNonNull(cause, "cause"));
stage = new DefaultFutureCompletionStage<>(this);
}
@Override
public Promise<V> setSuccess(V result) {
if (setSuccess0(result)) {
@ -161,13 +204,10 @@ public class DefaultPromise<V> implements Promise<V> {
}
@Override
public Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
public Promise<V> addListener(FutureListener<? super V> listener) {
requireNonNull(listener, "listener");
synchronized (this) {
addListener0(listener);
}
addListener0(listener, null);
if (isDone()) {
notifyListeners();
}
@ -176,7 +216,19 @@ public class DefaultPromise<V> implements Promise<V> {
}
@Override
public Promise<V> await() throws InterruptedException {
public <C> Promise<V> addListener(C context, FutureContextListener<? super C, ? super V> listener) {
requireNonNull(listener, "listener");
addListener0(listener, context == null ? NULL_CONTEXT : context);
if (isDone()) {
notifyListeners();
}
return this;
}
@Override
public Future<V> await() throws InterruptedException {
if (isDone()) {
return this;
}
@ -201,7 +253,7 @@ public class DefaultPromise<V> implements Promise<V> {
}
@Override
public Promise<V> awaitUninterruptibly() {
public Future<V> awaitUninterruptibly() {
if (isDone()) {
return this;
}
@ -339,14 +391,14 @@ public class DefaultPromise<V> implements Promise<V> {
}
@Override
public Promise<V> sync() throws InterruptedException {
public Future<V> sync() throws InterruptedException {
await();
rethrowIfFailed();
return this;
}
@Override
public Promise<V> syncUninterruptibly() {
public Future<V> syncUninterruptibly() {
awaitUninterruptibly();
rethrowIfFailed();
return this;
@ -410,6 +462,7 @@ public class DefaultPromise<V> implements Promise<V> {
safeExecute(executor(), this::notifyListenersNow);
}
@SuppressWarnings("unchecked")
private void notifyListenersNow() {
Object listeners;
synchronized (this) {
@ -424,7 +477,7 @@ public class DefaultPromise<V> implements Promise<V> {
if (listeners instanceof DefaultFutureListeners) {
notifyListeners0((DefaultFutureListeners) listeners);
} else {
notifyListener0(this, (GenericFutureListener<?>) listeners);
notifyListener0(this, (FutureListener<V>) listeners);
}
synchronized (this) {
if (this.listeners == null) {
@ -437,15 +490,10 @@ public class DefaultPromise<V> implements Promise<V> {
}
private void notifyListeners0(DefaultFutureListeners listeners) {
GenericFutureListener<?>[] a = listeners.listeners();
int size = listeners.size();
for (int i = 0; i < size; i ++) {
notifyListener0(this, a[i]);
}
listeners.notifyListeners(this, logger);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
static void notifyListener0(Future future, GenericFutureListener l) {
static <V> void notifyListener0(Future<V> future, FutureListener<? super V> l) {
try {
l.operationComplete(future);
} catch (Throwable t) {
@ -455,13 +503,18 @@ public class DefaultPromise<V> implements Promise<V> {
}
}
private void addListener0(GenericFutureListener<? extends Future<? super V>> listener) {
if (listeners == null) {
private synchronized void addListener0(Object listener, Object context) {
if (listeners == null && context == null) {
listeners = listener;
} else if (listeners instanceof DefaultFutureListeners) {
((DefaultFutureListeners) listeners).add(listener);
((DefaultFutureListeners) listeners).add(listener, context);
} else {
listeners = new DefaultFutureListeners((GenericFutureListener<?>) listeners, listener);
DefaultFutureListeners listeners = new DefaultFutureListeners();
if (this.listeners != null) {
listeners.add(this.listeners, null);
}
listeners.add(listener, context);
this.listeners = listeners;
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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:
*
* https://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 io.netty.util.concurrent;
import io.netty.util.internal.PlatformDependent;
import static java.util.Objects.requireNonNull;
/**
* The {@link CompleteFuture} which is failed already. It is
* recommended to use {@link EventExecutor#newFailedFuture(Throwable)}
* instead of calling the constructor of this future.
*/
public final class FailedFuture<V> extends CompleteFuture<V> {
private final Throwable cause;
/**
* Creates a new instance.
*
* @param executor the {@link EventExecutor} associated with this future
* @param cause the cause of failure
*/
public FailedFuture(EventExecutor executor, Throwable cause) {
super(executor);
requireNonNull(cause, "cause");
this.cause = cause;
}
@Override
public Throwable cause() {
return cause;
}
@Override
public boolean isSuccess() {
return false;
}
@Override
public Future<V> sync() {
PlatformDependent.throwException(cause);
return this;
}
@Override
public Future<V> syncUninterruptibly() {
PlatformDependent.throwException(cause);
return this;
}
@Override
public V getNow() {
return null;
}
}

View File

@ -23,10 +23,150 @@ import java.util.concurrent.TimeoutException;
/**
* The result of an asynchronous operation.
* <p>
* An asynchronous operation is one that might be completed outside a given
* thread of execution. The operation can either be performing computation,
* or I/O, or both.
* <p>
* All I/O operations in Netty are asynchronous. It means any I/O calls will
* return immediately with no guarantee that the requested I/O operation has
* been completed at the end of the call. Instead, you will be returned with
* a {@link Future} instance which gives you the information about the
* result or status of the I/O operation.
* <p>
* A {@link Future} is either <em>uncompleted</em> or <em>completed</em>.
* When an I/O operation begins, a new future object is created. The new future
* is uncompleted initially - it is neither succeeded, failed, nor cancelled
* because the I/O operation is not finished yet. If the I/O operation is
* finished either successfully, with failure, or by cancellation, the future is
* marked as completed with more specific information, such as the cause of the
* failure. Please note that even failure and cancellation belong to the
* completed state.
* <pre>
* +---------------------------+
* | Completed successfully |
* +---------------------------+
* +----> isDone() = true |
* +--------------------------+ | | isSuccess() = true |
* | Uncompleted | | +===========================+
* +--------------------------+ | | Completed with failure |
* | isDone() = false | | +---------------------------+
* | isSuccess() = false |----+----> isDone() = true |
* | isCancelled() = false | | | cause() = non-null |
* | cause() = null | | +===========================+
* +--------------------------+ | | Completed by cancellation |
* | +---------------------------+
* +----> isDone() = true |
* | isCancelled() = true |
* +---------------------------+
* </pre>
*
* Various methods are provided to let you check if the I/O operation has been
* completed, wait for the completion, and retrieve the result of the I/O
* operation. It also allows you to add {@link FutureListener}s so you
* can get notified when the I/O operation is completed.
*
* <h3>Prefer {@link #addListener(FutureListener)} to {@link #await()}</h3>
*
* It is recommended to prefer {@link #addListener(FutureListener)}, or
* {@link #addListener(Object, FutureContextListener)}, to {@link #await()}
* wherever possible to get notified when an I/O operation is done and to
* do any follow-up tasks.
* <p>
* The {@link #addListener(FutureListener)} method is non-blocking. It simply adds
* the specified {@link FutureListener} to the {@link Future}, and the I/O thread
* will notify the listeners when the I/O operation associated with the future is
* done. The {@link FutureListener} and {@link FutureContextListener} callbacks
* yield the best performance and resource utilization because it does not block at
* all, but it could be tricky to implement a sequential logic if you are not used to
* event-driven programming.
* <p>
* By contrast, {@link #await()} is a blocking operation. Once called, the
* caller thread blocks until the operation is done. It is easier to implement
* a sequential logic with {@link #await()}, but the caller thread blocks
* unnecessarily until the I/O operation is done and there's relatively
* expensive cost of inter-thread notification. Moreover, there's a chance of
* dead-lock in a particular circumstance, which is described below.
*
* <h3>Do not call {@link #await()} inside a {@link io.netty.channel.ChannelHandler}</h3>
* <p>
* The event handler methods in {@link io.netty.channel.ChannelHandler} are usually
* called by an I/O thread. If {@link #await()} is called by an event handler method,
* which is called by the I/O thread, the I/O operation it is waiting for might never
* complete because {@link #await()} can block the I/O operation it is waiting for,
* which is a dead-lock.
* <pre>
* // BAD - NEVER DO THIS
* {@code @Override}
* public void channelRead({@link io.netty.channel.ChannelHandlerContext} ctx, Object msg) {
* {@link Future} future = ctx.channel().close();
* future.awaitUninterruptibly();
* // Perform post-closure operation
* // ...
* }
*
* // GOOD
* {@code @Override}
* public void channelRead({@link io.netty.channel.ChannelHandlerContext} ctx, Object msg) {
* {@link Future} future = ctx.channel().close();
* future.addListener(new {@link FutureListener}() {
* public void operationComplete({@link Future} future) {
* // Perform post-closure operation
* // ...
* }
* });
* }
* </pre>
* <p>
* In spite of the disadvantages mentioned above, there are certainly the cases
* where it is more convenient to call {@link #await()}. In such a case, please
* make sure you do not call {@link #await()} in an I/O thread. Otherwise,
* {@link BlockingOperationException} will be raised to prevent a dead-lock.
*
* <h3>Do not confuse I/O timeout and await timeout</h3>
*
* The timeout value you specify with {@link #await(long)},
* {@link #await(long, TimeUnit)}, {@link #awaitUninterruptibly(long)}, or
* {@link #awaitUninterruptibly(long, TimeUnit)} are not related with I/O
* timeout at all. If an I/O operation times out, the future will be marked as
* 'completed with failure,' as depicted in the diagram above. For example,
* connect timeout should be configured via a transport-specific option:
* <pre>
* // BAD - NEVER DO THIS
* {@link io.netty.bootstrap.Bootstrap} b = ...;
* {@link Future} f = b.connect(...);
* f.awaitUninterruptibly(10, TimeUnit.SECONDS);
* if (f.isCancelled()) {
* // Connection attempt cancelled by user
* } else if (!f.isSuccess()) {
* // You might get a NullPointerException here because the future
* // might not be completed yet.
* f.cause().printStackTrace();
* } else {
* // Connection established successfully
* }
*
* // GOOD
* {@link io.netty.bootstrap.Bootstrap} b = ...;
* // Configure the connect timeout option.
* <b>b.option({@link io.netty.channel.ChannelOption}.CONNECT_TIMEOUT_MILLIS, 10000);</b>
* {@link Future} f = b.connect(...);
* f.awaitUninterruptibly();
*
* // Now we are sure the future is completed.
* assert f.isDone();
*
* if (f.isCancelled()) {
* // Connection attempt cancelled by user
* } else if (!f.isSuccess()) {
* f.cause().printStackTrace();
* } else {
* // Connection established successfully
* }
* </pre>
*/
@SuppressWarnings("ClassNameSameAsAncestorName")
public interface Future<V> extends java.util.concurrent.Future<V> {
/**
* Returns {@code true} if and only if the I/O operation was completed
* successfully.
@ -49,12 +189,27 @@ public interface Future<V> extends java.util.concurrent.Future<V> {
Throwable cause();
/**
* Adds the specified listener to this future. The
* specified listener is notified when this future is
* {@linkplain #isDone() done}. If this future is already
* completed, the specified listener is notified immediately.
* Adds the specified listener to this future.
* The specified listener is notified when this future is {@linkplain #isDone() done}.
* If this future is already completed, the specified listener is notified immediately.
*
* @param listener The listener to be called when this future completes.
* The listener will be passed this future as an argument.
* @return this future object.
*/
Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
Future<V> addListener(FutureListener<? super V> listener);
/**
* Adds the specified listener to this future.
* The specified listener is notified when this future is {@linkplain #isDone() done}.
* If this future is already completed, the specified listener is notified immediately.
*
* @param context The context object that will be passed to the listener when this future completes.
* @param listener The listener to be called when this future completes.
* The listener will be passed the given context, and this future.
* @return this future object.
*/
<C> Future<V> addListener(C context, FutureContextListener<? super C, ? super V> listener);
/**
* Waits for this future until it is done, and rethrows the cause of the failure if this future

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 The Netty Project
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -19,14 +19,18 @@ import java.util.EventListener;
/**
* Listens to the result of a {@link Future}. The result of the asynchronous operation is notified once this listener
* is added by calling {@link Future#addListener(GenericFutureListener)}.
* is added by calling {@link Future#addListener(Object, FutureContextListener)}.
* <pre>
* Future f = new DefaultPromise(..);
* f.addListener(context, (context, future) -> { .. });
* </pre>
*/
public interface GenericFutureListener<F extends Future<?>> extends EventListener {
@FunctionalInterface
public interface FutureContextListener<C, V> {
/**
* Invoked when the operation associated with the {@link Future} has been completed.
*
* @param future the source {@link Future} which called this callback
*/
void operationComplete(F future) throws Exception;
void operationComplete(C context, Future<? extends V> future) throws Exception;
}

View File

@ -16,13 +16,22 @@
package io.netty.util.concurrent;
import java.util.EventListener;
/**
* A subtype of {@link GenericFutureListener} that hides type parameter for convenience.
* Listens to the result of a {@link Future}. The result of the asynchronous operation is notified once this listener
* is added by calling {@link Future#addListener(FutureListener)}.
* <pre>
* Future f = new DefaultPromise(..);
* f.addListener(new FutureListener() {
* public void operationComplete(Future f) { .. }
* });
* f.addListener(future -> { .. });
* </pre>
*/
public interface FutureListener<V> extends GenericFutureListener<Future<V>> { }
@FunctionalInterface
public interface FutureListener<V> {
/**
* Invoked when the operation associated with the {@link Future} has been completed.
*
* @param future the source {@link Future} which called this callback
*/
void operationComplete(Future<? extends V> future) throws Exception;
}

View File

@ -67,7 +67,8 @@ public final class GlobalEventExecutor extends AbstractScheduledEventExecutor im
private final AtomicBoolean started = new AtomicBoolean();
volatile Thread thread;
private final Future<?> terminationFuture = new FailedFuture<>(this, new UnsupportedOperationException());
private final Future<?> terminationFuture = DefaultPromise.newFailedPromise(
this, new UnsupportedOperationException());
private GlobalEventExecutor() {
threadFactory = ThreadExecutorMap.apply(new DefaultThreadFactory(

View File

@ -54,7 +54,7 @@ public final class ImmediateEventExecutor extends AbstractEventExecutor {
}
};
private final Future<?> terminationFuture = new FailedFuture<>(
private final Future<?> terminationFuture = DefaultPromise.newFailedPromise(
GlobalEventExecutor.INSTANCE, new UnsupportedOperationException());
private ImmediateEventExecutor() { }

View File

@ -15,67 +15,53 @@
*/
package io.netty.util.concurrent;
import java.util.concurrent.CancellationException;
/**
* Special {@link Future} which is writable.
*/
public interface Promise<V> extends Future<V> {
/**
* Marks this future as a success and notifies all
* listeners.
*
* Marks this future as a success and notifies all listeners.
* <p>
* If it is success or failed already it will throw an {@link IllegalStateException}.
*/
Promise<V> setSuccess(V result);
/**
* Marks this future as a success and notifies all
* listeners.
* Marks this future as a success and notifies all listeners.
*
* @return {@code true} if and only if successfully marked this future as
* a success. Otherwise {@code false} because this future is
* already marked as either a success or a failure.
* @return {@code true} if and only if successfully marked this future as a success. Otherwise {@code false} because
* this future is already marked as either a success or a failure.
*/
boolean trySuccess(V result);
/**
* Marks this future as a failure and notifies all
* listeners.
*
* Marks this future as a failure and notifies all listeners.
* <p>
* If it is success or failed already it will throw an {@link IllegalStateException}.
*/
Promise<V> setFailure(Throwable cause);
/**
* Marks this future as a failure and notifies all
* listeners.
* Marks this future as a failure and notifies all listeners.
*
* @return {@code true} if and only if successfully marked this future as
* a failure. Otherwise {@code false} because this future is
* already marked as either a success or a failure.
* @return {@code true} if and only if successfully marked this future as a failure. Otherwise {@code false} because
* this future is already marked as either a success or a failure.
*/
boolean tryFailure(Throwable cause);
/**
* Make this future impossible to cancel.
*
* @return {@code true} if and only if successfully marked this future as uncancellable or it is already done
* without being cancelled. {@code false} if this future has been cancelled already.
* @return {@code true} if and only if successfully marked this future as uncancellable, or it is already done
* without being cancelled. Otherwise {@code false} if this future has been cancelled already.
*/
boolean setUncancellable();
@Override
Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
Promise<V> addListener(FutureListener<? super V> listener);
@Override
Promise<V> await() throws InterruptedException;
@Override
Promise<V> awaitUninterruptibly();
@Override
Promise<V> sync() throws InterruptedException;
@Override
Promise<V> syncUninterruptibly();
<C> Promise<V> addListener(C context, FutureContextListener<? super C, ? super V> listener);
}

View File

@ -38,7 +38,7 @@ public final class PromiseCombiner {
private int doneCount;
private Promise<Void> aggregatePromise;
private Throwable cause;
private final GenericFutureListener<Future<?>> listener = new GenericFutureListener<Future<?>>() {
private final FutureListener<Object> listener = new FutureListener<>() {
@Override
public void operationComplete(final Future<?> future) {
if (executor.inEventLoop()) {
@ -62,14 +62,6 @@ public final class PromiseCombiner {
private final EventExecutor executor;
/**
* Deprecated use {@link PromiseCombiner#PromiseCombiner(EventExecutor)}.
*/
@Deprecated
public PromiseCombiner() {
this(ImmediateEventExecutor.INSTANCE);
}
/**
* The {@link EventExecutor} to use for notifications. You must call {@link #add(Future)}, {@link #addAll(Future[])}
* and {@link #finish(Promise)} from within the {@link EventExecutor} thread.
@ -80,56 +72,28 @@ public final class PromiseCombiner {
this.executor = requireNonNull(executor, "executor");
}
/**
* Adds a new promise to be combined. New promises may be added until an aggregate promise is added via the
* {@link PromiseCombiner#finish(Promise)} method.
*
* @param promise the promise to add to this promise combiner
*
* @deprecated Replaced by {@link PromiseCombiner#add(Future)}.
*/
@Deprecated
public void add(Promise promise) {
add((Future) promise);
}
/**
* Adds a new future to be combined. New futures may be added until an aggregate promise is added via the
* {@link PromiseCombiner#finish(Promise)} method.
*
* @param future the future to add to this promise combiner
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public void add(Future future) {
public void add(Future<?> future) {
checkAddAllowed();
checkInEventLoop();
++expectedCount;
future.addListener(listener);
}
/**
* Adds new promises to be combined. New promises may be added until an aggregate promise is added via the
* {@link PromiseCombiner#finish(Promise)} method.
*
* @param promises the promises to add to this promise combiner
*
* @deprecated Replaced by {@link PromiseCombiner#addAll(Future[])}
*/
@Deprecated
public void addAll(Promise... promises) {
addAll((Future[]) promises);
}
/**
* Adds new futures to be combined. New futures may be added until an aggregate promise is added via the
* {@link PromiseCombiner#finish(Promise)} method.
*
* @param futures the futures to add to this promise combiner
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public void addAll(Future... futures) {
for (Future future : futures) {
this.add(future);
public void addAll(Future<?>... futures) {
for (Future<?> future : futures) {
add(future);
}
}
@ -163,7 +127,7 @@ public final class PromiseCombiner {
}
private boolean tryPromise() {
return (cause == null) ? aggregatePromise.trySuccess(null) : aggregatePromise.tryFailure(cause);
return cause == null? aggregatePromise.trySuccess(null) : aggregatePromise.tryFailure(cause);
}
private void checkAddAllowed() {

View File

@ -23,13 +23,12 @@ import static io.netty.util.internal.ObjectUtil.checkNotNullWithIAE;
import static java.util.Objects.requireNonNull;
/**
* {@link GenericFutureListener} implementation which takes other {@link Promise}s
* A {@link FutureListener} implementation which takes other {@link Promise}s
* and notifies them on completion.
*
* @param <V> the type of value returned by the future
* @param <F> the type of future
*/
public class PromiseNotifier<V, F extends Future<V>> implements GenericFutureListener<F> {
public class PromiseNotifier<V> implements FutureListener<V> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PromiseNotifier.class);
private final Promise<? super V>[] promises;
@ -38,7 +37,7 @@ public class PromiseNotifier<V, F extends Future<V>> implements GenericFutureLis
/**
* Create a new instance.
*
* @param promises the {@link Promise}s to notify once this {@link GenericFutureListener} is notified.
* @param promises the {@link Promise}s to notify once this {@link FutureListener} is notified.
*/
@SafeVarargs
public PromiseNotifier(Promise<? super V>... promises) {
@ -49,7 +48,7 @@ public class PromiseNotifier<V, F extends Future<V>> implements GenericFutureLis
* Create a new instance.
*
* @param logNotifyFailure {@code true} if logging should be done in case notification fails.
* @param promises the {@link Promise}s to notify once this {@link GenericFutureListener} is notified.
* @param promises the {@link Promise}s to notify once this {@link FutureListener} is notified.
*/
@SafeVarargs
public PromiseNotifier(boolean logNotifyFailure, Promise<? super V>... promises) {
@ -69,10 +68,9 @@ public class PromiseNotifier<V, F extends Future<V>> implements GenericFutureLis
* @param future the {@link Future} which will be used to listen to for notifying the {@link Promise}.
* @param promise the {@link Promise} which will be notified
* @param <V> the type of the value.
* @param <F> the type of the {@link Future}
* @return the passed in {@link Future}
*/
public static <V, F extends Future<V>> F cascade(final F future, final Promise<? super V> promise) {
public static <V> Future<V> cascade(final Future<V> future, final Promise<? super V> promise) {
return cascade(true, future, promise);
}
@ -85,29 +83,12 @@ public class PromiseNotifier<V, F extends Future<V>> implements GenericFutureLis
* @param future the {@link Future} which will be used to listen to for notifying the {@link Promise}.
* @param promise the {@link Promise} which will be notified
* @param <V> the type of the value.
* @param <F> the type of the {@link Future}
* @return the passed in {@link Future}
*/
public static <V, F extends Future<V>> F cascade(boolean logNotifyFailure, final F future,
public static <V> Future<V> cascade(boolean logNotifyFailure, final Future<V> future,
final Promise<? super V> promise) {
promise.addListener(new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> f) {
if (f.isCancelled()) {
future.cancel(false);
}
}
});
future.addListener(new PromiseNotifier<V, F>(logNotifyFailure, promise) {
@Override
public void operationComplete(F f) throws Exception {
if (promise.isCancelled() && f.isCancelled()) {
// Just return if we propagate a cancel from the promise to the future and both are notified already
return;
}
super.operationComplete(future);
}
});
promise.addListener(future, PromiseNotifier::propagateCancel);
future.addListener(new PromiseNotifier<V>(logNotifyFailure, promise), PromiseNotifier::propagateComplete);
return future;
}
@ -123,19 +104,12 @@ public class PromiseNotifier<V, F extends Future<V>> implements GenericFutureLis
* @param successResult the result that will be propagated to the promise on success
* @return the passed in {@link Future}
*/
public static <R, F extends Future<Void>> F cascade(boolean logNotifyFailure, F future,
public static <R> Future<Void> cascade(boolean logNotifyFailure, Future<Void> future,
Promise<R> promise, R successResult) {
promise.addListener(new FutureListener<Object>() {
promise.addListener(future, PromiseNotifier::propagateCancel);
future.addListener(new FutureListener<Void>() {
@Override
public void operationComplete(Future<Object> f) {
if (f.isCancelled()) {
future.cancel(false);
}
}
});
future.addListener(new GenericFutureListener<F>() {
@Override
public void operationComplete(F f) throws Exception {
public void operationComplete(Future<? extends Void> f) throws Exception {
if (promise.isCancelled() && f.isCancelled()) {
// Just return if we propagate a cancel from the promise to the future and both are notified already
return;
@ -157,8 +131,26 @@ public class PromiseNotifier<V, F extends Future<V>> implements GenericFutureLis
return future;
}
static <V, F extends Future<?>> void propagateCancel(F target, Future<? extends V> source) {
if (source.isCancelled()) {
target.cancel(false);
}
}
static <V> void propagateComplete(PromiseNotifier<V> target, Future<? extends V> source) throws Exception {
boolean allCancelled = target.promises.length > 0;
for (Promise<? super V> promise : target.promises) {
allCancelled &= promise.isCancelled();
}
if (allCancelled && source.isCancelled()) {
// Just return if we propagate a cancel from the promise to the future and both are notified already
return;
}
target.operationComplete(source);
}
@Override
public void operationComplete(F future) throws Exception {
public void operationComplete(Future<? extends V> future) throws Exception {
InternalLogger internalLogger = logNotifyFailure ? logger : null;
if (future.isSuccess()) {
V result = future.get();

View File

@ -112,10 +112,6 @@ class PromiseTask<V> extends DefaultPromise<V> implements RunnableFuture<V> {
return false;
}
protected final boolean trySuccessInternal(V result) {
return super.trySuccess(result);
}
@Override
public final boolean setUncancellable() {
throw new IllegalStateException();
@ -125,11 +121,6 @@ class PromiseTask<V> extends DefaultPromise<V> implements RunnableFuture<V> {
return super.setUncancellable();
}
@Override
public Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
return super.addListener(listener);
}
@Override
protected StringBuilder toStringBuilder() {
StringBuilder buf = super.toStringBuilder();

View File

@ -22,7 +22,10 @@ package io.netty.util.concurrent;
public interface RunnableFuture<V> extends java.util.concurrent.RunnableFuture<V>, Future<V> {
@Override
RunnableFuture<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
RunnableFuture<V> addListener(FutureListener<? super V> listener);
@Override
<C> RunnableFuture<V> addListener(C context, FutureContextListener<? super C, ? super V> listener);
@Override
RunnableFuture<V> sync() throws InterruptedException;

Some files were not shown because too many files have changed in this diff Show More