package edu.uw.zookeeper.netty; import static com.google.common.base.Preconditions.*; import java.util.Iterator; import org.apache.logging.log4j.Logger; import com.google.common.collect.Iterators; import edu.uw.zookeeper.common.Automaton; import edu.uw.zookeeper.common.Automatons; import edu.uw.zookeeper.common.Eventful; import edu.uw.zookeeper.net.Connection; import edu.uw.zookeeper.net.LoggingMarker; import net.engio.mbassy.common.IConcurrentSet; import net.engio.mbassy.common.StrongConcurrentSet; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.channel.SimpleChannelInboundHandler; public class EventfulHandler<O> extends SimpleChannelInboundHandler<O> implements Eventful<Connection.Listener<? super O>>, Automatons.AutomatonListener<Connection.State>, Connection.Listener<O> { public static EventfulHandler<?> fromPipeline(ChannelPipeline pipeline) { return (EventfulHandler<?>) pipeline.get(EventfulHandler.class.getName()); } public static ChannelPipeline toPipeline( EventfulHandler<?> handler, ChannelPipeline pipeline) { return pipeline.addLast( EventfulHandler.class.getName(), handler); } public static <O> EventfulHandler<O> withLogger( Class<? extends O> type, Logger logger) { return newInstance(type, EventfulHandler.<O>newListeners(), logger); } public static <O> EventfulHandler<O> newInstance( Class<? extends O> type, IConcurrentSet<Connection.Listener<? super O>> listeners, Logger logger) { return new EventfulHandler<O>(type, listeners, logger); } public static <O> IConcurrentSet<Connection.Listener<? super O>> newListeners() { return new StrongConcurrentSet<Connection.Listener<? super O>>(); } private final Logger logger; private final IConcurrentSet<Connection.Listener<? super O>> listeners; protected EventfulHandler( Class<? extends O> type, IConcurrentSet<Connection.Listener<? super O>> listeners, Logger logger) { super(type, true); this.logger = checkNotNull(logger); this.listeners = checkNotNull(listeners); } @Override public void subscribe(Connection.Listener<? super O> listener) { listeners.add(listener); } @Override public boolean unsubscribe(Connection.Listener<? super O> listener) { return listeners.remove(listener); } @Override public void handleAutomatonTransition(Automaton.Transition<Connection.State> transition) { handleConnectionState(transition); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Iterator<?> itr = Iterators.consumingIterator(listeners.iterator()); while (itr.hasNext()) { itr.next(); } super.handlerRemoved(ctx); } @Override public void handleConnectionState(Automaton.Transition<Connection.State> state) { for (Connection.Listener<? super O> listener: listeners) { listener.handleConnectionState(state); } } @Override public void handleConnectionRead(O message) { for (Connection.Listener<? super O> listener: listeners) { listener.handleConnectionRead(message); } } @Override protected void channelRead0(ChannelHandlerContext ctx, O message) { if (logger.isTraceEnabled()) { logger.trace(LoggingMarker.NET_MARKER.get(), "READ {} ({})", message, ctx.channel()); } handleConnectionRead(message); } }