@Override public ChannelGroupFuture close(ChannelMatcher matcher) { if (matcher == null) { throw new NullPointerException("matcher"); } Map<Channel, ChannelFuture> futures = new LinkedHashMap<Channel, ChannelFuture>(size()); if (stayClosed) { // It is important to set the closed to true, before closing channels. // Our invariants are: // closed=true happens-before ChannelGroup.close() // ChannelGroup.add() happens-before checking closed==true // // See https://github.com/netty/netty/issues/4020 closed = true; } for (Channel c : serverChannels) { if (matcher.matches(c)) { futures.put(c, c.close()); } } for (Channel c : nonServerChannels) { if (matcher.matches(c)) { futures.put(c, c.close()); } } return new DefaultChannelGroupFuture(this, futures, executor); }
@Override public boolean add(Channel channel) { ConcurrentSet<Channel> set = channel instanceof ServerChannel ? serverChannels : nonServerChannels; boolean added = set.add(channel); if (added) { channel.closeFuture().addListener(remover); } if (stayClosed && closed) { // First add channel, than check if closed. // Seems inefficient at first, but this way a volatile // gives us enough synchronization to be thread-safe. // // If true: Close right away. // (Might be closed a second time by ChannelGroup.close(), but this is ok) // // If false: Channel will definitely be closed by the ChannelGroup. // (Because closed=true always happens-before ChannelGroup.close()) // // See https://github.com/netty/netty/issues/4020 channel.close(); } return added; }
@Override public ChannelGroup flush(ChannelMatcher matcher) { for (Channel c : nonServerChannels) { if (matcher.matches(c)) { c.flush(); } } return this; }
/** * Returns the {@link ChannelGroupFuture} which will be notified when all {@link Channel}s that * are part of this {@link ChannelGroup}, at the time of calling, are closed. */ public ChannelGroupFuture newCloseFuture(ChannelMatcher matcher) { Map<Channel, ChannelFuture> futures = new LinkedHashMap<Channel, ChannelFuture>(size()); for (Channel c : serverChannels) { if (matcher.matches(c)) { futures.put(c, c.closeFuture()); } } for (Channel c : nonServerChannels) { if (matcher.matches(c)) { futures.put(c, c.closeFuture()); } } return new DefaultChannelGroupFuture(this, futures, executor); }
@Override public ChannelGroupFuture writeAndFlush(Object message, ChannelMatcher matcher) { if (message == null) { throw new NullPointerException("message"); } Map<Channel, ChannelFuture> futures = new LinkedHashMap<Channel, ChannelFuture>(size()); for (Channel c : nonServerChannels) { if (matcher.matches(c)) { futures.put(c, c.writeAndFlush(safeDuplicate(message))); } } ReferenceCountUtil.release(message); return new DefaultChannelGroupFuture(this, futures, executor); }
@Override public boolean remove(Object o) { if (!(o instanceof Channel)) { return false; } boolean removed; Channel c = (Channel) o; if (c instanceof ServerChannel) { removed = serverChannels.remove(c); } else { removed = nonServerChannels.remove(c); } if (!removed) { return false; } c.closeFuture().removeListener(remover); return true; }
@Override public ChannelGroupFuture deregister(ChannelMatcher matcher) { if (matcher == null) { throw new NullPointerException("matcher"); } Map<Channel, ChannelFuture> futures = new LinkedHashMap<Channel, ChannelFuture>(size()); for (Channel c : serverChannels) { if (matcher.matches(c)) { futures.put(c, c.deregister()); } } for (Channel c : nonServerChannels) { if (matcher.matches(c)) { futures.put(c, c.deregister()); } } return new DefaultChannelGroupFuture(this, futures, executor); }