package org.jboss.netty.channel; import java.net.SocketAddress; import java.util.Map; import org.jboss.netty.util.internal.ConversionUtil; public final class Channels { // pipeline factory methods /** * ����һ��Ĭ�ϵ�ChannelPipeline. */ public static ChannelPipeline pipeline() { return new DefaultChannelPipeline(); } /** * Creates a new {@link ChannelPipeline} which contains the specified * {@link ChannelHandler}s. The names of the specified handlers are * generated automatically; the first handler's name is {@code "0"}, the * second handler's name is {@code "1"}, the third handler's name is * {@code "2"}, and so on. */ public static ChannelPipeline pipeline(ChannelHandler... handlers) { if (handlers == null) { throw new NullPointerException("handlers"); } ChannelPipeline newPipeline = pipeline(); for (int i = 0; i < handlers.length; i++) { ChannelHandler h = handlers[i]; if (h == null) { break; } newPipeline.addLast(ConversionUtil.toString(i), h); } return newPipeline; } /** * Creates a new ChannelPipeline which contains the same entries * with the specified pipeline. Please note that only the names and * the references of the ChannelHandlers will be copied; a new * ChannelHandler instance will never be created. * ����һ���µ�ChannelPipeline��Ҫ������ָ����pipeline������ͬ������ * ֻ��pipeline�����ֺ�Handler�����ûḴ�ƣ������ᴴ���µ�Handlerʵ�� */ public static ChannelPipeline pipeline(ChannelPipeline pipeline) { ChannelPipeline newPipeline = pipeline(); for (Map.Entry<String, ChannelHandler> e : pipeline.toMap().entrySet()) { newPipeline.addLast(e.getKey(), e.getValue()); } return newPipeline; } // ����һ��������������pipeline�����������������ͬ�������� public static ChannelPipelineFactory pipelineFactory( final ChannelPipeline pipeline) { return new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { return pipeline(pipeline); } }; } // future�������� //Ϊָ����Channel����һ������ȡ���ģ�non-cancellable��hannelFuturefor public static ChannelFuture future(Channel channel) { return future(channel, false); } //������ȡ������˼�ǣ����ص�Future���Ե�����cancel()������ȡ�������Future������IO���� public static ChannelFuture future(Channel channel, boolean cancellable) { return new DefaultChannelFuture(channel, cancellable); } /** * Creates a new {@link ChannelFuture} which is already succeeded for the * specified {@link Channel}. */ public static ChannelFuture succeededFuture(Channel channel) { if (channel instanceof AbstractChannel) { return ((AbstractChannel) channel).getSucceededFuture(); } else { return new SucceededChannelFuture(channel); } } /** * Creates a new {@link ChannelFuture} which has failed already for the * specified {@link Channel}. * * @param cause * the cause of the failure */ public static ChannelFuture failedFuture(Channel channel, Throwable cause) { return new FailedChannelFuture(channel, cause); } // event emission methods �¼����䷽�� //����"channelOpen"�¼�����ͨ������ˮ���е�һ��ChannelUpstreamHandler //������Channel��parent����ôһ��"childChannelOpen"�¼�Ҳ�ᷢ�� public static void fireChannelOpen(Channel channel) { // Notify the parent handler. if (channel.getParent() != null) { fireChildChannelStateChanged(channel.getParent(), channel); } channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE)); } /** * Sends a {@code "channelOpen"} event to the {@link ChannelUpstreamHandler} * which is placed in the closest upstream from the handler associated with * the specified {@link ChannelHandlerContext}. * <p> * Please note that this method does not trigger a * {@code "childChannelOpen"} event unlike {@link #fireChannelOpen(Channel)} * method. */ public static void fireChannelOpen(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent(ctx.getChannel(), ChannelState.OPEN, Boolean.TRUE)); } /** * ����һ��ChannelUpstreamHandler����һ��"channelBound"��״̬�¼� * ���������׽��ְ󶨳ɹ� */ public static void fireChannelBound(Channel channel, SocketAddress localAddress) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent(channel, ChannelState.BOUND, localAddress)); } /** * Sends a {@code "channelBound"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param localAddress * the local address where the specified channel is bound */ public static void fireChannelBound(ChannelHandlerContext ctx, SocketAddress localAddress) { ctx.sendUpstream(new UpstreamChannelStateEvent(ctx.getChannel(), ChannelState.BOUND, localAddress)); } /** * Sends a {@code "channelConnected"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param remoteAddress * the remote address where the specified channel is connected */ public static void fireChannelConnected(Channel channel, SocketAddress remoteAddress) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, remoteAddress)); } /** * Sends a {@code "channelConnected"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param remoteAddress * the remote address where the specified channel is connected */ public static void fireChannelConnected(ChannelHandlerContext ctx, SocketAddress remoteAddress) { ctx.sendUpstream(new UpstreamChannelStateEvent(ctx.getChannel(), ChannelState.CONNECTED, remoteAddress)); } /** * Sends a {@code "messageReceived"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param message * the received message */ public static void fireMessageReceived(Channel channel, Object message) { fireMessageReceived(channel, message, null); } /** * Sends a {@code "messageReceived"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel} belongs. * * @param message * the received message * @param remoteAddress * the remote address where the received message came from */ public static void fireMessageReceived(Channel channel, Object message, SocketAddress remoteAddress) { channel.getPipeline().sendUpstream( new UpstreamMessageEvent(channel, message, remoteAddress)); } /** * Sends a {@code "messageReceived"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param message * the received message */ public static void fireMessageReceived(ChannelHandlerContext ctx, Object message) { ctx.sendUpstream(new UpstreamMessageEvent(ctx.getChannel(), message, null)); } /** * Sends a {@code "messageReceived"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param message * the received message * @param remoteAddress * the remote address where the received message came from */ public static void fireMessageReceived(ChannelHandlerContext ctx, Object message, SocketAddress remoteAddress) { ctx.sendUpstream(new UpstreamMessageEvent(ctx.getChannel(), message, remoteAddress)); } /** * Sends a {@code "writeComplete"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel} in the next io-thread. */ public static ChannelFuture fireWriteCompleteLater(final Channel channel, final long amount) { return channel.getPipeline().execute(new Runnable() { public void run() { fireWriteComplete(channel, amount); } }); } /** * Sends a {@code "writeComplete"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. */ public static void fireWriteComplete(Channel channel, long amount) { if (amount == 0) { return; } channel.getPipeline().sendUpstream( new DefaultWriteCompletionEvent(channel, amount)); } /** * Sends a {@code "writeComplete"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) { ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount)); } /** * Sends a {@code "channelInterestChanged"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelInterestChangedLater( final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelInterestChanged(channel); } }); } /** * Sends a {@code "channelInterestChanged"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. */ public static void fireChannelInterestChanged(Channel channel) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent(channel, ChannelState.INTEREST_OPS, Channel.OP_READ)); } /** * Sends a {@code "channelInterestChanged"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelInterestChanged(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent(ctx.getChannel(), ChannelState.INTEREST_OPS, Channel.OP_READ)); } /** * Sends a {@code "channelDisconnected"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelDisconnectedLater( final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelDisconnected(channel); } }); } /** * Sends a {@code "channelDisconnected"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. */ public static void fireChannelDisconnected(Channel channel) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, null)); } /** * Sends a {@code "channelDisconnected"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelDisconnected(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent(ctx.getChannel(), ChannelState.CONNECTED, null)); } /** * Sends a {@code "channelUnbound"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelUnboundLater(final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelUnbound(channel); } }); } /** * Sends a {@code "channelUnbound"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. */ public static void fireChannelUnbound(Channel channel) { channel.getPipeline() .sendUpstream( new UpstreamChannelStateEvent(channel, ChannelState.BOUND, null)); } /** * Sends a {@code "channelUnbound"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelUnbound(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent(ctx.getChannel(), ChannelState.BOUND, null)); } /** * Sends a {@code "channelClosed"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireChannelClosedLater(final Channel channel) { return channel.getPipeline().execute(new Runnable() { public void run() { fireChannelClosed(channel); } }); } /** * Sends a {@code "channelClosed"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. */ public static void fireChannelClosed(Channel channel) { channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.FALSE)); // Notify the parent handler. if (channel.getParent() != null) { fireChildChannelStateChanged(channel.getParent(), channel); } } /** * Sends a {@code "channelClosed"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireChannelClosed(ChannelHandlerContext ctx) { ctx.sendUpstream(new UpstreamChannelStateEvent(ctx.getChannel(), ChannelState.OPEN, Boolean.FALSE)); } /** * Sends a {@code "exceptionCaught"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel} once the io-thread runs again. */ public static ChannelFuture fireExceptionCaughtLater(final Channel channel, final Throwable cause) { return channel.getPipeline().execute(new Runnable() { public void run() { fireExceptionCaught(channel, cause); } }); } /** * Sends a {@code "exceptionCaught"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext} once the io-thread runs again. */ public static ChannelFuture fireExceptionCaughtLater( final ChannelHandlerContext ctx, final Throwable cause) { return ctx.getPipeline().execute(new Runnable() { public void run() { fireExceptionCaught(ctx, cause); } }); } /** * Sends a {@code "exceptionCaught"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. */ public static void fireExceptionCaught(Channel channel, Throwable cause) { channel.getPipeline().sendUpstream( new DefaultExceptionEvent(channel, cause)); } /** * Sends a {@code "exceptionCaught"} event to the * {@link ChannelUpstreamHandler} which is placed in the closest upstream * from the handler associated with the specified * {@link ChannelHandlerContext}. */ public static void fireExceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.sendUpstream(new DefaultExceptionEvent(ctx.getChannel(), cause)); } private static void fireChildChannelStateChanged(Channel channel, Channel childChannel) { channel.getPipeline().sendUpstream( new DefaultChildChannelStateEvent(channel, childChannel)); } // ���ͨ������ˮ�ߵ����һ��handler����һ��bind���� public static ChannelFuture bind(Channel channel, SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } //����һ������ȡ����ChannelFuture ChannelFuture future = future(channel); //Ӧ���Ƿ��͸�����ʵ�ֲ�������ChannelSink��״̬ʱBOUND��ֵ��LocalAddress channel.getPipeline().sendDownstream( new DownstreamChannelStateEvent(channel, future, ChannelState.BOUND, localAddress)); return future; } /** * Sends a {@code "bind"} request to the {@link ChannelDownstreamHandler} * which is placed in the closest downstream from the handler associated * with the specified {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified when the bind operation is * done * @param localAddress * the local address to bind to */ public static void bind(ChannelHandlerContext ctx, ChannelFuture future, SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } ctx.sendDownstream(new DownstreamChannelStateEvent(ctx.getChannel(), future, ChannelState.BOUND, localAddress)); } /** * Sends a {@code "unbind"} request to the {@link ChannelDownstreamHandler} * which is placed in the closest downstream from the handler associated * with the specified {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified when the unbind operation is * done */ public static void unbind(ChannelHandlerContext ctx, ChannelFuture future) { ctx.sendDownstream(new DownstreamChannelStateEvent(ctx.getChannel(), future, ChannelState.BOUND, null)); } /** * Sends a {@code "unbind"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param channel * the channel to unbind * * @return the {@link ChannelFuture} which will be notified when the unbind * operation is done */ public static ChannelFuture unbind(Channel channel) { ChannelFuture future = future(channel); channel.getPipeline().sendDownstream( new DownstreamChannelStateEvent(channel, future, ChannelState.BOUND, null)); return future; } /** * Sends a {@code "connect"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param channel * the channel to attempt a connection * @param remoteAddress * the remote address to connect to * * @return the {@link ChannelFuture} which will be notified when the * connection attempt is done */ public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } ChannelFuture future = future(channel, true); channel.getPipeline().sendDownstream( new DownstreamChannelStateEvent(channel, future, ChannelState.CONNECTED, remoteAddress)); return future; } /** * Sends a {@code "connect"} request to the {@link ChannelDownstreamHandler} * which is placed in the closest downstream from the handler associated * with the specified {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified when the connection attempt * is done * @param remoteAddress * the remote address to connect to */ public static void connect(ChannelHandlerContext ctx, ChannelFuture future, SocketAddress remoteAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } ctx.sendDownstream(new DownstreamChannelStateEvent(ctx.getChannel(), future, ChannelState.CONNECTED, remoteAddress)); } /** * Sends a {@code "write"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param channel * the channel to write a message * @param message * the message to write to the channel * * @return the {@link ChannelFuture} which will be notified when the write * operation is done */ public static ChannelFuture write(Channel channel, Object message) { return write(channel, message, null); } /** * Sends a {@code "write"} request to the {@link ChannelDownstreamHandler} * which is placed in the closest downstream from the handler associated * with the specified {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified when the write operation is * done */ public static void write(ChannelHandlerContext ctx, ChannelFuture future, Object message) { write(ctx, future, message, null); } /** * Sends a {@code "write"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param channel * the channel to write a message * @param message * the message to write to the channel * @param remoteAddress * the destination of the message. {@code null} to use the * default remote address * * @return the {@link ChannelFuture} which will be notified when the write * operation is done */ public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) { ChannelFuture future = future(channel); channel.getPipeline().sendDownstream( new DownstreamMessageEvent(channel, future, message, remoteAddress)); return future; } /** * Sends a {@code "write"} request to the {@link ChannelDownstreamHandler} * which is placed in the closest downstream from the handler associated * with the specified {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified when the write operation is * done * @param message * the message to write to the channel * @param remoteAddress * the destination of the message. {@code null} to use the * default remote address. */ public static void write(ChannelHandlerContext ctx, ChannelFuture future, Object message, SocketAddress remoteAddress) { ctx.sendDownstream(new DownstreamMessageEvent(ctx.getChannel(), future, message, remoteAddress)); } /** * Sends a {@code "setInterestOps"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param channel * the channel to change its interestOps * @param interestOps * the new interestOps * * @return the {@link ChannelFuture} which will be notified when the * interestOps is changed */ public static ChannelFuture setInterestOps(Channel channel, int interestOps) { validateInterestOps(interestOps); interestOps = filterDownstreamInterestOps(interestOps); ChannelFuture future = future(channel); channel.getPipeline().sendDownstream( new DownstreamChannelStateEvent(channel, future, ChannelState.INTEREST_OPS, interestOps)); return future; } /** * Sends a {@code "setInterestOps"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified when the interestOps is * changed. */ public static void setInterestOps(ChannelHandlerContext ctx, ChannelFuture future, int interestOps) { validateInterestOps(interestOps); interestOps = filterDownstreamInterestOps(interestOps); ctx.sendDownstream(new DownstreamChannelStateEvent(ctx.getChannel(), future, ChannelState.INTEREST_OPS, interestOps)); } /** * Sends a {@code "disconnect"} request to the last * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of the * specified {@link Channel}. * * @param channel * the channel to disconnect * * @return the {@link ChannelFuture} which will be notified on disconnection */ public static ChannelFuture disconnect(Channel channel) { ChannelFuture future = future(channel); channel.getPipeline().sendDownstream( new DownstreamChannelStateEvent(channel, future, ChannelState.CONNECTED, null)); return future; } /** * Sends a {@code "disconnect"} request to the * {@link ChannelDownstreamHandler} which is placed in the closest * downstream from the handler associated with the specified * {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified on disconnection */ public static void disconnect(ChannelHandlerContext ctx, ChannelFuture future) { ctx.sendDownstream(new DownstreamChannelStateEvent(ctx.getChannel(), future, ChannelState.CONNECTED, null)); } // ���ͨ������ˮ�ߵ����һ��handler����һ��bind���� public static ChannelFuture close(Channel channel) { ChannelFuture future = channel.getCloseFuture(); channel.getPipeline().sendDownstream( new DownstreamChannelStateEvent(channel, future, ChannelState.OPEN, Boolean.FALSE)); return future; } /** * Sends a {@code "close"} request to the {@link ChannelDownstreamHandler} * which is placed in the closest downstream from the handler associated * with the specified {@link ChannelHandlerContext}. * * @param ctx * the context * @param future * the future which will be notified on closure */ public static void close(ChannelHandlerContext ctx, ChannelFuture future) { ctx.sendDownstream(new DownstreamChannelStateEvent(ctx.getChannel(), future, ChannelState.OPEN, Boolean.FALSE)); } private static void validateInterestOps(int interestOps) { switch (interestOps) { case Channel.OP_NONE: case Channel.OP_READ: case Channel.OP_WRITE: case Channel.OP_READ_WRITE: break; default: throw new IllegalArgumentException("Invalid interestOps: " + interestOps); } } private static int filterDownstreamInterestOps(int interestOps) { return interestOps & ~Channel.OP_WRITE; } private Channels() { // Unused } }