private void replace0(
      DefaultChannelHandlerContext ctx,
      String newName,
      DefaultChannelHandlerContext newCtx,
      boolean forward) {
    boolean sameName = ctx.name().equals(newName);

    DefaultChannelHandlerContext prev = ctx.prev;
    DefaultChannelHandlerContext next = ctx.next;
    newCtx.prev = prev;
    newCtx.next = next;

    callBeforeRemove(ctx);
    callBeforeAdd(newCtx);

    prev.next = newCtx;
    next.prev = newCtx;

    if (!sameName) {
      name2ctx.remove(ctx.name());
    }
    name2ctx.put(newName, newCtx);

    ChannelPipelineException removeException = null;
    ChannelPipelineException addException = null;
    boolean removed = false;
    try {
      callAfterRemove(ctx, forward);
      removed = true;
    } catch (ChannelPipelineException e) {
      removeException = e;
    }

    boolean added = false;
    try {
      callAfterAdd(newCtx);
      added = true;
    } catch (ChannelPipelineException e) {
      addException = e;
    }

    if (!removed && !added) {
      logger.warn(removeException.getMessage(), removeException);
      logger.warn(addException.getMessage(), addException);
      throw new ChannelPipelineException(
          "Both "
              + ctx.handler().getClass().getName()
              + ".afterRemove() and "
              + newCtx.handler().getClass().getName()
              + ".afterAdd() failed; see logs.");
    } else if (!removed) {
      throw removeException;
    } else if (!added) {
      throw addException;
    }
  }
  private void addBefore0(
      final String name, DefaultChannelHandlerContext ctx, DefaultChannelHandlerContext newCtx) {

    newCtx.prev = ctx.prev;
    newCtx.next = ctx;

    callBeforeAdd(newCtx);

    ctx.prev.next = newCtx;
    ctx.prev = newCtx;
    name2ctx.put(name, newCtx);

    callAfterAdd(newCtx);
  }
  private void addLast0(final String name, DefaultChannelHandlerContext newCtx) {
    DefaultChannelHandlerContext prev = tail.prev;
    newCtx.prev = prev;
    newCtx.next = tail;

    callBeforeAdd(newCtx);

    prev.next = newCtx;
    tail.prev = newCtx;

    name2ctx.put(name, newCtx);

    callAfterAdd(newCtx);
  }
  private void addFirst0(String name, DefaultChannelHandlerContext newCtx) {
    DefaultChannelHandlerContext nextCtx = head.next;
    newCtx.prev = head;
    newCtx.next = nextCtx;

    callBeforeAdd(newCtx);

    head.next = newCtx;
    nextCtx.prev = newCtx;

    name2ctx.put(name, newCtx);

    callAfterAdd(newCtx);
  }
  public DefaultChannelPipeline(Channel channel) {
    if (channel == null) {
      throw new NullPointerException("channel");
    }
    this.channel = channel;

    tail = new DefaultChannelHandlerContext(this, null, generateName(TAIL_HANDLER), TAIL_HANDLER);

    HeadHandler headHandler;
    switch (channel.metadata().bufferType()) {
      case BYTE:
        headHandler = new ByteHeadHandler();
        break;
      case MESSAGE:
        headHandler = new MessageHeadHandler();
        break;
      default:
        throw new Error("unknown buffer type: " + channel.metadata().bufferType());
    }

    head =
        new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler, true);

    head.next = tail;
    tail.prev = head;

    unsafe = channel.unsafe();
  }
  private void remove0(DefaultChannelHandlerContext ctx, boolean forward) {
    callBeforeRemove(ctx);

    DefaultChannelHandlerContext prev = ctx.prev;
    DefaultChannelHandlerContext next = ctx.next;
    prev.next = next;
    next.prev = prev;
    name2ctx.remove(ctx.name());

    callAfterRemove(ctx, forward);
  }
  private void addAfter0(
      final String name, DefaultChannelHandlerContext ctx, DefaultChannelHandlerContext newCtx) {
    checkDuplicateName(name);

    newCtx.prev = ctx;
    newCtx.next = ctx.next;

    callBeforeAdd(newCtx);

    ctx.next.prev = newCtx;
    ctx.next = newCtx;

    name2ctx.put(name, newCtx);

    callAfterAdd(newCtx);
  }