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 }