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; } }
/** Returns the {@link String} representation of this pipeline. */ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getSimpleName()); buf.append('{'); DefaultChannelHandlerContext ctx = head.next; for (; ; ) { if (ctx == tail) { break; } buf.append('('); buf.append(ctx.name()); buf.append(" = "); buf.append(ctx.handler().getClass().getName()); buf.append(')'); ctx = ctx.next; if (ctx == tail) { break; } buf.append(", "); } buf.append('}'); return buf.toString(); }
@Override public ChannelHandler last() { DefaultChannelHandlerContext last = tail.prev; if (last == head) { return null; } return last.handler(); }
@Override public ChannelHandler first() { DefaultChannelHandlerContext first = head.next; if (first == null) { return null; } return first.handler(); }
private ChannelHandler replace( final DefaultChannelHandlerContext ctx, final String newName, ChannelHandler newHandler, final boolean forward) { assert ctx != head && ctx != tail; Future<?> future; synchronized (this) { boolean sameName = ctx.name().equals(newName); if (!sameName) { checkDuplicateName(newName); } final DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, ctx.executor, newName, newHandler); if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) { replace0(ctx, newName, newCtx, forward); return ctx.handler(); } else { future = newCtx .executor() .submit( new Runnable() { @Override public void run() { synchronized (DefaultChannelPipeline.this) { replace0(ctx, newName, newCtx, forward); } } }); } } // Run the following 'waiting' code outside of the above synchronized block // in order to avoid deadlock waitForFuture(future); return ctx.handler(); }
@Override public Map<String, ChannelHandler> toMap() { Map<String, ChannelHandler> map = new LinkedHashMap<String, ChannelHandler>(); DefaultChannelHandlerContext ctx = head.next; for (; ; ) { if (ctx == tail) { return map; } map.put(ctx.name(), ctx.handler()); ctx = ctx.next; } }
private void callAfterRemove(final DefaultChannelHandlerContext ctx, boolean forward) { final ChannelHandler handler = ctx.handler(); // Notify the complete removal. try { handler.afterRemove(ctx); } catch (Throwable t) { throw new ChannelPipelineException( ctx.handler().getClass().getName() + ".afterRemove() has thrown an exception.", t); } if (forward) { ctx.forwardBufferContent(); } else { ctx.clearBuffer(); } ctx.removed = true; // Free all buffers before completing removal. if (!channel.isRegistered()) { ctx.freeHandlerBuffersAfterRemoval(); } }
@Override public ChannelHandlerContext context(Class<? extends ChannelHandler> handlerType) { if (handlerType == null) { throw new NullPointerException("handlerType"); } DefaultChannelHandlerContext ctx = head.next; for (; ; ) { if (ctx == null) { return null; } if (handlerType.isAssignableFrom(ctx.handler().getClass())) { return ctx; } ctx = ctx.next; } }
@Override public ChannelHandlerContext context(ChannelHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } DefaultChannelHandlerContext ctx = head.next; for (; ; ) { if (ctx == null) { return null; } if (ctx.handler() == handler) { return ctx; } ctx = ctx.next; } }