/* * 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.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.util.Attribute; import io.netty.util.AttributeKey; import io.netty.util.AttributeMap; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.FutureListener; import java.net.ConnectException; import java.net.SocketAddress; import java.nio.channels.Channels; /** * Enables a {@link ChannelHandler} to interact with its {@link ChannelPipeline} * and other handlers. Among other things a handler can notify the next {@link ChannelHandler} in the * {@link ChannelPipeline} as well as modify the {@link ChannelPipeline} it belongs to dynamically. * *
* public class MyHandler extends {@link ChannelHandlerAdapter} { * * private {@link ChannelHandlerContext} ctx; * * public void beforeAdd({@link ChannelHandlerContext} ctx) { * this.ctx = ctx; * } * * public void login(String username, password) { * ctx.write(new LoginMessage(username, password)); * } * ... * } ** *
* For example, the following handler will have as many independent {@link AttributeKey}s * as how many times it is added to pipelines, regardless if it is added to the * same pipeline multiple times or added to different pipelines multiple times: *
* public class FactorialHandler extends {@link ChannelHandlerAdapter} { * * private final {@link AttributeKey}<{@link Integer}> counter = {@link AttributeKey}.valueOf("counter"); * * // This handler will receive a sequence of increasing integers starting * // from 1. * {@code @Override} * public void channelRead({@link ChannelHandlerContext} ctx, Object msg) { * {@link Attribute}<{@link Integer}> attr = ctx.getAttr(counter); * Integer a = ctx.getAttr(counter).get(); * * if (a == null) { * a = 1; * } * * attr.set(a * (Integer) msg); * } * } * * // Different context objects are given to "f1", "f2", "f3", and "f4" even if * // they refer to the same handler instance. Because the FactorialHandler * // stores its state in a context object (using an {@link AttributeKey}), the factorial is * // calculated correctly 4 times once the two pipelines (p1 and p2) are active. * FactorialHandler fh = new FactorialHandler(); * * {@link ChannelPipeline} p1 = {@link Channels}.pipeline(); * p1.addLast("f1", fh); * p1.addLast("f2", fh); * * {@link ChannelPipeline} p2 = {@link Channels}.pipeline(); * p2.addLast("f3", fh); * p2.addLast("f4", fh); ** *
* Please refer to the {@link ChannelHandler}, and * {@link ChannelPipeline} to find out more about inbound and outbound operations, * what fundamental differences they have, how they flow in a pipeline, and how to handle * the operation in your application. */ public interface ChannelHandlerContext extends AttributeMap { /** * Return the {@link Channel} which is bound to the {@link ChannelHandlerContext}. */ Channel channel(); /** * Returns the {@link EventExecutor} which is used to execute an arbitrary task. */ EventExecutor executor(); /** * Returns the {@link ChannelHandlerInvoker} which is used to trigger an event for the associated * {@link ChannelHandler}. Note that the methods in {@link ChannelHandlerInvoker} are not intended to be called * by a user. Use this method only to obtain the reference to the {@link ChannelHandlerInvoker} * (and not calling its methods) unless you know what you are doing. */ ChannelHandlerInvoker invoker(); /** * The unique name of the {@link ChannelHandlerContext}.The name was used when then {@link ChannelHandler} * was added to the {@link ChannelPipeline}. This name can also be used to access the registered * {@link ChannelHandler} from the {@link ChannelPipeline}. */ String name(); /** * The {@link ChannelHandler} that is bound this {@link ChannelHandlerContext}. */ ChannelHandler handler(); /** * Return {@code true} if the {@link ChannelHandler} which belongs to this {@link ChannelHandler} was removed * from the {@link ChannelPipeline}. Note that this method is only meant to be called from with in the * {@link EventLoop}. */ boolean isRemoved(); /** * A {@link Channel} was registered to its {@link EventLoop}. * * This will result in having the {@link ChannelHandler#channelRegistered(ChannelHandlerContext)} method * called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext fireChannelRegistered(); /** * A {@link Channel} was unregistered from its {@link EventLoop}. * * This will result in having the {@link ChannelHandler#channelUnregistered(ChannelHandlerContext)} method * called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext fireChannelUnregistered(); /** * A {@link Channel} is active now, which means it is connected. * * This will result in having the {@link ChannelHandler#channelActive(ChannelHandlerContext)} method * called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext fireChannelActive(); /** * A {@link Channel} is inactive now, which means it is closed. * * This will result in having the {@link ChannelHandler#channelInactive(ChannelHandlerContext)} method * called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext fireChannelInactive(); /** * A {@link Channel} received an {@link Throwable} in one of its inbound operations. * * This will result in having the {@link ChannelHandler#exceptionCaught(ChannelHandlerContext, Throwable)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext fireExceptionCaught(Throwable cause); /** * A {@link Channel} received an user defined event. * * This will result in having the {@link ChannelHandler#userEventTriggered(ChannelHandlerContext, Object)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext fireUserEventTriggered(Object event); /** * A {@link Channel} received a message. * * This will result in having the {@link ChannelHandler#channelRead(ChannelHandlerContext, Object)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext fireChannelRead(Object msg); /** * Triggers an {@link ChannelHandler#channelWritabilityChanged(ChannelHandlerContext)} * event to the next {@link ChannelHandler} in the {@link ChannelPipeline}. */ ChannelHandlerContext fireChannelReadComplete(); /** * Triggers an {@link ChannelHandler#channelWritabilityChanged(ChannelHandlerContext)} * event to the next {@link ChannelHandler} in the {@link ChannelPipeline}. */ ChannelHandlerContext fireChannelWritabilityChanged(); /** * Request to bind to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation * completes, either because the operation was successful or because of an error. *
* This will result in having the * {@link ChannelHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method * called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture bind(SocketAddress localAddress); /** * Request to connect to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation * completes, either because the operation was successful or because of an error. *
* If the connection fails because of a connection timeout, the {@link ChannelFuture} will get failed with * a {@link ConnectTimeoutException}. If it fails because of connection refused a {@link ConnectException} * will be used. *
* This will result in having the * {@link ChannelHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress); /** * Request to connect to the given {@link SocketAddress} while bind to the localAddress and notify the * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of * an error. *
* This will result in having the * {@link ChannelHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress); /** * Request to disconnect from the remote peer and notify the {@link ChannelFuture} once the operation completes, * either because the operation was successful or because of an error. *
* This will result in having the * {@link ChannelHandler#disconnect(ChannelHandlerContext, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture disconnect(); /** * Request to close the {@link Channel} and notify the {@link ChannelFuture} once the operation completes, * either because the operation was successful or because of * an error. * * After it is closed it is not possible to reuse it again. *
* This will result in having the * {@link ChannelHandler#close(ChannelHandlerContext, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture close(); /** * Request to deregister from the previous assigned {@link EventExecutor} and notify the * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of * an error. *
* This will result in having the * {@link ChannelHandler#deregister(ChannelHandlerContext, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. * */ ChannelFuture deregister(); /** * Request to bind to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation * completes, either because the operation was successful or because of an error. * * The given {@link ChannelPromise} will be notified. *
* This will result in having the * {@link ChannelHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method * called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise); /** * Request to connect to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation * completes, either because the operation was successful or because of an error. * * The given {@link ChannelFuture} will be notified. * *
* If the connection fails because of a connection timeout, the {@link ChannelFuture} will get failed with * a {@link ConnectTimeoutException}. If it fails because of connection refused a {@link ConnectException} * will be used. *
* This will result in having the * {@link ChannelHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise); /** * Request to connect to the given {@link SocketAddress} while bind to the localAddress and notify the * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of * an error. * * The given {@link ChannelPromise} will be notified and also returned. *
* This will result in having the * {@link ChannelHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise); /** * Request to disconnect from the remote peer and notify the {@link ChannelFuture} once the operation completes, * either because the operation was successful or because of an error. * * The given {@link ChannelPromise} will be notified. *
* This will result in having the * {@link ChannelHandler#disconnect(ChannelHandlerContext, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture disconnect(ChannelPromise promise); /** * Request to close the {@link Channel} and notify the {@link ChannelFuture} once the operation completes, * either because the operation was successful or because of * an error. * * After it is closed it is not possible to reuse it again. * The given {@link ChannelPromise} will be notified. *
* This will result in having the * {@link ChannelHandler#close(ChannelHandlerContext, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture close(ChannelPromise promise); /** * Request to deregister from the previous assigned {@link EventExecutor} and notify the * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of * an error. * * The given {@link ChannelPromise} will be notified. *
* This will result in having the * {@link ChannelHandler#deregister(ChannelHandlerContext, ChannelPromise)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelFuture deregister(ChannelPromise promise); /** * Request to Read data from the {@link Channel} into the first inbound buffer, triggers an * {@link ChannelHandler#channelRead(ChannelHandlerContext, Object)} event if data was * read, and triggers a * {@link ChannelHandler#channelReadComplete(ChannelHandlerContext) channelReadComplete} event so the * handler can decide to continue reading. If there's a pending read operation already, this method does nothing. *
* This will result in having the * {@link ChannelHandler#read(ChannelHandlerContext)} * method called of the next {@link ChannelHandler} contained in the {@link ChannelPipeline} of the * {@link Channel}. */ ChannelHandlerContext read(); /** * Request to write a message via this {@link ChannelHandlerContext} through the {@link ChannelPipeline}. * This method will not request to actual flush, so be sure to call {@link #flush()} * once you want to request to flush all pending data to the actual transport. */ ChannelFuture write(Object msg); /** * Request to write a message via this {@link ChannelHandlerContext} through the {@link ChannelPipeline}. * This method will not request to actual flush, so be sure to call {@link #flush()} * once you want to request to flush all pending data to the actual transport. */ ChannelFuture write(Object msg, ChannelPromise promise); /** * Request to flush all pending messages via this ChannelOutboundInvoker. */ ChannelHandlerContext flush(); /** * Shortcut for call {@link #write(Object, ChannelPromise)} and {@link #flush()}. */ ChannelFuture writeAndFlush(Object msg, ChannelPromise promise); /** * Shortcut for call {@link #write(Object)} and {@link #flush()}. */ ChannelFuture writeAndFlush(Object msg); /** * Return the assigned {@link ChannelPipeline} */ ChannelPipeline pipeline(); /** * Return the assigned {@link ByteBufAllocator} which will be used to allocate {@link ByteBuf}s. */ ByteBufAllocator alloc(); /** * Return a new {@link ChannelPromise}. */ ChannelPromise newPromise(); /** * Return an new {@link ChannelProgressivePromise} */ ChannelProgressivePromise newProgressivePromise(); /** * Create a new {@link ChannelFuture} which is marked as succeeded already. So {@link ChannelFuture#isSuccess()} * will return {@code true}. All {@link FutureListener} added to it will be notified directly. Also * every call of blocking methods will just return without blocking. */ ChannelFuture newSucceededFuture(); /** * Create a new {@link ChannelFuture} which is marked as failed already. So {@link ChannelFuture#isSuccess()} * will return {@code false}. All {@link FutureListener} added to it will be notified directly. Also * every call of blocking methods will just return without blocking. */ ChannelFuture newFailedFuture(Throwable cause); /** * Return a special ChannelPromise which can be reused for different operations. *
* It's only supported to use * it for {@link ChannelHandlerContext#write(Object, ChannelPromise)}. *
** Be aware that the returned {@link ChannelPromise} will not support most operations and should only be used * if you want to save an object allocation for every write operation. You will not be able to detect if the * operation was complete, only if it failed as the implementation will call * {@link ChannelPipeline#fireExceptionCaught(Throwable)} in this case. *
* Be aware this is an expert feature and should be used with care! */ ChannelPromise voidPromise(); }