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(); }
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); }
@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; } }
@Override public List<String> names() { List<String> list = new ArrayList<String>(); DefaultChannelHandlerContext ctx = head.next; for (; ; ) { if (ctx == null) { return list; } list.add(ctx.name()); ctx = ctx.next; } }
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(); }