/* * Copyright 2011 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.ChannelBuffer; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; /** * A list of {@link ChannelHandler}s which handles or intercepts * {@link ChannelEvent}s of a {@link Channel}. {@link ChannelPipeline} * implements an advanced form of the * Intercepting * Filter pattern to give a user full control over how an event is handled * and how the {@link ChannelHandler}s in the pipeline interact with each other. * *
* The recommended way to create a new pipeline is to use the helper methods in * {@link Channels} rather than calling an individual implementation's * constructor: *
* import static io.netty.channel.{@link Channels}.*; * {@link ChannelPipeline} pipeline = pipeline(); // same with Channels.pipeline() ** *
* I/O Request * via {@link Channel} or * {@link ChannelHandlerContext} * | * +----------------------------------------+---------------+ * | ChannelPipeline | | * | \|/ | * | +----------------------+ +-----------+------------+ | * | | Upstream Handler N | | Downstream Handler 1 | | * | +----------+-----------+ +-----------+------------+ | * | /|\ | | * | | \|/ | * | +----------+-----------+ +-----------+------------+ | * | | Upstream Handler N-1 | | Downstream Handler 2 | | * | +----------+-----------+ +-----------+------------+ | * | /|\ . | * | . . | * | [ sendUpstream() ] [ sendDownstream() ] | * | [ + INBOUND data ] [ + OUTBOUND data ] | * | . . | * | . \|/ | * | +----------+-----------+ +-----------+------------+ | * | | Upstream Handler 2 | | Downstream Handler M-1 | | * | +----------+-----------+ +-----------+------------+ | * | /|\ | | * | | \|/ | * | +----------+-----------+ +-----------+------------+ | * | | Upstream Handler 1 | | Downstream Handler M | | * | +----------+-----------+ +-----------+------------+ | * | /|\ | | * +-------------+--------------------------+---------------+ * | \|/ * +-------------+--------------------------+---------------+ * | | | | * | [ Socket.read() ] [ Socket.write() ] | * | | * | Netty Internal I/O Threads (Transport Implementation) | * +--------------------------------------------------------+ ** An upstream event is handled by the upstream handlers in the bottom-up * direction as shown on the left side of the diagram. An upstream handler * usually handles the inbound data generated by the I/O thread on the bottom * of the diagram. The inbound data is often read from a remote peer via the * actual input operation such as {@link InputStream#read(byte[])}. * If an upstream event goes beyond the top upstream handler, it is discarded * silently. *
* A downstream event is handled by the downstream handler in the top-down * direction as shown on the right side of the diagram. A downstream handler * usually generates or transforms the outbound traffic such as write requests. * If a downstream event goes beyond the bottom downstream handler, it is * handled by an I/O thread associated with the {@link Channel}. The I/O thread * often performs the actual output operation such as {@link OutputStream#write(byte[])}. *
* For example, let us assume that we created the following pipeline: *
* {@link ChannelPipeline} p = {@link Channels}.pipeline(); * p.addLast("1", new UpstreamHandlerA()); * p.addLast("2", new UpstreamHandlerB()); * p.addLast("3", new DownstreamHandlerA()); * p.addLast("4", new DownstreamHandlerB()); * p.addLast("5", new UpstreamHandlerX()); ** In the example above, the class whose name starts with {@code Upstream} means * it is an upstream handler. The class whose name starts with * {@code Downstream} means it is a downstream handler. *
* In the given example configuration, the handler evaluation order is 1, 2, 3, * 4, 5 when an event goes upstream. When an event goes downstream, the order * is 5, 4, 3, 2, 1. On top of this principle, {@link ChannelPipeline} skips * the evaluation of certain handlers to shorten the stack depth: *
* A user is supposed to have one or more {@link ChannelHandler}s in a * pipeline to receive I/O events (e.g. read) and to request I/O operations * (e.g. write and close). For example, a typical server will have the following * handlers in each channel's pipeline, but your mileage may vary depending on * the complexity and characteristics of the protocol and business logic: * *
* {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()}; * pipeline.addLast("decoder", new MyProtocolDecoder()); * pipeline.addLast("encoder", new MyProtocolEncoder()); * pipeline.addLast("executor", new ExecutionHandler(...)); * pipeline.addLast("handler", new MyBusinessLogicHandler()); ** *
* A {@link ChannelHandler} can be added or removed at any time because a * {@link ChannelPipeline} is thread safe. For example, you can insert an * encryption handler when sensitive information is about to be exchanged, * and remove it after the exchange. * *
* Due to the internal implementation detail of the current default * {@link ChannelPipeline}, the following code does not work as expected if * FirstHandler is the last handler in the pipeline: *
* public class FirstHandler extends {@link SimpleChannelUpstreamHandler} { * * {@code @Override} * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) { * // Remove this handler from the pipeline, * ctx.getPipeline().remove(this); * // And let SecondHandler handle the current event. * ctx.getPipeline().addLast("2nd", new SecondHandler()); * ctx.sendUpstream(e); * } * } ** To implement the expected behavior, you have to add SecondHandler * before the removal or make sure there is at least one more handler between * FirstHandler and SecondHandler. * @apiviz.landmark * @apiviz.composedOf io.netty.channel.ChannelHandlerContext * @apiviz.owns io.netty.channel.ChannelHandler * @apiviz.uses io.netty.channel.ChannelSink - - sends events downstream */ public interface ChannelPipeline extends ChannelHandlerInvoker { /** * Inserts a {@link ChannelHandler} at the first position of this pipeline. * * @param name the name of the handler to insert first * @param handler the handler to insert first * * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified name or handler is {@code null} */ void addFirst(String name, ChannelHandler handler); /** * Appends a {@link ChannelHandler} at the last position of this pipeline. * * @param name the name of the handler to append * @param handler the handler to append * * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified name or handler is {@code null} */ void addLast(String name, ChannelHandler handler); /** * Inserts a {@link ChannelHandler} before an existing handler of this * pipeline. * * @param baseName the name of the existing handler * @param name the name of the handler to insert before * @param handler the handler to insert before * * @throws NoSuchElementException * if there's no such entry with the specified {@code baseName} * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified baseName, name, or handler is {@code null} */ void addBefore(String baseName, String name, ChannelHandler handler); /** * Inserts a {@link ChannelHandler} after an existing handler of this * pipeline. * * @param baseName the name of the existing handler * @param name the name of the handler to insert after * @param handler the handler to insert after * * @throws NoSuchElementException * if there's no such entry with the specified {@code baseName} * @throws IllegalArgumentException * if there's an entry with the same name already in the pipeline * @throws NullPointerException * if the specified baseName, name, or handler is {@code null} */ void addAfter(String baseName, String name, ChannelHandler handler); /** * Removes the specified {@link ChannelHandler} from this pipeline. * * @throws NoSuchElementException * if there's no such handler in this pipeline * @throws NullPointerException * if the specified handler is {@code null} */ void remove(ChannelHandler handler); /** * Removes the {@link ChannelHandler} with the specified name from this * pipeline. * * @return the removed handler * * @throws NoSuchElementException * if there's no such handler with the specified name in this pipeline * @throws NullPointerException * if the specified name is {@code null} */ ChannelHandler remove(String name); /** * Removes the {@link ChannelHandler} of the specified type from this * pipeline * * @param