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.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}(new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576))); 172 * pipeline.addLast("handler", new MyBusinessLogicHandler()); 173 * </pre> 174 * 175 * <h3>Thread safety</h3> 176 * <p> 177 * A {@link ChannelHandler} can be added or removed at any time because a 178 * {@link ChannelPipeline} is thread safe. For example, you can insert a 179 * {@link SslHandler} when sensitive information is about to be exchanged, 180 * and remove it after the exchange. 181 * 182 * <h3>Pitfall</h3> 183 * <p> 184 * Due to the internal implementation detail of the current default 185 * {@link ChannelPipeline}, the following code does not work as expected if 186 * <tt>FirstHandler</tt> is the last handler in the pipeline: 187 * <pre> 188 * public class FirstHandler extends {@link SimpleChannelUpstreamHandler} { 189 * 190 * {@code @Override} 191 * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) { 192 * // Remove this handler from the pipeline, 193 * ctx.getPipeline().remove(this); 194 * // And let SecondHandler handle the current event. 195 * ctx.getPipeline().addLast("2nd", new SecondHandler()); 196 * ctx.sendUpstream(e); 197 * } 198 * } 199 * </pre> 200 * To implement the expected behavior, you have to add <tt>SecondHandler</tt> 201 * before the removal or make sure there is at least one more handler between 202 * <tt>FirstHandler</tt> and <tt>SecondHandler</tt>. 203 * 204 * @author <a href="http://www.jboss.org/netty/">The Netty Project</a> 205 * @author <a href="http://gleamynode.net/">Trustin Lee</a> 206 * 207 * @version $Rev: 2153 $, $Date: 2010-02-17 17:24:25 +0900 (Wed, 17 Feb 2010) $ 208 * 209 * @apiviz.landmark 210 * @apiviz.composedOf org.jboss.netty.channel.ChannelHandlerContext 211 * @apiviz.owns org.jboss.netty.channel.ChannelHandler 212 * @apiviz.uses org.jboss.netty.channel.ChannelSink - - sends events downstream 213 */ 214 public interface ChannelPipeline { 215 216 /** 217 * Inserts a {@link ChannelHandler} at the first position of this pipeline. 218 * 219 * @param name the name of the handler to insert first 220 * @param handler the handler to insert first 221 * 222 * @throws IllegalArgumentException 223 * if there's an entry with the same name already in the pipeline 224 * @throws NullPointerException 225 * if the specified name or handler is {@code null} 226 */ 227 void addFirst (String name, ChannelHandler handler); 228 229 /** 230 * Appends a {@link ChannelHandler} at the last position of this pipeline. 231 * 232 * @param name the name of the handler to append 233 * @param handler the handler to append 234 * 235 * @throws IllegalArgumentException 236 * if there's an entry with the same name already in the pipeline 237 * @throws NullPointerException 238 * if the specified name or handler is {@code null} 239 */ 240 void addLast (String name, ChannelHandler handler); 241 242 /** 243 * Inserts a {@link ChannelHandler} before an existing handler of this 244 * pipeline. 245 * 246 * @param baseName the name of the existing handler 247 * @param name the name of the handler to insert before 248 * @param handler the handler to insert before 249 * 250 * @throws NoSuchElementException 251 * if there's no such entry with the specified {@code baseName} 252 * @throws IllegalArgumentException 253 * if there's an entry with the same name already in the pipeline 254 * @throws NullPointerException 255 * if the specified baseName, name, or handler is {@code null} 256 */ 257 void addBefore(String baseName, String name, ChannelHandler handler); 258 259 /** 260 * Inserts a {@link ChannelHandler} after an existing handler of this 261 * pipeline. 262 * 263 * @param baseName the name of the existing handler 264 * @param name the name of the handler to insert after 265 * @param handler the handler to insert after 266 * 267 * @throws NoSuchElementException 268 * if there's no such entry with the specified {@code baseName} 269 * @throws IllegalArgumentException 270 * if there's an entry with the same name already in the pipeline 271 * @throws NullPointerException 272 * if the specified baseName, name, or handler is {@code null} 273 */ 274 void addAfter (String baseName, String name, ChannelHandler handler); 275 276 /** 277 * Removes the specified {@link ChannelHandler} from this pipeline. 278 * 279 * @throws NoSuchElementException 280 * if there's no such handler in this pipeline 281 * @throws NullPointerException 282 * if the specified handler is {@code null} 283 */ 284 void remove(ChannelHandler handler); 285 286 /** 287 * Removes the {@link ChannelHandler} with the specified name from this 288 * pipeline. 289 * 290 * @return the removed handler 291 * 292 * @throws NoSuchElementException 293 * if there's no such handler with the specified name in this pipeline 294 * @throws NullPointerException 295 * if the specified name is {@code null} 296 */ 297 ChannelHandler remove(String name); 298 299 /** 300 * Removes the {@link ChannelHandler} of the specified type from this 301 * pipeline 302 * 303 * @param <T> the type of the handler 304 * @param handlerType the type of the handler 305 * 306 * @return the removed handler 307 * 308 * @throws NoSuchElementException 309 * if there's no such handler of the specified type in this pipeline 310 * @throws NullPointerException 311 * if the specified handler type is {@code null} 312 */ 313 <T extends ChannelHandler> T remove(Class<T> handlerType); 314 315 /** 316 * Removes the first {@link ChannelHandler} in this pipeline. 317 * 318 * @return the removed handler 319 * 320 * @throws NoSuchElementException 321 * if this pipeline is empty 322 */ 323 ChannelHandler removeFirst(); 324 325 /** 326 * Removes the last {@link ChannelHandler} in this pipeline. 327 * 328 * @return the removed handler 329 * 330 * @throws NoSuchElementException 331 * if this pipeline is empty 332 */ 333 ChannelHandler removeLast(); 334 335 /** 336 * Replaces the specified {@link ChannelHandler} with a new handler in 337 * this pipeline. 338 * 339 * @throws NoSuchElementException 340 * if the specified old handler does not exist in this pipeline 341 * @throws IllegalArgumentException 342 * if a handler with the specified new name already exists in this 343 * pipeline, except for the handler to be replaced 344 * @throws NullPointerException 345 * if the specified old handler, new name, or new handler is 346 * {@code null} 347 */ 348 void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler); 349 350 /** 351 * Replaces the {@link ChannelHandler} of the specified name with a new 352 * handler in this pipeline. 353 * 354 * @return the removed handler 355 * 356 * @throws NoSuchElementException 357 * if the handler with the specified old name does not exist in this pipeline 358 * @throws IllegalArgumentException 359 * if a handler with the specified new name already exists in this 360 * pipeline, except for the handler to be replaced 361 * @throws NullPointerException 362 * if the specified old handler, new name, or new handler is 363 * {@code null} 364 */ 365 ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler); 366 367 /** 368 * Replaces the {@link ChannelHandler} of the specified type with a new 369 * handler in this pipeline. 370 * 371 * @return the removed handler 372 * 373 * @throws NoSuchElementException 374 * if the handler of the specified old handler type does not exist 375 * in this pipeline 376 * @throws IllegalArgumentException 377 * if a handler with the specified new name already exists in this 378 * pipeline, except for the handler to be replaced 379 * @throws NullPointerException 380 * if the specified old handler, new name, or new handler is 381 * {@code null} 382 */ 383 <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName, ChannelHandler newHandler); 384 385 /** 386 * Returns the first {@link ChannelHandler} in this pipeline. 387 * 388 * @return the first handler. {@code null} if this pipeline is empty. 389 */ 390 ChannelHandler getFirst(); 391 392 /** 393 * Returns the last {@link ChannelHandler} in this pipeline. 394 * 395 * @return the last handler. {@code null} if this pipeline is empty. 396 */ 397 ChannelHandler getLast(); 398 399 /** 400 * Returns the {@link ChannelHandler} with the specified name in this 401 * pipeline. 402 * 403 * @return the handler with the specified name. 404 * {@code null} if there's no such handler in this pipeline. 405 */ 406 ChannelHandler get(String name); 407 408 /** 409 * Returns the {@link ChannelHandler} of the specified type in this 410 * pipeline. 411 * 412 * @return the handler of the specified handler type. 413 * {@code null} if there's no such handler in this pipeline. 414 */ 415 <T extends ChannelHandler> T get(Class<T> handlerType); 416 417 /** 418 * Returns the context object of the specified {@link ChannelHandler} in 419 * this pipeline. 420 * 421 * @return the context object of the specified handler. 422 * {@code null} if there's no such handler in this pipeline. 423 */ 424 ChannelHandlerContext getContext(ChannelHandler handler); 425 426 /** 427 * Returns the context object of the {@link ChannelHandler} with the 428 * specified name in this pipeline. 429 * 430 * @return the context object of the handler with the specified name. 431 * {@code null} if there's no such handler in this pipeline. 432 */ 433 ChannelHandlerContext getContext(String name); 434 435 /** 436 * Returns the context object of the {@link ChannelHandler} of the 437 * specified type in this pipeline. 438 * 439 * @return the context object of the handler of the specified type. 440 * {@code null} if there's no such handler in this pipeline. 441 */ 442 ChannelHandlerContext getContext(Class<? extends ChannelHandler> handlerType); 443 444 445 /** 446 * Sends the specified {@link ChannelEvent} to the first 447 * {@link ChannelUpstreamHandler} in this pipeline. 448 * 449 * @throws NullPointerException 450 * if the specified event is {@code null} 451 */ 452 void sendUpstream(ChannelEvent e); 453 454 /** 455 * Sends the specified {@link ChannelEvent} to the last 456 * {@link ChannelDownstreamHandler} in this pipeline. 457 * 458 * @throws NullPointerException 459 * if the specified event is {@code null} 460 */ 461 void sendDownstream(ChannelEvent e); 462 463 /** 464 * Returns the {@link Channel} that this pipeline is attached to. 465 * 466 * @return the channel. {@code null} if this pipeline is not attached yet. 467 */ 468 Channel getChannel(); 469 470 /** 471 * Returns the {@link ChannelSink} that this pipeline is attached to. 472 * 473 * @return the sink. {@code null} if this pipeline is not attached yet. 474 */ 475 ChannelSink getSink(); 476 477 /** 478 * Attaches this pipeline to the specified {@link Channel} and 479 * {@link ChannelSink}. Once a pipeline is attached, it can't be detached 480 * nor attached again. 481 * 482 * @throws IllegalStateException if this pipeline is attached already 483 */ 484 void attach(Channel channel, ChannelSink sink); 485 486 /** 487 * Returns {@code true} if and only if this pipeline is attached to 488 * a {@link Channel}. 489 */ 490 boolean isAttached(); 491 492 /** 493 * Returns the {@link List} of the handler names. 494 */ 495 List<String> getNames(); 496 497 /** 498 * Converts this pipeline into an ordered {@link Map} whose keys are 499 * handler names and whose values are handlers. 500 */ 501 Map<String, ChannelHandler> toMap(); 502 }