package edu.uw.zookeeper.protocol; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.uw.zookeeper.common.Automaton; import edu.uw.zookeeper.common.Automatons; import edu.uw.zookeeper.net.CodecConnection; import edu.uw.zookeeper.net.Connection; import edu.uw.zookeeper.protocol.ProtocolState; public abstract class ProtocolConnection<I,O,V extends ProtocolCodec<?,?,?,?>, T extends CodecConnection<? super I, ? extends O, V, ?>, C extends ProtocolConnection<I,O,V,T,C>> extends ForwardingCodecConnection<I,O,V,T,C> implements Automatons.AutomatonListener<ProtocolState>, Connection.Listener<O> { protected final Logger logger; protected final T connection; protected ProtocolConnection(T connection) { this.logger = LogManager.getLogger(getClass()); this.connection = connection; connection.subscribe(this); connection.codec().subscribe(this); } @Override public void handleConnectionRead(O message) { } @Override public void handleAutomatonTransition(Automaton.Transition<ProtocolState> transition) { switch (transition.to()) { case DISCONNECTED: case ERROR: { execute(new CloseTask()); break; } default: break; } } @Override public void handleConnectionState(Automaton.Transition<Connection.State> transition) { switch (transition.to()) { case CONNECTION_CLOSED: { delegate().unsubscribe(this); codec().unsubscribe(this); ProtocolState state = codec().state(); switch (state) { case ANONYMOUS: case DISCONNECTED: case ERROR: break; default: logger.warn(LoggingMarker.PROTOCOL_MARKER.get(), "Connection closed with protocol state {}: {}", state, this); codec().apply(ProtocolState.ERROR); } break; } default: break; } } @Override protected T delegate() { return connection; } public class CloseTask implements Runnable { @Override public void run() { logger.debug("Closing {}", ProtocolConnection.this); delegate().flush(); delegate().close(); } } }