Simplified DefaultChannelPipeline by making its list head final
- Previously, head was a volatile field which is null at the beginning. While iterating over the pipeline, if the loop hits null, it called Channel.Unsafe explicitly. - Instead, I created an outbound handler that redirects all requests to the unsafe and made it a final field of the pipeline. - As a result, DefaultChannelPipeline code became much simpler.
This commit is contained in:
parent
f6e14b636f
commit
f3734e1eb9
@ -72,7 +72,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
private final Channel parent;
|
private final Channel parent;
|
||||||
private final Integer id;
|
private final Integer id;
|
||||||
private final Unsafe unsafe;
|
private final Unsafe unsafe;
|
||||||
private final ChannelPipeline pipeline;
|
private final DefaultChannelPipeline pipeline;
|
||||||
private final ChannelFuture succeededFuture = new SucceededChannelFuture(this);
|
private final ChannelFuture succeededFuture = new SucceededChannelFuture(this);
|
||||||
private final ChannelFuture voidFuture = new VoidChannelFuture(this);
|
private final ChannelFuture voidFuture = new VoidChannelFuture(this);
|
||||||
private final CloseFuture closeFuture = new CloseFuture(this);
|
private final CloseFuture closeFuture = new CloseFuture(this);
|
||||||
@ -82,7 +82,6 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
private volatile EventLoop eventLoop;
|
private volatile EventLoop eventLoop;
|
||||||
private volatile boolean registered;
|
private volatile boolean registered;
|
||||||
|
|
||||||
private final ChannelBufferHolder<Object> directOutbound;
|
|
||||||
private ClosedChannelException closedChannelException;
|
private ClosedChannelException closedChannelException;
|
||||||
private final Deque<FlushCheckpoint> flushCheckpoints = new ArrayDeque<FlushCheckpoint>();
|
private final Deque<FlushCheckpoint> flushCheckpoints = new ArrayDeque<FlushCheckpoint>();
|
||||||
private long writeCounter;
|
private long writeCounter;
|
||||||
@ -123,7 +122,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
unsafe = newUnsafe();
|
unsafe = newUnsafe();
|
||||||
directOutbound = (ChannelBufferHolder<Object>) outboundBuffer;
|
pipeline = new DefaultChannelPipeline(this);
|
||||||
|
|
||||||
closeFuture().addListener(new ChannelFutureListener() {
|
closeFuture().addListener(new ChannelFutureListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -132,7 +131,6 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pipeline = new DefaultChannelPipeline(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -385,7 +383,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ChannelBufferHolder<Object> directOutbound() {
|
public final ChannelBufferHolder<Object> directOutbound() {
|
||||||
return directOutbound;
|
return pipeline.directOutbound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -628,7 +626,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
inFlushNow = true;
|
inFlushNow = true;
|
||||||
final ChannelBufferHolder<Object> out = directOutbound;
|
final ChannelBufferHolder<Object> out = directOutbound();
|
||||||
try {
|
try {
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
int oldSize = out.size();
|
int oldSize = out.size();
|
||||||
|
@ -5,6 +5,8 @@ import io.netty.util.DefaultAttributeMap;
|
|||||||
|
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelInboundHandlerContext<Object>, ChannelOutboundHandlerContext<Object> {
|
final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelInboundHandlerContext<Object>, ChannelOutboundHandlerContext<Object> {
|
||||||
volatile DefaultChannelHandlerContext next;
|
volatile DefaultChannelHandlerContext next;
|
||||||
@ -17,7 +19,17 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
|||||||
private final boolean canHandleInbound;
|
private final boolean canHandleInbound;
|
||||||
private final boolean canHandleOutbound;
|
private final boolean canHandleOutbound;
|
||||||
final ChannelBufferHolder<Object> in;
|
final ChannelBufferHolder<Object> in;
|
||||||
private final ChannelBufferHolder<Object> out;
|
final ChannelBufferHolder<Object> out;
|
||||||
|
|
||||||
|
// When the two handlers run in a different thread and they are next to each other,
|
||||||
|
// each other's buffers can be accessed at the same time resuslting in a race condition.
|
||||||
|
// To avoid such situation, we lazily creates an additional thread-safe buffer called
|
||||||
|
// 'bridge' so that the two handlers access each other's buffer only via the bridges.
|
||||||
|
// The content written into a bridge is flushed into the actual buffer by flushBridge().
|
||||||
|
final AtomicReference<BlockingQueue<Object>> inMsgBridge;
|
||||||
|
final AtomicReference<BlockingQueue<Object>> outMsgBridge;
|
||||||
|
final AtomicReference<ChannelBuffer> inByteBridge;
|
||||||
|
final AtomicReference<ChannelBuffer> outByteBridge;
|
||||||
|
|
||||||
// Runnables that calls handlers
|
// Runnables that calls handlers
|
||||||
final Runnable fireChannelRegisteredTask = new Runnable() {
|
final Runnable fireChannelRegisteredTask = new Runnable() {
|
||||||
@ -73,6 +85,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void run() {
|
public void run() {
|
||||||
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
|
DefaultChannelHandlerContext ctx = DefaultChannelHandlerContext.this;
|
||||||
|
flushBridge();
|
||||||
try {
|
try {
|
||||||
((ChannelInboundHandler<Object>) ctx.handler()).inboundBufferUpdated(ctx);
|
((ChannelInboundHandler<Object>) ctx.handler()).inboundBufferUpdated(ctx);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
@ -135,8 +148,23 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ChannelPipelineException("A user handler failed to create a new inbound buffer.", e);
|
throw new ChannelPipelineException("A user handler failed to create a new inbound buffer.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!in.isBypass()) {
|
||||||
|
if (in.hasByteBuffer()) {
|
||||||
|
inByteBridge = new AtomicReference<ChannelBuffer>();
|
||||||
|
inMsgBridge = null;
|
||||||
|
} else {
|
||||||
|
inByteBridge = null;
|
||||||
|
inMsgBridge = new AtomicReference<BlockingQueue<Object>>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inByteBridge = null;
|
||||||
|
inMsgBridge = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
in = null;
|
in = null;
|
||||||
|
inByteBridge = null;
|
||||||
|
inMsgBridge = null;
|
||||||
}
|
}
|
||||||
if (canHandleOutbound) {
|
if (canHandleOutbound) {
|
||||||
try {
|
try {
|
||||||
@ -148,8 +176,38 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
|||||||
// TODO Release the inbound buffer once pooling is implemented.
|
// TODO Release the inbound buffer once pooling is implemented.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!out.isBypass()) {
|
||||||
|
if (out.hasByteBuffer()) {
|
||||||
|
outByteBridge = new AtomicReference<ChannelBuffer>();
|
||||||
|
outMsgBridge = null;
|
||||||
|
} else {
|
||||||
|
outByteBridge = null;
|
||||||
|
outMsgBridge = new AtomicReference<BlockingQueue<Object>>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outByteBridge = null;
|
||||||
|
outMsgBridge = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
out = null;
|
out = null;
|
||||||
|
outByteBridge = null;
|
||||||
|
outMsgBridge = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flushBridge() {
|
||||||
|
if (inMsgBridge != null) {
|
||||||
|
BlockingQueue<Object> bridge = inMsgBridge.get();
|
||||||
|
if (bridge != null) {
|
||||||
|
bridge.drainTo(in.messageBuffer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outMsgBridge != null) {
|
||||||
|
BlockingQueue<Object> bridge = outMsgBridge.get();
|
||||||
|
if (bridge != null) {
|
||||||
|
bridge.drainTo(out.messageBuffer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +287,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Queue<Object> nextInboundMessageBuffer() {
|
public Queue<Object> nextInboundMessageBuffer() {
|
||||||
return DefaultChannelPipeline.nextInboundMessageBuffer(next);
|
return DefaultChannelPipeline.nextInboundMessageBuffer(executor(), next);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -239,7 +297,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Queue<Object> nextOutboundMessageBuffer() {
|
public Queue<Object> nextOutboundMessageBuffer() {
|
||||||
return pipeline.nextOutboundMessageBuffer(prev);
|
return pipeline.nextOutboundMessageBuffer(executor(), prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,6 +18,7 @@ package io.netty.channel;
|
|||||||
import io.netty.buffer.ChannelBuffer;
|
import io.netty.buffer.ChannelBuffer;
|
||||||
import io.netty.logging.InternalLogger;
|
import io.netty.logging.InternalLogger;
|
||||||
import io.netty.logging.InternalLoggerFactory;
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
import io.netty.util.internal.QueueFactory;
|
||||||
|
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -28,6 +29,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default {@link ChannelPipeline} implementation. It is usually created
|
* The default {@link ChannelPipeline} implementation. It is usually created
|
||||||
@ -39,9 +43,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
private final Channel.Unsafe unsafe;
|
private final Channel.Unsafe unsafe;
|
||||||
private final ChannelBufferHolder<Object> directOutbound;
|
final ChannelBufferHolder<Object> directOutbound;
|
||||||
|
|
||||||
private volatile DefaultChannelHandlerContext head;
|
private final DefaultChannelHandlerContext head;
|
||||||
private volatile DefaultChannelHandlerContext tail;
|
private volatile DefaultChannelHandlerContext tail;
|
||||||
private final Map<String, DefaultChannelHandlerContext> name2ctx =
|
private final Map<String, DefaultChannelHandlerContext> name2ctx =
|
||||||
new HashMap<String, DefaultChannelHandlerContext>(4);
|
new HashMap<String, DefaultChannelHandlerContext>(4);
|
||||||
@ -56,8 +60,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
throw new NullPointerException("channel");
|
throw new NullPointerException("channel");
|
||||||
}
|
}
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
|
||||||
|
HeadHandler headHandler = new HeadHandler();
|
||||||
|
head = new DefaultChannelHandlerContext(
|
||||||
|
this, null, null, null, generateName(headHandler), headHandler);
|
||||||
|
tail = head;
|
||||||
|
|
||||||
|
directOutbound = head.out;
|
||||||
unsafe = channel.unsafe();
|
unsafe = channel.unsafe();
|
||||||
directOutbound = unsafe.directOutbound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -72,23 +82,20 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized ChannelPipeline addFirst(EventExecutor executor, String name, ChannelHandler handler) {
|
public synchronized ChannelPipeline addFirst(EventExecutor executor, String name, ChannelHandler handler) {
|
||||||
if (name2ctx.isEmpty()) {
|
|
||||||
init(executor, name, handler);
|
|
||||||
} else {
|
|
||||||
checkDuplicateName(name);
|
checkDuplicateName(name);
|
||||||
DefaultChannelHandlerContext oldHead = head;
|
DefaultChannelHandlerContext nextCtx = head.next;
|
||||||
DefaultChannelHandlerContext newHead =
|
DefaultChannelHandlerContext newCtx =
|
||||||
new DefaultChannelHandlerContext(this, executor, null, oldHead, name, handler);
|
new DefaultChannelHandlerContext(this, executor, head, nextCtx, name, handler);
|
||||||
|
|
||||||
callBeforeAdd(newHead);
|
callBeforeAdd(newCtx);
|
||||||
|
|
||||||
oldHead.prev = newHead;
|
if (nextCtx != null) {
|
||||||
head = newHead;
|
nextCtx.prev = newCtx;
|
||||||
name2ctx.put(name, newHead);
|
|
||||||
|
|
||||||
callAfterAdd(newHead);
|
|
||||||
}
|
}
|
||||||
|
head.next = newCtx;
|
||||||
|
name2ctx.put(name, newCtx);
|
||||||
|
|
||||||
|
callAfterAdd(newCtx);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,9 +106,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized ChannelPipeline addLast(EventExecutor executor, String name, ChannelHandler handler) {
|
public synchronized ChannelPipeline addLast(EventExecutor executor, String name, ChannelHandler handler) {
|
||||||
if (name2ctx.isEmpty()) {
|
|
||||||
init(executor, name, handler);
|
|
||||||
} else {
|
|
||||||
checkDuplicateName(name);
|
checkDuplicateName(name);
|
||||||
DefaultChannelHandlerContext oldTail = tail;
|
DefaultChannelHandlerContext oldTail = tail;
|
||||||
DefaultChannelHandlerContext newTail =
|
DefaultChannelHandlerContext newTail =
|
||||||
@ -114,8 +118,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
name2ctx.put(name, newTail);
|
name2ctx.put(name, newTail);
|
||||||
|
|
||||||
callAfterAdd(newTail);
|
callAfterAdd(newTail);
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,9 +129,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized ChannelPipeline addBefore(EventExecutor executor, String baseName, String name, ChannelHandler handler) {
|
public synchronized ChannelPipeline addBefore(EventExecutor executor, String baseName, String name, ChannelHandler handler) {
|
||||||
DefaultChannelHandlerContext ctx = getContextOrDie(baseName);
|
DefaultChannelHandlerContext ctx = getContextOrDie(baseName);
|
||||||
if (ctx == head) {
|
|
||||||
addFirst(name, handler);
|
|
||||||
} else {
|
|
||||||
checkDuplicateName(name);
|
checkDuplicateName(name);
|
||||||
DefaultChannelHandlerContext newCtx =
|
DefaultChannelHandlerContext newCtx =
|
||||||
new DefaultChannelHandlerContext(this, executor, ctx.prev, ctx, name, handler);
|
new DefaultChannelHandlerContext(this, executor, ctx.prev, ctx, name, handler);
|
||||||
@ -141,8 +140,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
name2ctx.put(name, newCtx);
|
name2ctx.put(name, newCtx);
|
||||||
|
|
||||||
callAfterAdd(newCtx);
|
callAfterAdd(newCtx);
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,10 +247,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
private DefaultChannelHandlerContext remove(DefaultChannelHandlerContext ctx) {
|
private DefaultChannelHandlerContext remove(DefaultChannelHandlerContext ctx) {
|
||||||
if (head == tail) {
|
if (head == tail) {
|
||||||
head = tail = null;
|
return null;
|
||||||
name2ctx.clear();
|
|
||||||
} else if (ctx == head) {
|
} else if (ctx == head) {
|
||||||
removeFirst();
|
throw new Error(); // Should never happen.
|
||||||
} else if (ctx == tail) {
|
} else if (ctx == tail) {
|
||||||
removeLast();
|
removeLast();
|
||||||
} else {
|
} else {
|
||||||
@ -272,55 +268,26 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized ChannelHandler removeFirst() {
|
public synchronized ChannelHandler removeFirst() {
|
||||||
if (name2ctx.isEmpty()) {
|
if (head == tail) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
|
return remove(head.next).handler();
|
||||||
DefaultChannelHandlerContext oldHead = head;
|
|
||||||
if (oldHead == null) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
|
|
||||||
callBeforeRemove(oldHead);
|
|
||||||
|
|
||||||
if (oldHead.next == null) {
|
|
||||||
head = tail = null;
|
|
||||||
name2ctx.clear();
|
|
||||||
} else {
|
|
||||||
oldHead.next.prev = null;
|
|
||||||
head = oldHead.next;
|
|
||||||
name2ctx.remove(oldHead.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
callAfterRemove(oldHead);
|
|
||||||
|
|
||||||
return oldHead.handler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized ChannelHandler removeLast() {
|
public synchronized ChannelHandler removeLast() {
|
||||||
if (name2ctx.isEmpty()) {
|
if (head == tail) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultChannelHandlerContext oldTail = tail;
|
DefaultChannelHandlerContext oldTail = tail;
|
||||||
if (oldTail == null) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
|
|
||||||
callBeforeRemove(oldTail);
|
callBeforeRemove(oldTail);
|
||||||
|
|
||||||
if (oldTail.prev == null) {
|
|
||||||
head = tail = null;
|
|
||||||
name2ctx.clear();
|
|
||||||
} else {
|
|
||||||
oldTail.prev.next = null;
|
oldTail.prev.next = null;
|
||||||
tail = oldTail.prev;
|
tail = oldTail.prev;
|
||||||
name2ctx.remove(oldTail.name());
|
name2ctx.remove(oldTail.name());
|
||||||
}
|
|
||||||
|
|
||||||
callBeforeRemove(oldTail);
|
callBeforeRemove(oldTail);
|
||||||
|
|
||||||
return oldTail.handler();
|
return oldTail.handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,8 +310,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
private ChannelHandler replace(DefaultChannelHandlerContext ctx, String newName, ChannelHandler newHandler) {
|
private ChannelHandler replace(DefaultChannelHandlerContext ctx, String newName, ChannelHandler newHandler) {
|
||||||
if (ctx == head) {
|
if (ctx == head) {
|
||||||
removeFirst();
|
throw new IllegalArgumentException();
|
||||||
addFirst(newName, newHandler);
|
|
||||||
} else if (ctx == tail) {
|
} else if (ctx == tail) {
|
||||||
removeLast();
|
removeLast();
|
||||||
addLast(newName, newHandler);
|
addLast(newName, newHandler);
|
||||||
@ -472,20 +438,20 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized ChannelHandler first() {
|
public synchronized ChannelHandler first() {
|
||||||
DefaultChannelHandlerContext head = this.head;
|
DefaultChannelHandlerContext first = head.next;
|
||||||
if (head == null) {
|
if (first == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return head.handler();
|
return first.handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized ChannelHandler last() {
|
public synchronized ChannelHandler last() {
|
||||||
DefaultChannelHandlerContext tail = this.tail;
|
DefaultChannelHandlerContext last = tail;
|
||||||
if (tail == null) {
|
if (last == head || last == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return tail.handler();
|
return last.handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -548,7 +514,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
if (name2ctx.isEmpty()) {
|
if (name2ctx.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
DefaultChannelHandlerContext ctx = head;
|
DefaultChannelHandlerContext ctx = head.next;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (handlerType.isAssignableFrom(ctx.handler().getClass())) {
|
if (handlerType.isAssignableFrom(ctx.handler().getClass())) {
|
||||||
return ctx;
|
return ctx;
|
||||||
@ -569,7 +535,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultChannelHandlerContext ctx = head;
|
DefaultChannelHandlerContext ctx = head.next;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
list.add(ctx.name());
|
list.add(ctx.name());
|
||||||
ctx = ctx.next;
|
ctx = ctx.next;
|
||||||
@ -587,7 +553,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultChannelHandlerContext ctx = head;
|
DefaultChannelHandlerContext ctx = head.next;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
map.put(ctx.name(), ctx.handler());
|
map.put(ctx.name(), ctx.handler());
|
||||||
ctx = ctx.next;
|
ctx = ctx.next;
|
||||||
@ -606,7 +572,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
buf.append(getClass().getSimpleName());
|
buf.append(getClass().getSimpleName());
|
||||||
buf.append('{');
|
buf.append('{');
|
||||||
DefaultChannelHandlerContext ctx = head;
|
DefaultChannelHandlerContext ctx = head.next;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
buf.append('(');
|
buf.append('(');
|
||||||
buf.append(ctx.name());
|
buf.append(ctx.name());
|
||||||
@ -629,7 +595,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
throw new NoSuchBufferException(
|
throw new NoSuchBufferException(
|
||||||
"The first inbound buffer of this channel must be a message buffer.");
|
"The first inbound buffer of this channel must be a message buffer.");
|
||||||
}
|
}
|
||||||
return nextInboundMessageBuffer(head);
|
return nextInboundMessageBuffer(null, head.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -638,12 +604,12 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
throw new NoSuchBufferException(
|
throw new NoSuchBufferException(
|
||||||
"The first inbound buffer of this channel must be a byte buffer.");
|
"The first inbound buffer of this channel must be a byte buffer.");
|
||||||
}
|
}
|
||||||
return nextInboundByteBuffer(head);
|
return nextInboundByteBuffer(head.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Queue<Object> outboundMessageBuffer() {
|
public Queue<Object> outboundMessageBuffer() {
|
||||||
return nextOutboundMessageBuffer(tail);
|
return nextOutboundMessageBuffer(null, tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -690,14 +656,27 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Queue<Object> nextInboundMessageBuffer(DefaultChannelHandlerContext ctx) {
|
static Queue<Object> nextInboundMessageBuffer(
|
||||||
|
EventExecutor currentExecutor, DefaultChannelHandlerContext ctx) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
throw new NoSuchBufferException();
|
throw new NoSuchBufferException();
|
||||||
}
|
}
|
||||||
ChannelBufferHolder<Object> in = ctx.inbound();
|
|
||||||
if (in != null && !in.isBypass() && in.hasMessageBuffer()) {
|
final AtomicReference<BlockingQueue<Object>> inMsgBridge = ctx.inMsgBridge;
|
||||||
return in.messageBuffer();
|
if (inMsgBridge != null) {
|
||||||
|
if (currentExecutor == ctx.executor()) {
|
||||||
|
return ctx.in.messageBuffer();
|
||||||
|
} else {
|
||||||
|
BlockingQueue<Object> queue = inMsgBridge.get();
|
||||||
|
if (queue == null) {
|
||||||
|
queue = QueueFactory.createQueue();
|
||||||
|
if (!inMsgBridge.compareAndSet(null, queue)) {
|
||||||
|
queue = inMsgBridge.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx = ctx.next;
|
ctx = ctx.next;
|
||||||
}
|
}
|
||||||
@ -706,12 +685,8 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
boolean hasNextOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
|
boolean hasNextOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
if (directOutbound.hasByteBuffer()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ChannelBufferHolder<Object> out = ctx.outbound();
|
ChannelBufferHolder<Object> out = ctx.outbound();
|
||||||
if (out != null && !out.isBypass() && out.hasByteBuffer()) {
|
if (out != null && !out.isBypass() && out.hasByteBuffer()) {
|
||||||
@ -724,12 +699,8 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
boolean hasNextOutboundMessageBuffer(DefaultChannelHandlerContext ctx) {
|
boolean hasNextOutboundMessageBuffer(DefaultChannelHandlerContext ctx) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
if (directOutbound.hasMessageBuffer()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ChannelBufferHolder<Object> out = ctx.outbound();
|
ChannelBufferHolder<Object> out = ctx.outbound();
|
||||||
if (out != null && !out.isBypass() && out.hasMessageBuffer()) {
|
if (out != null && !out.isBypass() && out.hasMessageBuffer()) {
|
||||||
@ -742,12 +713,8 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
ChannelBuffer nextOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
|
ChannelBuffer nextOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
if (directOutbound.hasByteBuffer()) {
|
|
||||||
return directOutbound.byteBuffer();
|
|
||||||
} else {
|
|
||||||
throw new NoSuchBufferException();
|
throw new NoSuchBufferException();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ChannelBufferHolder<Object> out = ctx.outbound();
|
ChannelBufferHolder<Object> out = ctx.outbound();
|
||||||
if (out != null && !out.isBypass() && out.hasByteBuffer()) {
|
if (out != null && !out.isBypass() && out.hasByteBuffer()) {
|
||||||
@ -757,20 +724,28 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Queue<Object> nextOutboundMessageBuffer(DefaultChannelHandlerContext ctx) {
|
Queue<Object> nextOutboundMessageBuffer(Executor currentExecutor, DefaultChannelHandlerContext ctx) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
if (directOutbound.hasMessageBuffer()) {
|
|
||||||
return directOutbound.messageBuffer();
|
|
||||||
} else {
|
|
||||||
throw new NoSuchBufferException();
|
throw new NoSuchBufferException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final AtomicReference<BlockingQueue<Object>> outMsgBridge = ctx.outMsgBridge;
|
||||||
|
if (outMsgBridge != null) {
|
||||||
|
if (currentExecutor == ctx.executor()) {
|
||||||
|
return ctx.out.messageBuffer();
|
||||||
|
} else {
|
||||||
|
BlockingQueue<Object> queue = outMsgBridge.get();
|
||||||
|
if (queue == null) {
|
||||||
|
queue = QueueFactory.createQueue();
|
||||||
|
if (!outMsgBridge.compareAndSet(null, queue)) {
|
||||||
|
queue = outMsgBridge.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelBufferHolder<Object> out = ctx.outbound();
|
|
||||||
if (out != null && !out.isBypass() && out.hasMessageBuffer()) {
|
|
||||||
return out.messageBuffer();
|
|
||||||
}
|
|
||||||
ctx = ctx.prev;
|
ctx = ctx.prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -998,7 +973,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
validateFuture(future);
|
validateFuture(future);
|
||||||
|
|
||||||
if (ctx != null) {
|
|
||||||
EventExecutor executor = ctx.executor();
|
EventExecutor executor = ctx.executor();
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
try {
|
try {
|
||||||
@ -1014,9 +988,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unsafe.bind(localAddress, future);
|
|
||||||
}
|
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1036,7 +1007,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
validateFuture(future);
|
validateFuture(future);
|
||||||
|
|
||||||
if (ctx != null) {
|
|
||||||
EventExecutor executor = ctx.executor();
|
EventExecutor executor = ctx.executor();
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
try {
|
try {
|
||||||
@ -1052,9 +1022,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unsafe.connect(remoteAddress, localAddress, future);
|
|
||||||
}
|
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
@ -1066,7 +1033,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
ChannelFuture disconnect(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
ChannelFuture disconnect(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
||||||
validateFuture(future);
|
validateFuture(future);
|
||||||
if (ctx != null) {
|
|
||||||
EventExecutor executor = ctx.executor();
|
EventExecutor executor = ctx.executor();
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
try {
|
try {
|
||||||
@ -1082,9 +1048,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unsafe.disconnect(future);
|
|
||||||
}
|
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
@ -1096,7 +1059,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
ChannelFuture close(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
ChannelFuture close(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
||||||
validateFuture(future);
|
validateFuture(future);
|
||||||
if (ctx != null) {
|
|
||||||
EventExecutor executor = ctx.executor();
|
EventExecutor executor = ctx.executor();
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
try {
|
try {
|
||||||
@ -1112,9 +1074,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unsafe.close(future);
|
|
||||||
}
|
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
@ -1126,7 +1085,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
ChannelFuture deregister(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
ChannelFuture deregister(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
||||||
validateFuture(future);
|
validateFuture(future);
|
||||||
if (ctx != null) {
|
|
||||||
EventExecutor executor = ctx.executor();
|
EventExecutor executor = ctx.executor();
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
try {
|
try {
|
||||||
@ -1142,9 +1100,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unsafe.deregister(future);
|
|
||||||
}
|
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
@ -1156,7 +1111,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
ChannelFuture flush(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
ChannelFuture flush(final DefaultChannelHandlerContext ctx, final ChannelFuture future) {
|
||||||
validateFuture(future);
|
validateFuture(future);
|
||||||
if (ctx != null) {
|
|
||||||
EventExecutor executor = ctx.executor();
|
EventExecutor executor = ctx.executor();
|
||||||
if (executor.inEventLoop()) {
|
if (executor.inEventLoop()) {
|
||||||
flush0(ctx, future);
|
flush0(ctx, future);
|
||||||
@ -1168,15 +1122,13 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unsafe.flush(future);
|
|
||||||
}
|
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void flush0(final DefaultChannelHandlerContext ctx, ChannelFuture future) {
|
private void flush0(final DefaultChannelHandlerContext ctx, ChannelFuture future) {
|
||||||
try {
|
try {
|
||||||
|
ctx.flushBridge();
|
||||||
((ChannelOutboundHandler<Object>) ctx.handler()).flush(ctx, future);
|
((ChannelOutboundHandler<Object>) ctx.handler()).flush(ctx, future);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
notifyHandlerException(t);
|
notifyHandlerException(t);
|
||||||
@ -1204,17 +1156,8 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
boolean msgBuf = false;
|
boolean msgBuf = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
executor = channel.eventLoop();
|
|
||||||
out = directOutbound;
|
|
||||||
if (out.hasByteBuffer()) {
|
|
||||||
if(!(message instanceof ChannelBuffer)) {
|
|
||||||
throw new NoSuchBufferException();
|
throw new NoSuchBufferException();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
msgBuf = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.canHandleOutbound()) {
|
if (ctx.canHandleOutbound()) {
|
||||||
out = ctx.outbound();
|
out = ctx.outbound();
|
||||||
@ -1238,11 +1181,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
ChannelBuffer buf = (ChannelBuffer) message;
|
ChannelBuffer buf = (ChannelBuffer) message;
|
||||||
out.byteBuffer().writeBytes(buf, buf.readerIndex(), buf.readableBytes());
|
out.byteBuffer().writeBytes(buf, buf.readerIndex(), buf.readableBytes());
|
||||||
}
|
}
|
||||||
if (ctx != null) {
|
|
||||||
flush0(ctx, future);
|
flush0(ctx, future);
|
||||||
} else {
|
|
||||||
unsafe.flush(future);
|
|
||||||
}
|
|
||||||
return future;
|
return future;
|
||||||
} else {
|
} else {
|
||||||
final DefaultChannelHandlerContext ctx0 = ctx;
|
final DefaultChannelHandlerContext ctx0 = ctx;
|
||||||
@ -1274,7 +1213,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DefaultChannelHandlerContext firstInboundContext() {
|
private DefaultChannelHandlerContext firstInboundContext() {
|
||||||
return nextInboundContext(head);
|
return nextInboundContext(head.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DefaultChannelHandlerContext firstOutboundContext() {
|
private DefaultChannelHandlerContext firstOutboundContext() {
|
||||||
@ -1347,16 +1286,6 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
return inExceptionCaught(cause.getCause());
|
return inExceptionCaught(cause.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(EventExecutor executor, String name, ChannelHandler handler) {
|
|
||||||
DefaultChannelHandlerContext ctx =
|
|
||||||
new DefaultChannelHandlerContext(this, executor, null, null, name, handler);
|
|
||||||
callBeforeAdd(ctx);
|
|
||||||
head = tail = ctx;
|
|
||||||
name2ctx.clear();
|
|
||||||
name2ctx.put(name, ctx);
|
|
||||||
callAfterAdd(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkDuplicateName(String name) {
|
private void checkDuplicateName(String name) {
|
||||||
if (name2ctx.containsKey(name)) {
|
if (name2ctx.containsKey(name)) {
|
||||||
throw new IllegalArgumentException("Duplicate handler name: " + name);
|
throw new IllegalArgumentException("Duplicate handler name: " + name);
|
||||||
@ -1365,7 +1294,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
private DefaultChannelHandlerContext getContextOrDie(String name) {
|
private DefaultChannelHandlerContext getContextOrDie(String name) {
|
||||||
DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) context(name);
|
DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) context(name);
|
||||||
if (ctx == null) {
|
if (ctx == null || ctx == head) {
|
||||||
throw new NoSuchElementException(name);
|
throw new NoSuchElementException(name);
|
||||||
} else {
|
} else {
|
||||||
return ctx;
|
return ctx;
|
||||||
@ -1374,7 +1303,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
private DefaultChannelHandlerContext getContextOrDie(ChannelHandler handler) {
|
private DefaultChannelHandlerContext getContextOrDie(ChannelHandler handler) {
|
||||||
DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) context(handler);
|
DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) context(handler);
|
||||||
if (ctx == null) {
|
if (ctx == null || ctx == head) {
|
||||||
throw new NoSuchElementException(handler.getClass().getName());
|
throw new NoSuchElementException(handler.getClass().getName());
|
||||||
} else {
|
} else {
|
||||||
return ctx;
|
return ctx;
|
||||||
@ -1383,10 +1312,84 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
private DefaultChannelHandlerContext getContextOrDie(Class<? extends ChannelHandler> handlerType) {
|
private DefaultChannelHandlerContext getContextOrDie(Class<? extends ChannelHandler> handlerType) {
|
||||||
DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) context(handlerType);
|
DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) context(handlerType);
|
||||||
if (ctx == null) {
|
if (ctx == null || ctx == head) {
|
||||||
throw new NoSuchElementException(handlerType.getName());
|
throw new NoSuchElementException(handlerType.getName());
|
||||||
} else {
|
} else {
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private final class HeadHandler implements ChannelOutboundHandler {
|
||||||
|
@Override
|
||||||
|
public ChannelBufferHolder newOutboundBuffer(
|
||||||
|
ChannelOutboundHandlerContext ctx) throws Exception {
|
||||||
|
switch (channel.type()) {
|
||||||
|
case STREAM:
|
||||||
|
return ChannelBufferHolders.byteBuffer();
|
||||||
|
case MESSAGE:
|
||||||
|
return ChannelBufferHolders.messageBuffer();
|
||||||
|
default:
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterAdd(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterRemove(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bind(ChannelOutboundHandlerContext ctx,
|
||||||
|
SocketAddress localAddress, ChannelFuture future)
|
||||||
|
throws Exception {
|
||||||
|
unsafe.bind(localAddress, future);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(ChannelOutboundHandlerContext ctx,
|
||||||
|
SocketAddress remoteAddress, SocketAddress localAddress,
|
||||||
|
ChannelFuture future) throws Exception {
|
||||||
|
unsafe.connect(remoteAddress, localAddress, future);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(ChannelOutboundHandlerContext ctx,
|
||||||
|
ChannelFuture future) throws Exception {
|
||||||
|
unsafe.disconnect(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close(ChannelOutboundHandlerContext ctx,
|
||||||
|
ChannelFuture future) throws Exception {
|
||||||
|
unsafe.close(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deregister(ChannelOutboundHandlerContext ctx,
|
||||||
|
ChannelFuture future) throws Exception {
|
||||||
|
unsafe.deregister(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush(ChannelOutboundHandlerContext ctx,
|
||||||
|
ChannelFuture future) throws Exception {
|
||||||
|
unsafe.flush(future);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user