Example usage for io.netty.channel ChannelFuture addListener

List of usage examples for io.netty.channel ChannelFuture addListener

Introduction

In this page you can find the example usage for io.netty.channel ChannelFuture addListener.

Prototype

@Override
    ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener);

Source Link

Usage

From source file:com.linecorp.armeria.client.HttpRemoteInvoker.java

License:Apache License

static <T> void invoke0(ClientCodec codec, Channel channel, Method method, Object[] args, ClientOptions options,
        Promise<T> resultPromise, PoolKey poolKey) {

    final HttpSession session = HttpSessionHandler.get(channel);
    final SessionProtocol sessionProtocol = session.protocol();
    if (sessionProtocol == null) {
        resultPromise.setFailure(ClosedSessionException.INSTANCE);
        return;/* w w w  .j  a  v a2s. c o  m*/
    }

    final EncodeResult encodeResult = codec.encodeRequest(channel, sessionProtocol, method, args);
    if (encodeResult.isSuccess()) {
        ServiceInvocationContext ctx = encodeResult.invocationContext();
        Promise<FullHttpResponse> responsePromise = channel.eventLoop().newPromise();

        final Invocation invocation = new Invocation(ctx, options, responsePromise, encodeResult.content());
        //write request
        final ChannelFuture writeFuture = writeRequest(channel, invocation, ctx, options);
        writeFuture.addListener(fut -> {
            if (!fut.isSuccess()) {
                ctx.rejectPromise(responsePromise, fut.cause());
            } else {
                long responseTimeoutMillis = options.responseTimeoutPolicy().timeout(ctx);
                scheduleTimeout(channel, responsePromise, responseTimeoutMillis, false);
            }
        });

        //handle response
        if (responsePromise.isSuccess()) {
            decodeResult(codec, resultPromise, ctx, responsePromise.getNow());
        } else {
            responsePromise.addListener((Future<FullHttpResponse> future) -> {
                if (future.isSuccess()) {
                    decodeResult(codec, resultPromise, ctx, responsePromise.getNow());
                } else {
                    ctx.rejectPromise(resultPromise, future.cause());
                }
            });
        }
    } else {
        final Throwable cause = encodeResult.cause();
        if (!resultPromise.tryFailure(cause)) {
            logger.warn("Failed to reject an invocation promise ({}) with {}", resultPromise, cause, cause);
        }
    }

    if (!session.onRequestSent()) {
        // Can't send a request via the current session anymore; do not return the channel to the pool.
        return;
    }

    // Return the channel to the pool.
    final KeyedChannelPool<PoolKey> pool = KeyedChannelPool.findPool(channel);
    if (sessionProtocol.isMultiplex()) {
        pool.release(poolKey, channel);
    } else {
        resultPromise.addListener(fut -> pool.release(poolKey, channel));
    }
}

From source file:com.linecorp.armeria.client.HttpRequestSubscriber.java

License:Apache License

private void write0(HttpObject o, boolean endOfStream, boolean flush) {
    final ChannelFuture future;
    if (o instanceof HttpData) {
        final HttpData data = (HttpData) o;
        future = encoder.writeData(ctx, id, streamId(), data, endOfStream);
        logBuilder.increaseRequestLength(data.length());
    } else if (o instanceof HttpHeaders) {
        future = encoder.writeHeaders(ctx, id, streamId(), (HttpHeaders) o, endOfStream);
    } else {/*from w  w  w .  j  a  v  a  2s .co m*/
        // Should never reach here because we did validation in onNext().
        throw new Error();
    }

    if (endOfStream) {
        logBuilder.endRequest();
    }

    future.addListener(this);
    if (flush) {
        ctx.flush();
    }

    if (state == State.DONE) {
        assert subscription != null;
        subscription.cancel();
    }
}

From source file:com.linecorp.armeria.internal.http.Http1ObjectEncoder.java

License:Apache License

@Override
protected ChannelFuture doWriteReset(ChannelHandlerContext ctx, int id, int streamId, Http2Error error) {
    // NB: this.minClosedId can be overwritten more than once when 3+ pipelined requests are received
    //     and they are handled by different threads simultaneously.
    //     e.g. when the 3rd request triggers a reset and then the 2nd one triggers another.
    minClosedId = Math.min(minClosedId, id);
    for (int i = minClosedId; i <= maxIdWithPendingWrites; i++) {
        final PendingWrites pendingWrites = this.pendingWrites.remove(i);
        for (;;) {
            final Entry<HttpObject, ChannelPromise> e = pendingWrites.poll();
            if (e == null) {
                break;
            }//from  ww  w .j a v a 2 s  .  c o  m
            e.getValue().tryFailure(ClosedSessionException.get());
        }
    }

    final ChannelFuture f = ctx.write(Unpooled.EMPTY_BUFFER);
    if (currentId >= minClosedId) {
        f.addListener(ChannelFutureListener.CLOSE);
    }

    return f;
}

From source file:com.linecorp.armeria.internal.Http1ObjectEncoder.java

License:Apache License

private ChannelFuture writeServerHeaders(ChannelHandlerContext ctx, int id, int streamId, HttpHeaders headers,
        boolean endStream) throws Http2Exception {

    final HttpObject converted = convertServerHeaders(streamId, headers, endStream);
    final HttpStatus status = headers.status();
    if (status == null) {
        // Trailing headers
        final ChannelFuture f = write(ctx, id, converted, endStream);
        ctx.flush();//from  ww  w  .  j av a2 s.com
        return f;
    }

    if (status.codeClass() == HttpStatusClass.INFORMATIONAL) {
        // Informational status headers.
        final ChannelFuture f = write(ctx, id, converted, false);
        if (endStream) {
            // Can't end a stream with informational status in HTTP/1.
            f.addListener(ChannelFutureListener.CLOSE);
        }
        ctx.flush();
        return f;
    }

    // Non-informational status headers.
    return writeNonInformationalHeaders(ctx, id, converted, endStream);
}

From source file:com.linecorp.armeria.internal.Http1ObjectEncoder.java

License:Apache License

@Override
protected ChannelFuture doWriteReset(ChannelHandlerContext ctx, int id, int streamId, Http2Error error) {
    // NB: this.minClosedId can be overwritten more than once when 3+ pipelined requests are received
    //     and they are handled by different threads simultaneously.
    //     e.g. when the 3rd request triggers a reset and then the 2nd one triggers another.
    minClosedId = Math.min(minClosedId, id);
    for (int i = minClosedId; i <= maxIdWithPendingWrites; i++) {
        final PendingWrites pendingWrites = pendingWritesMap.remove(i);
        for (;;) {
            final Entry<HttpObject, ChannelPromise> e = pendingWrites.poll();
            if (e == null) {
                break;
            }//from  ww  w .  j a  va2  s .  c  o m
            e.getValue().tryFailure(ClosedSessionException.get());
        }
    }

    final ChannelFuture f = ctx.write(Unpooled.EMPTY_BUFFER);
    if (currentId >= minClosedId) {
        f.addListener(ChannelFutureListener.CLOSE);
    }

    return f;
}

From source file:com.linecorp.armeria.server.http.Http1RequestDecoder.java

License:Apache License

private void fail(ChannelHandlerContext ctx, HttpResponseStatus status) {
    discarding = true;//from  ww  w  .j  a v  a 2s .c o  m
    req = null;

    final ChannelFuture future;
    if (receivedRequests <= sentResponses) {
        // Just close the connection if sending an error response will make the number of the sent
        // responses exceed the number of the received requests, which doesn't make sense.
        future = ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
    } else {
        final ByteBuf content = Unpooled.copiedBuffer(status.toString(), StandardCharsets.UTF_8);
        final FullHttpResponse res = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, content);

        final HttpHeaders headers = res.headers();
        headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
        headers.set(HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8);
        headers.setInt(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());

        future = ctx.writeAndFlush(res);
    }

    future.addListener(ChannelFutureListener.CLOSE);
}

From source file:com.linecorp.armeria.server.http.HttpResponseSubscriber.java

License:Apache License

private void write0(HttpObject o, boolean endOfStream, boolean flush) {
    final ChannelFuture future;
    if (o instanceof HttpData) {
        final HttpData data = (HttpData) o;
        future = responseEncoder.writeData(ctx, req.id(), req.streamId(), data, endOfStream);
        logBuilder.increaseContentLength(data.length());
    } else if (o instanceof HttpHeaders) {
        future = responseEncoder.writeHeaders(ctx, req.id(), req.streamId(), (HttpHeaders) o, endOfStream);
    } else {//  w w w  . j  av a 2s  . c  o m
        // Should never reach here because we did validation in onNext().
        throw new Error();
    }

    if (endOfStream) {
        logBuilder.end();
    }

    future.addListener(this);
    if (flush) {
        ctx.flush();
    }
}

From source file:com.linecorp.armeria.server.HttpResponseSubscriber.java

License:Apache License

private void write0(HttpObject o, boolean endOfStream) {
    final ChannelFuture future;
    final boolean wroteEmptyData;
    if (o instanceof HttpData) {
        final HttpData data = (HttpData) o;
        wroteEmptyData = data.isEmpty();
        future = responseEncoder.writeData(ctx, req.id(), req.streamId(), data, endOfStream);
        logBuilder().increaseResponseLength(data.length());
    } else if (o instanceof HttpHeaders) {
        wroteEmptyData = false;//from  w  w  w.ja va2 s  .  c o m
        future = responseEncoder.writeHeaders(ctx, req.id(), req.streamId(), (HttpHeaders) o, endOfStream);
    } else {
        // Should never reach here because we did validation in onNext().
        throw new Error();
    }

    future.addListener((ChannelFuture f) -> {
        final boolean isSuccess;
        if (f.isSuccess()) {
            isSuccess = true;
        } else {
            // If 1) the last chunk we attempted to send was empty,
            //    2) the connection has been closed,
            //    3) and the protocol is HTTP/1,
            // it is very likely that a client closed the connection after receiving the complete content,
            // which is not really a problem.
            isSuccess = endOfStream && wroteEmptyData && f.cause() instanceof ClosedChannelException
                    && responseEncoder instanceof Http1ObjectEncoder;
        }

        // Write an access log if:
        // - every message has been sent successfully.
        // - any write operation is failed with a cause.
        if (isSuccess) {
            if (endOfStream && tryComplete()) {
                logBuilder().endResponse();
                reqCtx.log().addListener(accessLogWriter::accept, RequestLogAvailability.COMPLETE);
            }
            if (state != State.DONE) {
                subscription.request(1);
            }
            return;
        }

        if (tryComplete()) {
            setDone();
            logBuilder().endResponse(f.cause());
            subscription.cancel();
            reqCtx.log().addListener(accessLogWriter::accept, RequestLogAvailability.COMPLETE);
        }
        HttpServerHandler.CLOSE_ON_FAILURE.operationComplete(f);
    });

    ctx.flush();
}

From source file:com.linecorp.armeria.server.HttpResponseSubscriber.java

License:Apache License

private void addCallbackAndFlush(Throwable cause, State oldState, ChannelFuture future) {
    if (oldState != State.DONE) {
        future.addListener(unused -> {
            // Write an access log always with a cause. Respect the first specified cause.
            if (tryComplete()) {
                logBuilder().endResponse(cause);
                reqCtx.log().addListener(accessLogWriter::accept, RequestLogAvailability.COMPLETE);
            }/* w  w w.j a  va 2 s.  co m*/
        });
    }
    ctx.flush();
}

From source file:com.linecorp.armeria.server.HttpServerHandler.java

License:Apache License

private ChannelFuture respond0(ChannelHandlerContext ctx, DecodedHttpRequest req, AggregatedHttpMessage res,
        RequestContext reqCtx, @Nullable Throwable cause) {

    // No need to consume further since the response is ready.
    req.close();/*from  w w  w.  jav  a 2 s . co m*/

    final boolean trailingHeadersEmpty = res.trailingHeaders().isEmpty();
    final boolean contentAndTrailingHeadersEmpty = res.content().isEmpty() && trailingHeadersEmpty;

    final RequestLogBuilder logBuilder = reqCtx.logBuilder();

    logBuilder.startResponse();
    assert responseEncoder != null;
    ChannelFuture future = responseEncoder.writeHeaders(ctx, req.id(), req.streamId(), res.headers(),
            contentAndTrailingHeadersEmpty);
    logBuilder.responseHeaders(res.headers());
    if (!contentAndTrailingHeadersEmpty) {
        future = responseEncoder.writeData(ctx, req.id(), req.streamId(), res.content(), trailingHeadersEmpty);
        logBuilder.increaseResponseLength(res.content().length());
        if (!trailingHeadersEmpty) {
            future = responseEncoder.writeHeaders(ctx, req.id(), req.streamId(), res.trailingHeaders(), true);
        }
    }

    future.addListener(f -> {
        if (cause == null && f.isSuccess()) {
            logBuilder.endResponse();
        } else {
            // Respect the first specified cause.
            logBuilder.endResponse(firstNonNull(cause, f.cause()));
        }
        reqCtx.log().addListener(accessLogWriter::accept, RequestLogAvailability.COMPLETE);
    });
    return future;
}