/**
   * {@inheritDoc} Down-casts the received upstream event into more meaningful sub-type event and
   * calls an appropriate handler method with the down-casted event.
   */
  public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {

    if (e instanceof MessageEvent) {
      messageReceived(ctx, (MessageEvent) e);
    } else if (e instanceof WriteCompletionEvent) {
      WriteCompletionEvent evt = (WriteCompletionEvent) e;
      writeComplete(ctx, evt);
    } else if (e instanceof ChildChannelStateEvent) {
      ChildChannelStateEvent evt = (ChildChannelStateEvent) e;
      if (evt.getChildChannel().isOpen()) {
        childChannelOpen(ctx, evt);
      } else {
        childChannelClosed(ctx, evt);
      }
    } else if (e instanceof ChannelStateEvent) {
      ChannelStateEvent evt = (ChannelStateEvent) e;
      switch (evt.getState()) {
        case OPEN:
          if (Boolean.TRUE.equals(evt.getValue())) {
            channelOpen(ctx, evt);
          } else {
            channelClosed(ctx, evt);
          }
          break;
        case BOUND:
          if (evt.getValue() != null) {
            channelBound(ctx, evt);
          } else {
            channelUnbound(ctx, evt);
          }
          break;
        case CONNECTED:
          if (evt.getValue() != null) {
            channelConnected(ctx, evt);
          } else {
            channelDisconnected(ctx, evt);
          }
          break;
        case INTEREST_OPS:
          channelInterestChanged(ctx, evt);
          break;
        default:
          ctx.sendUpstream(e);
      }
    } else if (e instanceof ExceptionEvent) {
      exceptionCaught(ctx, (ExceptionEvent) e);
    } else {
      ctx.sendUpstream(e);
    }
  }