Netty의 ChannelPipeline(2) ChannelHandler 제거

20101 단어 Netty
지난번에 첨가한다고 했으니 이번에는 빼보자.remove(ChannelHandler handler) 방법으로 지정된 ChannelHandler 객체를 pipeline에서 제거합니다.
@Override
public final ChannelPipeline remove(ChannelHandler handler) {
     
    remove(getContextOrDie(handler));
    return this;
}

getContextOrDie(ChannelHandler handler) 방법으로 해당하는 AbstractChannelHandlerContext 노드를 획득합니다.
private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
     
    AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
    if (ctx == null) {
      
    // , 
        throw new NoSuchElementException(handler.getClass().getName());
    } else {
     
        return ctx;
    }
}

@Override
public final ChannelHandlerContext context(ChannelHandler handler) {
     
    if (handler == null) {
     
        throw new NullPointerException("handler");
    }
    AbstractChannelHandlerContext ctx = head.next;
    //  ,  ChannelHandler  
    for (;;) {
     
        if (ctx == null) {
     
            return null;
        }
        if (ctx.handler() == handler) {
      
        // ChannelHandler  
            return ctx;
        }
        ctx = ctx.next;
    }
}

remove(AbstractChannelHandlerContext ctx) 메서드를 사용하여 지정된 AbstractChannelHandlerContext 노드를 제거합니다.
 private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
     
     assert ctx != head && ctx != tail;
 
     synchronized (this) {
      
     	 //  pipeline  
         //  
         remove0(ctx);
         // If the registered is false it means that the channel was not registered on an eventloop yet.
         // In this case we remove the context from the pipeline and add a task that will call
         // ChannelHandler.handlerRemoved(...) once the channel is registered.
         if (!registered) {
     
         //Channel 
         // PendingHandlerRemovedTask , Channel 。
             callHandlerCallbackLater(ctx, false);
             return ctx;
         }
         EventExecutor executor = ctx.executor();
         //   EventLoop  。
         if (!executor.inEventLoop()) {
     
             //   EventLoop  ,
             executor.execute(new Runnable() {
     
                 @Override
                 public void run() {
     
                 //  ChannelHandler removed  
                     callHandlerRemoved0(ctx);
                 }
             });
             return ctx;
         }
     }
 
     //   ChannelHandler removed  
     callHandlerRemoved0(ctx);
     return ctx;
 }

remove0 (AbstractChannelHandlerContext ctx) 방법은 pipeline에서 지정한 AbstractChannelHandlerContext 노드를 제거합니다.
private static void remove0(AbstractChannelHandlerContext ctx) {
     
    //  
    AbstractChannelHandlerContext prev = ctx.prev;
    AbstractChannelHandlerContext next = ctx.next;
    //  
    prev.next = next;
    next.prev = prev;
}

callHandlerRemoved0(AbstractChannelHandlerContext) 방법으로 ChannelHandler 제거 완료(removed) 이벤트를 리셋합니다.
 private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
     
     // Notify the complete removal.
     try {
     
         try {
     
             //   ChannelHandler  ( removed ) , ChannelHandler ( EventLoop , )
             ctx.handler().handlerRemoved(ctx);
         } finally {
     
             //   AbstractChannelHandlerContext  
             ctx.setRemoved();
         }
     } catch (Throwable t) {
     
         fireExceptionCaught(new ChannelPipelineException(
                 ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
     }
 }

PendingHandlerRemovedTask는 PendingHandlerCallback 추상 클래스를 실현하고 채널Handler 노드를 리셋하는 데 사용됩니다.
private final class PendingHandlerRemovedTask extends PendingHandlerCallback {
     

    PendingHandlerRemovedTask(AbstractChannelHandlerContext ctx) {
     
        super(ctx);
    }

    @Override
    public void run() {
     
        callHandlerRemoved0(ctx);
    }

    @Override
    void execute() {
     
        EventExecutor executor = ctx.executor();
        //   EventLoop  ,  ChannelHandler removed  
        if (executor.inEventLoop()) {
     
            callHandlerRemoved0(ctx);
        } else {
     
            //   EventLoop  ,  ChannelHandler removed  
            try {
     
                executor.execute(this); 
            } catch (RejectedExecutionException e) {
     
                if (logger.isWarnEnabled()) {
     
                    logger.warn(
                            "Can't invoke handlerRemoved() as the EventExecutor {} rejected it," +
                                    " removing handler {}.", executor, ctx.name(), e);
                }
                //   AbstractChannelHandlerContext  
                // remove0(...) was call before so just call AbstractChannelHandlerContext.setRemoved().
                ctx.setRemoved();
            }
        }
    }
    
}

좋은 웹페이지 즐겨찾기