1 /* 2 * Copyright 2012 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package io.netty5.channel.group; 17 18 import io.netty5.channel.Channel; 19 import io.netty5.channel.ChannelHandler; 20 import io.netty5.channel.ChannelHandlerContext; 21 import io.netty5.util.concurrent.Future; 22 import io.netty5.util.concurrent.FutureCompletionStage; 23 import io.netty5.util.concurrent.FutureListener; 24 25 import java.util.Iterator; 26 27 /** 28 * The result of an asynchronous {@link ChannelGroup} operation. 29 * {@link ChannelGroupFuture} is composed of {@link Future}s which 30 * represent the outcome of the individual I/O operations that affect the 31 * {@link Channel}s in the {@link ChannelGroup}. 32 * 33 * <p> 34 * All I/O operations in {@link ChannelGroup} are asynchronous. It means any 35 * I/O calls will return immediately with no guarantee that the requested I/O 36 * operations have been completed at the end of the call. Instead, you will be 37 * returned with a {@link ChannelGroupFuture} instance which tells you when the 38 * requested I/O operations have succeeded, failed, or cancelled. 39 * <p> 40 * Various methods are provided to let you check if the I/O operations has been 41 * completed, wait for the completion, and retrieve the result of the I/O 42 * operation. It also allows you to add more than one 43 * {@link ChannelGroupFutureListener} so you can get notified when the I/O 44 * operation have been completed. 45 * 46 * <h3>Prefer {@link #addListener(FutureListener)} to {@link FutureCompletionStage#await()}</h3> 47 * 48 * It is recommended to prefer {@link #addListener(FutureListener)} to 49 * {@link FutureCompletionStage#await()} wherever possible to get notified when I/O operations are 50 * done and to do any follow-up tasks. 51 * <p> 52 * {@link #addListener(FutureListener)} is non-blocking. It simply 53 * adds the specified {@link ChannelGroupFutureListener} to the 54 * {@link ChannelGroupFuture}, and I/O thread will notify the listeners when 55 * the I/O operations associated with the future is done. 56 * {@link ChannelGroupFutureListener} yields the best performance and resource 57 * utilization because it does not block at all, but it could be tricky to 58 * implement a sequential logic if you are not used to event-driven programming. 59 * <p> 60 * By contrast, {@link FutureCompletionStage#await()} is a blocking operation. Once called, the 61 * caller thread blocks until all I/O operations are done. It is easier to 62 * implement a sequential logic with {@link FutureCompletionStage#await()}, but the caller thread 63 * blocks unnecessarily until all I/O operations are done and there's relatively 64 * expensive cost of inter-thread notification. Moreover, there's a chance of 65 * dead lock in a particular circumstance, which is described below. 66 * 67 * <h3>Do not call {@link FutureCompletionStage#await()} inside {@link ChannelHandler}</h3> 68 * <p> 69 * The event handler methods in {@link ChannelHandler} is often called by 70 * an I/O thread. If {@link FutureCompletionStage#await()} is called by an event handler 71 * method, which is called by the I/O thread, the I/O operation it is waiting 72 * for might never be complete because {@link FutureCompletionStage#await()} can block the I/O 73 * operation it is waiting for, which is a deadlock. 74 * <pre> 75 * // BAD - NEVER DO THIS 76 * {@code @Override} 77 * public void messageReceived({@link ChannelHandlerContext} ctx, ShutdownMessage msg) { 78 * {@link ChannelGroup} allChannels = MyServer.getAllChannels(); 79 * {@link ChannelGroupFuture} future = allChannels.close(); 80 * future.asStage().await(); 81 * // Perform post-shutdown operation 82 * // ... 83 * 84 * } 85 * 86 * // GOOD 87 * {@code @Override} 88 * public void messageReceived(ChannelHandlerContext ctx, ShutdownMessage msg) { 89 * {@link ChannelGroup} allChannels = MyServer.getAllChannels(); 90 * {@link ChannelGroupFuture} future = allChannels.close(); 91 * future.addListener(new {@link ChannelGroupFutureListener}() { 92 * public void operationComplete({@link ChannelGroupFuture} future) { 93 * // Perform post-closure operation 94 * // ... 95 * } 96 * }); 97 * } 98 * </pre> 99 * <p> 100 * In spite of the disadvantages mentioned above, there are certainly the cases 101 * where it is more convenient to call {@link FutureCompletionStage#await()}. In such a case, please 102 * make sure you do not call {@link FutureCompletionStage#await()} in an I/O thread. Otherwise, 103 * {@link IllegalStateException} will be raised to prevent a dead lock. 104 */ 105 public interface ChannelGroupFuture extends Future<Void>, Iterable<Future<Void>> { 106 107 /** 108 * Returns the {@link ChannelGroup} which is associated with this future. 109 */ 110 ChannelGroup group(); 111 112 /** 113 * Returns the {@link Future} of the individual I/O operation which 114 * is associated with the specified {@link Channel}. 115 * 116 * @return the matching {@link Future} if found. 117 * {@code null} otherwise. 118 */ 119 Future<Void> find(Channel channel); 120 121 /** 122 * Returns {@code true} if and only if all I/O operations associated with 123 * this future were successful without any failure. 124 */ 125 @Override 126 boolean isSuccess(); 127 128 @Override 129 ChannelGroupException cause(); 130 131 /** 132 * Returns {@code true} if and only if the I/O operations associated with 133 * this future were partially successful with some failure. 134 */ 135 boolean isPartialSuccess(); 136 137 /** 138 * Returns {@code true} if and only if the I/O operations associated with 139 * this future have failed partially with some success. 140 */ 141 boolean isPartialFailure(); 142 143 @Override 144 ChannelGroupFuture addListener(FutureListener<? super Void> listener); 145 146 /** 147 * Returns the {@link Iterator} that enumerates all {@link Future}s 148 * which are associated with this future. Please note that the returned 149 * {@link Iterator} is is unmodifiable, which means a {@link Future} 150 * cannot be removed from this future. 151 */ 152 @Override 153 Iterator<Future<Void>> iterator(); 154 }