1 /*
2 * Copyright 2012 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package org.jboss.netty.channel;
17
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.NoSuchElementException;
23
24 import org.jboss.netty.buffer.ChannelBuffer;
25 import org.jboss.netty.handler.execution.ExecutionHandler;
26 import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
27 import org.jboss.netty.handler.ssl.SslHandler;
28
29
30 /**
31 * A list of {@link ChannelHandler}s which handles or intercepts
32 * {@link ChannelEvent}s of a {@link Channel}. {@link ChannelPipeline}
33 * implements an advanced form of the
34 * <a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html">Intercepting
35 * Filter</a> pattern to give a user full control over how an event is handled
36 * and how the {@link ChannelHandler}s in the pipeline interact with each other.
37 *
38 * <h3>Creation of a pipeline</h3>
39 *
40 * For each new channel, a new pipeline must be created and attached to the
41 * channel. Once attached, the coupling between the channel and the pipeline
42 * is permanent; the channel cannot attach another pipeline to it nor detach
43 * the current pipeline from it.
44 * <p>
45 * The recommended way to create a new pipeline is to use the helper methods in
46 * {@link Channels} rather than calling an individual implementation's
47 * constructor:
48 * <pre>
49 * import static org.jboss.netty.channel.{@link Channels}.*;
50 * {@link ChannelPipeline} pipeline = pipeline(); // same with Channels.pipeline()
51 * </pre>
52 *
53 * <h3>How an event flows in a pipeline</h3>
54 *
55 * The following diagram describes how {@link ChannelEvent}s are processed by
56 * {@link ChannelHandler}s in a {@link ChannelPipeline} typically.
57 * A {@link ChannelEvent} can be handled by either a {@link ChannelUpstreamHandler}
58 * or a {@link ChannelDownstreamHandler} and be forwarded to the closest
59 * handler by calling {@link ChannelHandlerContext#sendUpstream(ChannelEvent)}
60 * or {@link ChannelHandlerContext#sendDownstream(ChannelEvent)}. The meaning
61 * of the event is interpreted somewhat differently depending on whether it is
62 * going upstream or going downstream. Please refer to {@link ChannelEvent} for
63 * more information.
64 * <pre>
65 * I/O Request
66 * via {@link Channel} or
67 * {@link ChannelHandlerContext}
68 * |
69 * +----------------------------------------+---------------+
70 * | ChannelPipeline | |
71 * | \|/ |
72 * | +----------------------+ +-----------+------------+ |
73 * | | Upstream Handler N | | Downstream Handler 1 | |
74 * | +----------+-----------+ +-----------+------------+ |
75 * | /|\ | |
76 * | | \|/ |
77 * | +----------+-----------+ +-----------+------------+ |
78 * | | Upstream Handler N-1 | | Downstream Handler 2 | |
79 * | +----------+-----------+ +-----------+------------+ |
80 * | /|\ . |
81 * | . . |
82 * | [ sendUpstream() ] [ sendDownstream() ] |
83 * | [ + INBOUND data ] [ + OUTBOUND data ] |
84 * | . . |
85 * | . \|/ |
86 * | +----------+-----------+ +-----------+------------+ |
87 * | | Upstream Handler 2 | | Downstream Handler M-1 | |
88 * | +----------+-----------+ +-----------+------------+ |
89 * | /|\ | |
90 * | | \|/ |
91 * | +----------+-----------+ +-----------+------------+ |
92 * | | Upstream Handler 1 | | Downstream Handler M | |
93 * | +----------+-----------+ +-----------+------------+ |
94 * | /|\ | |
95 * +-------------+--------------------------+---------------+
96 * | \|/
97 * +-------------+--------------------------+---------------+
98 * | | | |
99 * | [ Socket.read() ] [ Socket.write() ] |
100 * | |
101 * | Netty Internal I/O Threads (Transport Implementation) |
102 * +--------------------------------------------------------+
103 * </pre>
104 * An upstream event is handled by the upstream handlers in the bottom-up
105 * direction as shown on the left side of the diagram. An upstream handler
106 * usually handles the inbound data generated by the I/O thread on the bottom
107 * of the diagram. The inbound data is often read from a remote peer via the
108 * actual input operation such as {@link InputStream#read(byte[])}.
109 * If an upstream event goes beyond the top upstream handler, it is discarded
110 * silently.
111 * <p>
112 * A downstream event is handled by the downstream handler in the top-down
113 * direction as shown on the right side of the diagram. A downstream handler
114 * usually generates or transforms the outbound traffic such as write requests.
115 * If a downstream event goes beyond the bottom downstream handler, it is
116 * handled by an I/O thread associated with the {@link Channel}. The I/O thread
117 * often performs the actual output operation such as {@link OutputStream#write(byte[])}.
118 * <p>
119 * For example, let us assume that we created the following pipeline:
120 * <pre>
121 * {@link ChannelPipeline} p = {@link Channels}.pipeline();
122 * p.addLast("1", new UpstreamHandlerA());
123 * p.addLast("2", new UpstreamHandlerB());
124 * p.addLast("3", new DownstreamHandlerA());
125 * p.addLast("4", new DownstreamHandlerB());
126 * p.addLast("5", new UpstreamHandlerX());
127 * </pre>
128 * In the example above, the class whose name starts with {@code Upstream} means
129 * it is an upstream handler. The class whose name starts with
130 * {@code Downstream} means it is a downstream handler.
131 * <p>
132 * In the given example configuration, the handler evaluation order is 1, 2, 3,
133 * 4, 5 when an event goes upstream. When an event goes downstream, the order
134 * is 5, 4, 3, 2, 1. On top of this principle, {@link ChannelPipeline} skips
135 * the evaluation of certain handlers to shorten the stack depth:
136 * <ul>
137 * <li>3 and 4 don't implement {@link ChannelUpstreamHandler}, and therefore the
138 * actual evaluation order of an upstream event will be: 1, 2, and 5.</li>
139 * <li>1, 2, and 5 don't implement {@link ChannelDownstreamHandler}, and
140 * therefore the actual evaluation order of a downstream event will be:
141 * 4 and 3.</li>
142 * <li>If 5 extended {@link SimpleChannelHandler} which implements both
143 * {@link ChannelUpstreamHandler} and {@link ChannelDownstreamHandler}, the
144 * evaluation order of an upstream and a downstream event could be 125 and
145 * 543 respectively.</li>
146 * </ul>
147 *
148 * <h3>Building a pipeline</h3>
149 * <p>
150 * A user is supposed to have one or more {@link ChannelHandler}s in a
151 * pipeline to receive I/O events (e.g. read) and to request I/O operations
152 * (e.g. write and close). For example, a typical server will have the following
153 * handlers in each channel's pipeline, but your mileage may vary depending on
154 * the complexity and characteristics of the protocol and business logic:
155 *
156 * <ol>
157 * <li>Protocol Decoder - translates binary data (e.g. {@link ChannelBuffer})
158 * into a Java object.</li>
159 * <li>Protocol Encoder - translates a Java object into binary data.</li>
160 * <li>{@link ExecutionHandler} - applies a thread model.</li>
161 * <li>Business Logic Handler - performs the actual business logic
162 * (e.g. database access).</li>
163 * </ol>
164 *
165 * and it could be represented as shown in the following example:
166 *
167 * <pre>
168 * {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()};
169 * pipeline.addLast("decoder", new MyProtocolDecoder());
170 * pipeline.addLast("encoder", new MyProtocolEncoder());
171 * pipeline.addLast("executor", new {@link ExecutionHandler}(
172 * new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576)));
173 * pipeline.addLast("handler", new MyBusinessLogicHandler());
174 * </pre>
175 *
176 * <h3>Thread safety</h3>
177 * <p>
178 * A {@link ChannelHandler} can be added or removed at any time because a
179 * {@link ChannelPipeline} is thread safe. For example, you can insert a
180 * {@link SslHandler} when sensitive information is about to be exchanged,
181 * and remove it after the exchange.
182 *
183 * <h3>Pitfall</h3>
184 * <p>
185 * Due to the internal implementation detail of the current default
186 * {@link ChannelPipeline}, the following code does not work as expected if
187 * <tt>FirstHandler</tt> is the last handler in the pipeline:
188 * <pre>
189 * public class FirstHandler extends {@link SimpleChannelUpstreamHandler} {
190 *
191 * {@code @Override}
192 * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
193 * // Remove this handler from the pipeline,
194 * ctx.getPipeline().remove(this);
195 * // And let SecondHandler handle the current event.
196 * ctx.getPipeline().addLast("2nd", new SecondHandler());
197 * ctx.sendUpstream(e);
198 * }
199 * }
200 * </pre>
201 * To implement the expected behavior, you have to add <tt>SecondHandler</tt>
202 * before the removal or make sure there is at least one more handler between
203 * <tt>FirstHandler</tt> and <tt>SecondHandler</tt>.
204 *
205 * @apiviz.landmark
206 * @apiviz.composedOf org.jboss.netty.channel.ChannelHandlerContext
207 * @apiviz.owns org.jboss.netty.channel.ChannelHandler
208 * @apiviz.uses org.jboss.netty.channel.ChannelSink - - sends events downstream
209 */
210 public interface ChannelPipeline {
211
212 /**
213 * Inserts a {@link ChannelHandler} at the first position of this pipeline.
214 *
215 * @param name the name of the handler to insert first
216 * @param handler the handler to insert first
217 *
218 * @throws IllegalArgumentException
219 * if there's an entry with the same name already in the pipeline
220 * @throws NullPointerException
221 * if the specified name or handler is {@code null}
222 */
223 void addFirst(String name, ChannelHandler handler);
224
225 /**
226 * Appends a {@link ChannelHandler} at the last position of this pipeline.
227 *
228 * @param name the name of the handler to append
229 * @param handler the handler to append
230 *
231 * @throws IllegalArgumentException
232 * if there's an entry with the same name already in the pipeline
233 * @throws NullPointerException
234 * if the specified name or handler is {@code null}
235 */
236 void addLast(String name, ChannelHandler handler);
237
238 /**
239 * Inserts a {@link ChannelHandler} before an existing handler of this
240 * pipeline.
241 *
242 * @param baseName the name of the existing handler
243 * @param name the name of the handler to insert before
244 * @param handler the handler to insert before
245 *
246 * @throws NoSuchElementException
247 * if there's no such entry with the specified {@code baseName}
248 * @throws IllegalArgumentException
249 * if there's an entry with the same name already in the pipeline
250 * @throws NullPointerException
251 * if the specified baseName, name, or handler is {@code null}
252 */
253 void addBefore(String baseName, String name, ChannelHandler handler);
254
255 /**
256 * Inserts a {@link ChannelHandler} after an existing handler of this
257 * pipeline.
258 *
259 * @param baseName the name of the existing handler
260 * @param name the name of the handler to insert after
261 * @param handler the handler to insert after
262 *
263 * @throws NoSuchElementException
264 * if there's no such entry with the specified {@code baseName}
265 * @throws IllegalArgumentException
266 * if there's an entry with the same name already in the pipeline
267 * @throws NullPointerException
268 * if the specified baseName, name, or handler is {@code null}
269 */
270 void addAfter(String baseName, String name, ChannelHandler handler);
271
272 /**
273 * Removes the specified {@link ChannelHandler} from this pipeline.
274 *
275 * @throws NoSuchElementException
276 * if there's no such handler in this pipeline
277 * @throws NullPointerException
278 * if the specified handler is {@code null}
279 */
280 void remove(ChannelHandler handler);
281
282 /**
283 * Removes the {@link ChannelHandler} with the specified name from this
284 * pipeline.
285 *
286 * @return the removed handler
287 *
288 * @throws NoSuchElementException
289 * if there's no such handler with the specified name in this pipeline
290 * @throws NullPointerException
291 * if the specified name is {@code null}
292 */
293 ChannelHandler remove(String name);
294
295 /**
296 * Removes the {@link ChannelHandler} of the specified type from this
297 * pipeline
298 *
299 * @param <T> the type of the handler
300 * @param handlerType the type of the handler
301 *
302 * @return the removed handler
303 *
304 * @throws NoSuchElementException
305 * if there's no such handler of the specified type in this pipeline
306 * @throws NullPointerException
307 * if the specified handler type is {@code null}
308 */
309 <T extends ChannelHandler> T remove(Class<T> handlerType);
310
311 /**
312 * Removes the first {@link ChannelHandler} in this pipeline.
313 *
314 * @return the removed handler
315 *
316 * @throws NoSuchElementException
317 * if this pipeline is empty
318 */
319 ChannelHandler removeFirst();
320
321 /**
322 * Removes the last {@link ChannelHandler} in this pipeline.
323 *
324 * @return the removed handler
325 *
326 * @throws NoSuchElementException
327 * if this pipeline is empty
328 */
329 ChannelHandler removeLast();
330
331 /**
332 * Replaces the specified {@link ChannelHandler} with a new handler in
333 * this pipeline.
334 *
335 * @throws NoSuchElementException
336 * if the specified old handler does not exist in this pipeline
337 * @throws IllegalArgumentException
338 * if a handler with the specified new name already exists in this
339 * pipeline, except for the handler to be replaced
340 * @throws NullPointerException
341 * if the specified old handler, new name, or new handler is
342 * {@code null}
343 */
344 void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
345
346 /**
347 * Replaces the {@link ChannelHandler} of the specified name with a new
348 * handler in this pipeline.
349 *
350 * @return the removed handler
351 *
352 * @throws NoSuchElementException
353 * if the handler with the specified old name does not exist in this pipeline
354 * @throws IllegalArgumentException
355 * if a handler with the specified new name already exists in this
356 * pipeline, except for the handler to be replaced
357 * @throws NullPointerException
358 * if the specified old handler, new name, or new handler is
359 * {@code null}
360 */
361 ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
362
363 /**
364 * Replaces the {@link ChannelHandler} of the specified type with a new
365 * handler in this pipeline.
366 *
367 * @return the removed handler
368 *
369 * @throws NoSuchElementException
370 * if the handler of the specified old handler type does not exist
371 * in this pipeline
372 * @throws IllegalArgumentException
373 * if a handler with the specified new name already exists in this
374 * pipeline, except for the handler to be replaced
375 * @throws NullPointerException
376 * if the specified old handler, new name, or new handler is
377 * {@code null}
378 */
379 <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName, ChannelHandler newHandler);
380
381 /**
382 * Returns the first {@link ChannelHandler} in this pipeline.
383 *
384 * @return the first handler. {@code null} if this pipeline is empty.
385 */
386 ChannelHandler getFirst();
387
388 /**
389 * Returns the last {@link ChannelHandler} in this pipeline.
390 *
391 * @return the last handler. {@code null} if this pipeline is empty.
392 */
393 ChannelHandler getLast();
394
395 /**
396 * Returns the {@link ChannelHandler} with the specified name in this
397 * pipeline.
398 *
399 * @return the handler with the specified name.
400 * {@code null} if there's no such handler in this pipeline.
401 */
402 ChannelHandler get(String name);
403
404 /**
405 * Returns the {@link ChannelHandler} of the specified type in this
406 * pipeline.
407 *
408 * @return the handler of the specified handler type.
409 * {@code null} if there's no such handler in this pipeline.
410 */
411 <T extends ChannelHandler> T get(Class<T> handlerType);
412
413 /**
414 * Returns the context object of the specified {@link ChannelHandler} in
415 * this pipeline.
416 *
417 * @return the context object of the specified handler.
418 * {@code null} if there's no such handler in this pipeline.
419 */
420 ChannelHandlerContext getContext(ChannelHandler handler);
421
422 /**
423 * Returns the context object of the {@link ChannelHandler} with the
424 * specified name in this pipeline.
425 *
426 * @return the context object of the handler with the specified name.
427 * {@code null} if there's no such handler in this pipeline.
428 */
429 ChannelHandlerContext getContext(String name);
430
431 /**
432 * Returns the context object of the {@link ChannelHandler} of the
433 * specified type in this pipeline.
434 *
435 * @return the context object of the handler of the specified type.
436 * {@code null} if there's no such handler in this pipeline.
437 */
438 ChannelHandlerContext getContext(Class<? extends ChannelHandler> handlerType);
439
440 /**
441 * Sends the specified {@link ChannelEvent} to the first
442 * {@link ChannelUpstreamHandler} in this pipeline.
443 *
444 * @throws NullPointerException
445 * if the specified event is {@code null}
446 */
447 void sendUpstream(ChannelEvent e);
448
449 /**
450 * Sends the specified {@link ChannelEvent} to the last
451 * {@link ChannelDownstreamHandler} in this pipeline.
452 *
453 * @throws NullPointerException
454 * if the specified event is {@code null}
455 */
456 void sendDownstream(ChannelEvent e);
457
458 /**
459 * Schedules the specified task to be executed in the I/O thread associated
460 * with this pipeline's {@link Channel}.
461 */
462 ChannelFuture execute(Runnable task);
463
464 /**
465 * Returns the {@link Channel} that this pipeline is attached to.
466 *
467 * @return the channel. {@code null} if this pipeline is not attached yet.
468 */
469 Channel getChannel();
470
471 /**
472 * Returns the {@link ChannelSink} that this pipeline is attached to.
473 *
474 * @return the sink. {@code null} if this pipeline is not attached yet.
475 */
476 ChannelSink getSink();
477
478 /**
479 * Attaches this pipeline to the specified {@link Channel} and
480 * {@link ChannelSink}. Once a pipeline is attached, it can't be detached
481 * nor attached again.
482 *
483 * @throws IllegalStateException if this pipeline is attached already
484 */
485 void attach(Channel channel, ChannelSink sink);
486
487 /**
488 * Returns {@code true} if and only if this pipeline is attached to
489 * a {@link Channel}.
490 */
491 boolean isAttached();
492
493 /**
494 * Returns the {@link List} of the handler names.
495 */
496 List<String> getNames();
497
498 /**
499 * Converts this pipeline into an ordered {@link Map} whose keys are
500 * handler names and whose values are handlers.
501 */
502 Map<String, ChannelHandler> toMap();
503 }