netty5/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java
Norman Maurer 690ab563e7 Ensure ChannelHandlerContext.attr(...) and ChannelHandlerContext.hasAttr(...) has no semantic change
Motivation:

The ChannelHandlerContext.attr(...) and ChannelHandlerContext.hasAttr(...) delegated to Channel for the attributes which is a semantic change compared to 4.0 releases. We should not change the semantic to not break users applications when upgrading to 4.1.0

Modifications:

- Revert semantic change
- Mark ChannelHandlerContext.attr(...) and hasAttr(...) as @deprecated so we can remove these later

Result:

Semantic of attribute operations on ChannelHandlerContext is the same in 4.1 as in 4.0 again.
2016-05-13 15:51:58 +02:00

409 lines
12 KiB
Java

/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.DefaultAttributeMap;
import io.netty.util.ResourceLeakHint;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.StringUtil;
import java.net.SocketAddress;
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
implements ChannelHandlerContext, ResourceLeakHint {
volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
private final boolean inbound;
private final boolean outbound;
private final DefaultChannelPipeline pipeline;
private final String name;
private boolean handlerRemoved;
final ChannelHandlerInvoker invoker;
private ChannelFuture succeededFuture;
// Lazily instantiated tasks used to trigger events to a handler with different executor.
// These needs to be volatile as otherwise an other Thread may see an half initialized instance.
// See the JMM for more details
volatile Runnable invokeChannelReadCompleteTask;
volatile Runnable invokeReadTask;
volatile Runnable invokeChannelWritableStateChangedTask;
volatile Runnable invokeFlushTask;
AbstractChannelHandlerContext(
DefaultChannelPipeline pipeline, ChannelHandlerInvoker invoker,
String name, boolean inbound, boolean outbound) {
if (name == null) {
throw new NullPointerException("name");
}
this.pipeline = pipeline;
this.name = name;
this.invoker = invoker;
this.inbound = inbound;
this.outbound = outbound;
}
@Override
public Channel channel() {
return pipeline.channel();
}
@Override
public ChannelPipeline pipeline() {
return pipeline;
}
@Override
public ByteBufAllocator alloc() {
return channel().config().getAllocator();
}
@Override
public EventExecutor executor() {
return invoker().executor();
}
@Override
public String name() {
return name;
}
@Override
public ChannelHandlerContext fireChannelRegistered() {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelRegistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelUnregistered() {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelUnregistered();
return this;
}
@Override
public ChannelHandlerContext fireChannelActive() {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelActive();
return this;
}
@Override
public ChannelHandlerContext fireChannelInactive() {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelInactive();
return this;
}
@Override
public ChannelHandlerContext fireExceptionCaught(Throwable cause) {
AbstractChannelHandlerContext next = this.next;
next.invokeExceptionCaught(cause);
return this;
}
@Override
public ChannelHandlerContext fireUserEventTriggered(Object event) {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeUserEventTriggered(event);
return this;
}
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelRead(pipeline.touch(msg, next));
return this;
}
@Override
public ChannelHandlerContext fireChannelReadComplete() {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelReadComplete();
return this;
}
@Override
public ChannelHandlerContext fireChannelWritabilityChanged() {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelWritabilityChanged();
return this;
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
return bind(localAddress, newPromise());
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
return connect(remoteAddress, newPromise());
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return connect(remoteAddress, localAddress, newPromise());
}
@Override
public ChannelFuture disconnect() {
return disconnect(newPromise());
}
@Override
public ChannelFuture close() {
return close(newPromise());
}
@Override
public ChannelFuture deregister() {
return deregister(newPromise());
}
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeBind(localAddress, promise);
return promise;
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return connect(remoteAddress, null, promise);
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeConnect(remoteAddress, localAddress, promise);
return promise;
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
if (!channel().metadata().hasDisconnect()) {
return close(promise);
}
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeDisconnect(promise);
return promise;
}
@Override
public ChannelFuture close(ChannelPromise promise) {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeClose(promise);
return promise;
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeDeregister(promise);
return promise;
}
@Override
public ChannelHandlerContext read() {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeRead();
return this;
}
@Override
public ChannelFuture write(Object msg) {
return write(msg, newPromise());
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeWrite(pipeline.touch(msg, next), promise);
return promise;
}
@Override
public ChannelHandlerContext flush() {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeFlush();
return this;
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
AbstractChannelHandlerContext next = findContextOutbound();
next.invokeWriteAndFlush(pipeline.touch(msg, next), promise);
return promise;
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
return writeAndFlush(msg, newPromise());
}
@Override
public ChannelPromise newPromise() {
return new DefaultChannelPromise(channel(), executor());
}
@Override
public ChannelProgressivePromise newProgressivePromise() {
return new DefaultChannelProgressivePromise(channel(), executor());
}
@Override
public ChannelFuture newSucceededFuture() {
ChannelFuture succeededFuture = this.succeededFuture;
if (succeededFuture == null) {
this.succeededFuture = succeededFuture = new SucceededChannelFuture(channel(), executor());
}
return succeededFuture;
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
return new FailedChannelFuture(channel(), executor(), cause);
}
private AbstractChannelHandlerContext findContextInbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
return ctx;
}
private AbstractChannelHandlerContext findContextOutbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
@Override
public ChannelPromise voidPromise() {
return channel().voidPromise();
}
void setRemoved() {
handlerRemoved = true;
}
@Override
public boolean isRemoved() {
return handlerRemoved;
}
final void invokeChannelRegistered() {
invoker().invokeChannelRegistered(this);
}
final void invokeChannelUnregistered() {
invoker().invokeChannelUnregistered(this);
}
final void invokeChannelActive() {
invoker().invokeChannelActive(this);
}
final void invokeChannelInactive() {
invoker().invokeChannelInactive(this);
}
final void invokeExceptionCaught(final Throwable cause) {
invoker().invokeExceptionCaught(this, cause);
}
final void invokeUserEventTriggered(final Object event) {
invoker().invokeUserEventTriggered(this, event);
}
final void invokeChannelRead(final Object msg) {
invoker().invokeChannelRead(this, msg);
}
final void invokeChannelReadComplete() {
invoker().invokeChannelReadComplete(this);
}
final void invokeChannelWritabilityChanged() {
invoker().invokeChannelWritabilityChanged(this);
}
final void invokeBind(final SocketAddress localAddress, final ChannelPromise promise) {
invoker().invokeBind(this, localAddress, promise);
}
final void invokeConnect(final SocketAddress remoteAddress,
final SocketAddress localAddress, final ChannelPromise promise) {
invoker().invokeConnect(this, remoteAddress, localAddress, promise);
}
final void invokeDisconnect(final ChannelPromise promise) {
invoker().invokeDisconnect(this, promise);
}
final void invokeClose(final ChannelPromise promise) {
invoker().invokeClose(this, promise);
}
final void invokeDeregister(final ChannelPromise promise) {
invoker().invokeDeregister(this, promise);
}
final void invokeRead() {
invoker().invokeRead(this);
}
final void invokeWrite(final Object msg, final ChannelPromise promise) {
invoker().invokeWrite(this, msg, promise);
}
final void invokeFlush() {
invoker().invokeFlush(this);
}
final void invokeWriteAndFlush(final Object msg, final ChannelPromise promise) {
final ChannelHandlerInvoker invoker = invoker();
invoker.invokeWrite(this, msg, promise);
invoker.invokeFlush(this);
}
@Override
public ChannelHandlerInvoker invoker() {
return invoker == null ? channel().unsafe().invoker() : invoker;
}
@Override
public String toHintString() {
return '\'' + name + "' will handle the message from this point.";
}
@Override
public String toString() {
return StringUtil.simpleClassName(ChannelHandlerContext.class) + '(' + name + ", " + channel() + ')';
}
}