List of usage examples for io.netty.channel ChannelProgressiveFuture channel
Channel channel();
From source file:me.jesonlee.jjfsserver.httpserver.HttpStaticFileServerHandler.java
License:Apache License
@Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST);/*from w w w . j a v a 2 s .co m*/ return; } if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final String uri = request.getUri(); final String path = PathUtil.sanitizeUri(uri); if (path == null) { sendError(ctx, FORBIDDEN); return; } File file = new File(path); if (file.isHidden() || !file.exists()) { sendError(ctx, NOT_FOUND); return; } if (file.isDirectory()) { if (uri.endsWith("/")) { sendListing(ctx, file); } else { sendRedirect(ctx, uri + '/'); } return; } if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; } // Cache Validation String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client // does not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = file.lastModified() / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { sendNotModified(ctx); return; } } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND); return; } long fileLength = raf.length(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, fileLength); setContentTypeHeader(response, file); setDateAndCacheHeaders(response, file); if (HttpHeaders.isKeepAlive(request)) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture; ChannelFuture lastContentFuture; if (ctx.pipeline().get(SslHandler.class) == null) { sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); // Write the end marker. lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } else { sendFileFuture = ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()); // HttpChunkedInput will write the end marker (LastHttpContent) for us. lastContentFuture = sendFileFuture; } sendFileFuture.addListener(new ChannelProgressiveFutureListener() { @Override public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown System.err.println(future.channel() + " Transfer progress: " + progress); } else { System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) { System.err.println(future.channel() + " Transfer complete."); } }); // Decide whether to close the connection or not. if (!HttpHeaders.isKeepAlive(request)) { // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); } }
From source file:net.NettyEngine4.file.HttpStaticFileServerHandler.java
License:Apache License
/** * <strong>Please keep in mind that this method will be renamed to * {@code messageReceived(ChannelHandlerContext, I)} in 5.0.</strong> * <p/>/* www . java 2 s . c om*/ * Is called for each message of type {@link SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, Object)}. * * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler} * belongs to * @param request the message to handle * @throws Exception is thrown if an error occurred */ @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST); return; } if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final String uri = request.getUri(); final String path = sanitizeUri(uri); if (path == null) { sendError(ctx, FORBIDDEN); return; } File file = new File(path); if (file.isHidden() || !file.exists()) { sendError(ctx, NOT_FOUND); return; } if (file.isDirectory()) { if (uri.endsWith("/")) { sendListing(ctx, file); } else { sendRedirect(ctx, uri + '/'); } return; } if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; } // Cache Validation String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client // does not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = file.lastModified() / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { sendNotModified(ctx); return; } } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND); return; } long fileLength = raf.length(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, fileLength); setContentTypeHeader(response, file); setDateAndCacheHeaders(response, file); if (HttpHeaders.isKeepAlive(request)) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture; if (ctx.pipeline().get(SslHandler.class) == null) { sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); } else { sendFileFuture = ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()); } /** * */ sendFileFuture.addListener(new ChannelProgressiveFutureListener() { @Override public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown LOGGER.debug(future.channel() + " Transfer progress: " + progress); } else { LOGGER.debug(future.channel() + " Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) { LOGGER.debug(future.channel() + " Transfer complete."); } }); // Write the end marker ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); // Decide whether to close the connection or not. if (!HttpHeaders.isKeepAlive(request)) { // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); } }
From source file:Netty4.book.http.file.HttpStaticFileServerHandler.java
License:Apache License
@Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.decoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST);//w w w. j a v a 2 s . co m return; } if (request.method() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final String uri = request.uri(); final String path = sanitizeUri(uri); if (path == null) { sendError(ctx, FORBIDDEN); return; } File file = new File(path); if (file.isHidden() || !file.exists()) { sendError(ctx, NOT_FOUND); return; } if (file.isDirectory()) { if (uri.endsWith("/")) { sendListing(ctx, file); } else { sendRedirect(ctx, uri + '/'); } return; } if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; } // Cache Validation String ifModifiedSince = request.headers().get(HttpHeaderNames.IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client // does not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = file.lastModified() / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { sendNotModified(ctx); return; } } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND); return; } long fileLength = raf.length(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, fileLength); setContentTypeHeader(response, file); setDateAndCacheHeaders(response, file); if (HttpHeaders.isKeepAlive(request)) { response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture; ChannelFuture lastContentFuture; if (ctx.pipeline().get(SslHandler.class) == null) { sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); // Write the end marker. lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } else { sendFileFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()); // HttpChunkedInput will write the end marker (LastHttpContent) for us. lastContentFuture = sendFileFuture; } sendFileFuture.addListener(new ChannelProgressiveFutureListener() { public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown System.err.println(future.channel() + " Transfer progress: " + progress); } else { System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total); } } public void operationComplete(ChannelProgressiveFuture future) throws Exception { System.err.println(future.channel() + " Transfer complete."); } } ); // Decide whether to close the connection or not. if (!HttpUtil.isKeepAlive(request)) { // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); } }
From source file:org.asynchttpclient.netty.request.ProgressListener.java
License:Open Source License
@Override public void operationComplete(ChannelProgressiveFuture cf) { // The write operation failed. If the channel was cached, it means it got asynchronously closed. // Let's retry a second time. if (!abortOnThrowable(cf.cause(), cf.channel())) { future.touch();/*from w w w. j a va 2 s. c o m*/ /** * We need to make sure we aren't in the middle of an authorization * process before publishing events as we will re-publish again the * same event after the authorization, causing unpredictable * behavior. */ Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : config.getRealm(); boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { ProgressAsyncHandler<?> progressAsyncHandler = (ProgressAsyncHandler<?>) asyncHandler; if (notifyHeaders) { progressAsyncHandler.onHeadersWritten(); } else { progressAsyncHandler.onContentWritten(); } } } }
From source file:org.asynchttpclient.netty.request.WriteProgressListener.java
License:Open Source License
@Override public void operationComplete(ChannelProgressiveFuture cf) { operationComplete(cf.channel(), cf.cause()); }
From source file:org.asynchttpclient.providers.netty.request.ProgressListener.java
License:Apache License
@Override public void operationComplete(ChannelProgressiveFuture cf) { // The write operation failed. If the channel was cached, it means it got asynchronously closed. // Let's retry a second time. if (!abortOnThrowable(cf.cause(), cf.channel())) { future.touch();/*from w ww. ja v a 2 s .c o m*/ /** * We need to make sure we aren't in the middle of an authorization process before publishing events as we * will re-publish again the same event after the authorization, * causing unpredictable behavior. */ Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : config.getRealm(); boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { ProgressAsyncHandler<?> progressAsyncHandler = (ProgressAsyncHandler<?>) asyncHandler; if (notifyHeaders) { progressAsyncHandler.onHeaderWriteCompleted(); } else { progressAsyncHandler.onContentWriteCompleted(); } } } }
From source file:org.asynchttpclient.providers.netty4.request.ProgressListener.java
License:Open Source License
@Override public void operationComplete(ChannelProgressiveFuture cf) { // The write operation failed. If the channel was cached, it means it got asynchronously closed. // Let's retry a second time. if (!abortOnThrowable(cf.cause(), cf.channel())) { future.touch();/*www . ja va2 s.c om*/ /** * We need to make sure we aren't in the middle of an authorization * process before publishing events as we will re-publish again the * same event after the authorization, causing unpredictable * behavior. */ Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : config.getRealm(); boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { ProgressAsyncHandler<?> progressAsyncHandler = (ProgressAsyncHandler<?>) asyncHandler; if (notifyHeaders) { progressAsyncHandler.onHeaderWriteCompleted(); } else { progressAsyncHandler.onContentWriteCompleted(); } } } }
From source file:org.atmosphere.nettosphere.HttpStaticFileServerHandler.java
License:Apache License
@Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST, request); return;//from w w w . j a v a 2 s. co m } if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED, request); return; } File file = null; RandomAccessFile raf = null; boolean found = true; for (String p : paths) { String path = p + sanitizeUri(request.getUri()); if (path.endsWith("/") || path.endsWith(File.separator)) { path += "index.html"; } if (path.endsWith("/favicon.ico") || path.endsWith(File.separator)) { request.headers().add(SERVICED, "true"); found = false; continue; } file = new File(path); if (file.isHidden() || !file.exists() || !file.isFile()) { found = false; continue; } // if (file.isDirectory()) { // if (uri.endsWith("/")) { // sendListing(ctx, file); // } else { // sendRedirect(ctx, uri + '/'); // } // return; // } try { raf = new RandomAccessFile(file, "r"); found = true; break; } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND, request); return; } } if (!found) { sendError(ctx, NOT_FOUND, request); return; } request.headers().add(SERVICED, "true"); // Cache Validation String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client // does not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = file.lastModified() / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { sendNotModified(ctx); return; } } long fileLength = raf.length(); ctx.pipeline().addBefore(BridgeRuntime.class.getName(), "encoder", new HttpResponseEncoder()); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, fileLength); contentType(request, response, file); setDateAndCacheHeaders(response, file); // if (HttpHeaders.isKeepAlive(request)) { // response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); // } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture; ChannelFuture lastContentFuture; if (ctx.pipeline().get(SslHandler.class) == null) { sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); // Write the end marker. lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } else { sendFileFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()); // HttpChunkedInput will write the end marker (LastHttpContent) for us. lastContentFuture = sendFileFuture; } sendFileFuture.addListener(new ChannelProgressiveFutureListener() { @Override public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown logger.trace(future.channel() + " Transfer progress: " + progress); } else { logger.trace(future.channel() + " Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) { logger.trace(future.channel() + " Transfer complete."); } }); // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); }
From source file:org.mp4parser.rtp2dash.DashServerHandler.java
License:Apache License
@Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST);//from ww w .j a v a2 s . c om return; } if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final String uri = request.getUri(); if ("/Manifest.mpd".equals(uri)) { try { sendManifest(ctx); } catch (Exception e) { e.printStackTrace(); } return; } final String path = sanitizeUri(uri); if (path == null) { sendError(ctx, FORBIDDEN); return; } File file = new File(path); if (file.isHidden() || file.isDirectory() || !file.exists()) { sendError(ctx, NOT_FOUND); return; } if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; } // Cache Validation String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client // does not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = file.lastModified() / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { sendNotModified(ctx); return; } } final RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND); return; } long fileLength = raf.length(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, fileLength); setContentTypeHeader(response, file); setDateAndCacheHeaders(response, file); response.headers().set("Access-Control-Allow-Origin", "*"); if (HttpHeaders.isKeepAlive(request)) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture; ChannelFuture lastContentFuture; if (ctx.pipeline().get(SslHandler.class) == null) { sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); // Write the end marker. lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } else { sendFileFuture = ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()); // HttpChunkedInput will write the end marker (LastHttpContent) for us. lastContentFuture = sendFileFuture; } sendFileFuture.addListener(new ChannelProgressiveFutureListener() { public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown System.err.println(future.channel() + " Transfer progress: " + progress); } else { System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total); } } public void operationComplete(ChannelProgressiveFuture future) { try { raf.close(); } catch (IOException e) { LOG.severe("Cannot close " + raf.toString()); } System.err.println(future.channel() + " Transfer complete."); } }); // Decide whether to close the connection or not. if (!HttpHeaders.isKeepAlive(request)) { // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); } }
From source file:storage.netty.HttpUploadClient.java
License:Apache License
/** * Standard post without multipart but already support on Factory (memory management) * * @return the list of HttpData object (attribute and file) to be reused on next post *//*from www. j a v a 2s. c o m*/ private void formpost(Bootstrap bootstrap, String host, int port, URI uriSimple, String resourceUrl, File file, HttpDataFactory factory) throws Exception { // Start the connection attempt. Channel channel = bootstrap.connect(host, port).sync().channel(); // Wait until the connection attempt succeeds or fails. //Channel channel = future.sync().channel(); // Prepare the HTTP request. HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.PUT, uriSimple.toASCIIString()); request.headers().set(HttpHeaderNames.HOST, host); request.headers().add("x-ms-version", "2016-05-31"); final DateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); formatter.setTimeZone(TimeZone.getTimeZone("GMT")); String dateTime = formatter.format(new Date()); request.headers().set("x-ms-date", dateTime); request.headers().set("x-ms-blob-type", "BlockBlob"); request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); RandomAccessFile raf = new RandomAccessFile(file, "r"); long fileLength = raf.length(); HttpUtil.setContentLength(request, fileLength); setContentTypeHeader(request, file); // Use the PostBody encoder //HttpPostRequestEncoder bodyRequestEncoder = // new HttpPostRequestEncoder(factory, request, false); // false => not multipart // add Form attribute //bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false); request.headers().set("Authorization", "SharedKey " + account_name + ":" + AuthorizationHeader(account_name, account_key, "PUT", dateTime, request, resourceUrl, "", "")); channel.write(request); // ByteBuf buffer = Unpooled.copiedBuffer(Files.readAllBytes(file.toPath())); //ByteBuf buffer = Unpooled.buffer(new FileInputStream(file), (int) file.length()); ChannelFuture sendFileFuture = channel.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), channel.newProgressivePromise()); // Write the end marker. ChannelFuture lastContentFuture = channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); sendFileFuture.addListener(new ChannelProgressiveFutureListener() { @Override public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown System.err.println(future.channel() + " Transfer progress: " + progress); } else { System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) { System.err.println(future.channel() + " Transfer complete."); } }); }