List of usage examples for io.netty.channel ChannelFuture addListener
@Override ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener);
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; }