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