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.net.SocketAddress;
19 import java.util.Map;
20
21 import org.jboss.netty.util.internal.ConversionUtil;
22
23
24 /**
25 * A helper class which provides various convenience methods related with
26 * {@link Channel}, {@link ChannelHandler}, and {@link ChannelPipeline}.
27 *
28 * <h3>Factory methods</h3>
29 * <p>
30 * It is always recommended to use the factory methods provided by
31 * {@link Channels} rather than calling the constructor of the implementation
32 * types.
33 * <ul>
34 * <li>{@link #pipeline()}</li>
35 * <li>{@link #pipeline(ChannelPipeline)}</li>
36 * <li>{@link #pipelineFactory(ChannelPipeline)}</li>
37 * <li>{@link #succeededFuture(Channel)}</li>
38 * <li>{@link #failedFuture(Channel, Throwable)}</li>
39 * </ul>
40 *
41 * <h3>Upstream and downstream event generation</h3>
42 * <p>
43 * Various event generation methods are provided to simplify the generation of
44 * upstream events and downstream events. It is always recommended to use the
45 * event generation methods provided by {@link Channels} rather than calling
46 * {@link ChannelHandlerContext#sendUpstream(ChannelEvent)} or
47 * {@link ChannelHandlerContext#sendDownstream(ChannelEvent)} by yourself.
48 * @apiviz.landmark
49 */
50 public final class Channels {
51
52 // pipeline factory methods
53
54 /**
55 * Creates a new {@link ChannelPipeline}.
56 */
57 public static ChannelPipeline pipeline() {
58 return new DefaultChannelPipeline();
59 }
60
61 /**
62 * Creates a new {@link ChannelPipeline} which contains the specified
63 * {@link ChannelHandler}s. The names of the specified handlers are
64 * generated automatically; the first handler's name is {@code "0"},
65 * the second handler's name is {@code "1"}, the third handler's name is
66 * {@code "2"}, and so on.
67 */
68 public static ChannelPipeline pipeline(ChannelHandler... handlers) {
69 if (handlers == null) {
70 throw new NullPointerException("handlers");
71 }
72
73 ChannelPipeline newPipeline = pipeline();
74 for (int i = 0; i < handlers.length; i ++) {
75 ChannelHandler h = handlers[i];
76 if (h == null) {
77 break;
78 }
79 newPipeline.addLast(ConversionUtil.toString(i), h);
80 }
81 return newPipeline;
82 }
83
84 /**
85 * Creates a new {@link ChannelPipeline} which contains the same entries
86 * with the specified {@code pipeline}. Please note that only the names
87 * and the references of the {@link ChannelHandler}s will be copied; a new
88 * {@link ChannelHandler} instance will never be created.
89 */
90 public static ChannelPipeline pipeline(ChannelPipeline pipeline) {
91 ChannelPipeline newPipeline = pipeline();
92 for (Map.Entry<String, ChannelHandler> e: pipeline.toMap().entrySet()) {
93 newPipeline.addLast(e.getKey(), e.getValue());
94 }
95 return newPipeline;
96 }
97
98 /**
99 * Creates a new {@link ChannelPipelineFactory} which creates a new
100 * {@link ChannelPipeline} which contains the same entries with the
101 * specified {@code pipeline}. Please note that only the names and the
102 * references of the {@link ChannelHandler}s will be copied; a new
103 * {@link ChannelHandler} instance will never be created.
104 */
105 public static ChannelPipelineFactory pipelineFactory(
106 final ChannelPipeline pipeline) {
107 return new ChannelPipelineFactory() {
108 public ChannelPipeline getPipeline() {
109 return pipeline(pipeline);
110 }
111 };
112 }
113
114 // future factory methods
115
116 /**
117 * Creates a new non-cancellable {@link ChannelFuture} for the specified
118 * {@link Channel}.
119 */
120 public static ChannelFuture future(Channel channel) {
121 return future(channel, false);
122 }
123
124 /**
125 * Creates a new {@link ChannelFuture} for the specified {@link Channel}.
126 *
127 * @param cancellable {@code true} if and only if the returned future
128 * can be canceled by {@link ChannelFuture#cancel()}
129 */
130 public static ChannelFuture future(Channel channel, boolean cancellable) {
131 return new DefaultChannelFuture(channel, cancellable);
132 }
133
134 /**
135 * Creates a new {@link ChannelFuture} which is already succeeded for the
136 * specified {@link Channel}.
137 */
138 public static ChannelFuture succeededFuture(Channel channel) {
139 if (channel instanceof AbstractChannel) {
140 return ((AbstractChannel) channel).getSucceededFuture();
141 } else {
142 return new SucceededChannelFuture(channel);
143 }
144 }
145
146 /**
147 * Creates a new {@link ChannelFuture} which has failed already for the
148 * specified {@link Channel}.
149 *
150 * @param cause the cause of the failure
151 */
152 public static ChannelFuture failedFuture(Channel channel, Throwable cause) {
153 return new FailedChannelFuture(channel, cause);
154 }
155
156 // event emission methods
157
158 /**
159 * Sends a {@code "channelOpen"} event to the first
160 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
161 * the specified {@link Channel}. If the specified channel has a parent,
162 * a {@code "childChannelOpen"} event will be sent, too.
163 */
164 public static void fireChannelOpen(Channel channel) {
165 // Notify the parent handler.
166 if (channel.getParent() != null) {
167 fireChildChannelStateChanged(channel.getParent(), channel);
168 }
169
170 channel.getPipeline().sendUpstream(
171 new UpstreamChannelStateEvent(
172 channel, ChannelState.OPEN, Boolean.TRUE));
173 }
174
175 /**
176 * Sends a {@code "channelOpen"} event to the
177 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
178 * from the handler associated with the specified
179 * {@link ChannelHandlerContext}.
180 * <p>
181 * Please note that this method does not trigger a
182 * {@code "childChannelOpen"} event unlike {@link #fireChannelOpen(Channel)}
183 * method.
184 */
185 public static void fireChannelOpen(ChannelHandlerContext ctx) {
186 ctx.sendUpstream(new UpstreamChannelStateEvent(
187 ctx.getChannel(), ChannelState.OPEN, Boolean.TRUE));
188 }
189
190 /**
191 * Sends a {@code "channelBound"} event to the first
192 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
193 * the specified {@link Channel}.
194 *
195 * @param localAddress
196 * the local address where the specified channel is bound
197 */
198 public static void fireChannelBound(Channel channel, SocketAddress localAddress) {
199 channel.getPipeline().sendUpstream(
200 new UpstreamChannelStateEvent(
201 channel, ChannelState.BOUND, localAddress));
202 }
203
204 /**
205 * Sends a {@code "channelBound"} event to the
206 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
207 * from the handler associated with the specified
208 * {@link ChannelHandlerContext}.
209 *
210 * @param localAddress
211 * the local address where the specified channel is bound
212 */
213 public static void fireChannelBound(ChannelHandlerContext ctx, SocketAddress localAddress) {
214 ctx.sendUpstream(new UpstreamChannelStateEvent(
215 ctx.getChannel(), ChannelState.BOUND, localAddress));
216 }
217
218 /**
219 * Sends a {@code "channelConnected"} event to the first
220 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
221 * the specified {@link Channel}.
222 *
223 * @param remoteAddress
224 * the remote address where the specified channel is connected
225 */
226 public static void fireChannelConnected(Channel channel, SocketAddress remoteAddress) {
227 channel.getPipeline().sendUpstream(
228 new UpstreamChannelStateEvent(
229 channel, ChannelState.CONNECTED, remoteAddress));
230 }
231
232 /**
233 * Sends a {@code "channelConnected"} event to the
234 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
235 * from the handler associated with the specified
236 * {@link ChannelHandlerContext}.
237 *
238 * @param remoteAddress
239 * the remote address where the specified channel is connected
240 */
241 public static void fireChannelConnected(ChannelHandlerContext ctx, SocketAddress remoteAddress) {
242
243 ctx.sendUpstream(new UpstreamChannelStateEvent(
244 ctx.getChannel(), ChannelState.CONNECTED, remoteAddress));
245 }
246
247 /**
248 * Sends a {@code "messageReceived"} event to the first
249 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
250 * the specified {@link Channel}.
251 *
252 * @param message the received message
253 */
254 public static void fireMessageReceived(Channel channel, Object message) {
255 fireMessageReceived(channel, message, null);
256 }
257
258 /**
259 * Sends a {@code "messageReceived"} event to the first
260 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
261 * the specified {@link Channel} belongs.
262 *
263 * @param message the received message
264 * @param remoteAddress the remote address where the received message
265 * came from
266 */
267 public static void fireMessageReceived(Channel channel, Object message, SocketAddress remoteAddress) {
268 channel.getPipeline().sendUpstream(
269 new UpstreamMessageEvent(channel, message, remoteAddress));
270 }
271
272 /**
273 * Sends a {@code "messageReceived"} event to the
274 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
275 * from the handler associated with the specified
276 * {@link ChannelHandlerContext}.
277 *
278 * @param message the received message
279 */
280 public static void fireMessageReceived(ChannelHandlerContext ctx, Object message) {
281 ctx.sendUpstream(new UpstreamMessageEvent(ctx.getChannel(), message, null));
282 }
283
284 /**
285 * Sends a {@code "messageReceived"} event to the
286 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
287 * from the handler associated with the specified
288 * {@link ChannelHandlerContext}.
289 *
290 * @param message the received message
291 * @param remoteAddress the remote address where the received message
292 * came from
293 */
294 public static void fireMessageReceived(
295 ChannelHandlerContext ctx, Object message, SocketAddress remoteAddress) {
296 ctx.sendUpstream(new UpstreamMessageEvent(
297 ctx.getChannel(), message, remoteAddress));
298 }
299
300 /**
301 * Sends a {@code "writeComplete"} event to the first
302 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
303 * the specified {@link Channel} in the next io-thread.
304 */
305 public static ChannelFuture fireWriteCompleteLater(final Channel channel, final long amount) {
306 return channel.getPipeline().execute(new Runnable() {
307
308 public void run() {
309 fireWriteComplete(channel, amount);
310 }
311 });
312
313 }
314
315
316 /**
317 * Sends a {@code "writeComplete"} event to the first
318 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
319 * the specified {@link Channel}.
320 */
321 public static void fireWriteComplete(Channel channel, long amount) {
322 if (amount == 0) {
323 return;
324 }
325
326 channel.getPipeline().sendUpstream(
327 new DefaultWriteCompletionEvent(channel, amount));
328 }
329
330 /**
331 * Sends a {@code "writeComplete"} event to the
332 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
333 * from the handler associated with the specified
334 * {@link ChannelHandlerContext}.
335 */
336 public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) {
337 ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount));
338 }
339
340 /**
341 * Sends a {@code "channelInterestChanged"} event to the first
342 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
343 * the specified {@link Channel} once the io-thread runs again.
344 */
345 public static ChannelFuture fireChannelInterestChangedLater(final Channel channel) {
346 return channel.getPipeline().execute(new Runnable() {
347
348 public void run() {
349 fireChannelInterestChanged(channel);
350
351 }
352 });
353 }
354
355 /**
356 * Sends a {@code "channelInterestChanged"} event to the first
357 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
358 * the specified {@link Channel}.
359 */
360 public static void fireChannelInterestChanged(Channel channel) {
361 channel.getPipeline().sendUpstream(
362 new UpstreamChannelStateEvent(
363 channel, ChannelState.INTEREST_OPS, Channel.OP_READ));
364 }
365
366 /**
367 * Sends a {@code "channelInterestChanged"} event to the
368 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
369 * from the handler associated with the specified
370 * {@link ChannelHandlerContext}.
371 */
372 public static void fireChannelInterestChanged(
373 ChannelHandlerContext ctx) {
374
375 ctx.sendUpstream(
376 new UpstreamChannelStateEvent(
377 ctx.getChannel(), ChannelState.INTEREST_OPS, Channel.OP_READ));
378 }
379
380 /**
381 * Sends a {@code "channelDisconnected"} event to the first
382 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
383 * the specified {@link Channel} once the io-thread runs again.
384 */
385 public static ChannelFuture fireChannelDisconnectedLater(final Channel channel) {
386 return channel.getPipeline().execute(new Runnable() {
387
388 public void run() {
389 fireChannelDisconnected(channel);
390 }
391 });
392 }
393 /**
394 * Sends a {@code "channelDisconnected"} event to the first
395 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
396 * the specified {@link Channel}.
397 */
398 public static void fireChannelDisconnected(Channel channel) {
399 channel.getPipeline().sendUpstream(
400 new UpstreamChannelStateEvent(
401 channel, ChannelState.CONNECTED, null));
402 }
403
404 /**
405 * Sends a {@code "channelDisconnected"} event to the
406 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
407 * from the handler associated with the specified
408 * {@link ChannelHandlerContext}.
409 */
410 public static void fireChannelDisconnected(ChannelHandlerContext ctx) {
411 ctx.sendUpstream(new UpstreamChannelStateEvent(
412 ctx.getChannel(), ChannelState.CONNECTED, null));
413 }
414
415 /**
416 * Sends a {@code "channelUnbound"} event to the first
417 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
418 * the specified {@link Channel} once the io-thread runs again.
419 */
420 public static ChannelFuture fireChannelUnboundLater(final Channel channel) {
421 return channel.getPipeline().execute(new Runnable() {
422
423 public void run() {
424 fireChannelUnbound(channel);
425 }
426 });
427 }
428
429
430 /**
431 * Sends a {@code "channelUnbound"} event to the first
432 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
433 * the specified {@link Channel}.
434 */
435 public static void fireChannelUnbound(Channel channel) {
436 channel.getPipeline().sendUpstream(new UpstreamChannelStateEvent(
437 channel, ChannelState.BOUND, null));
438 }
439
440 /**
441 * Sends a {@code "channelUnbound"} event to the
442 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
443 * from the handler associated with the specified
444 * {@link ChannelHandlerContext}.
445 */
446 public static void fireChannelUnbound(ChannelHandlerContext ctx) {
447
448 ctx.sendUpstream(new UpstreamChannelStateEvent(
449 ctx.getChannel(), ChannelState.BOUND, null));
450 }
451
452
453
454 /**
455 * Sends a {@code "channelClosed"} event to the first
456 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
457 * the specified {@link Channel} once the io-thread runs again.
458 */
459 public static ChannelFuture fireChannelClosedLater(final Channel channel) {
460 return channel.getPipeline().execute(new Runnable() {
461
462 public void run() {
463 fireChannelClosed(channel);
464 }
465 });
466
467 }
468
469
470 /**
471 * Sends a {@code "channelClosed"} event to the first
472 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
473 * the specified {@link Channel}.
474 */
475 public static void fireChannelClosed(Channel channel) {
476 channel.getPipeline().sendUpstream(
477 new UpstreamChannelStateEvent(
478 channel, ChannelState.OPEN, Boolean.FALSE));
479
480 // Notify the parent handler.
481 if (channel.getParent() != null) {
482 fireChildChannelStateChanged(channel.getParent(), channel);
483 }
484 }
485
486 /**
487 * Sends a {@code "channelClosed"} event to the
488 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
489 * from the handler associated with the specified
490 * {@link ChannelHandlerContext}.
491 */
492 public static void fireChannelClosed(ChannelHandlerContext ctx) {
493 ctx.sendUpstream(
494 new UpstreamChannelStateEvent(
495 ctx.getChannel(), ChannelState.OPEN, Boolean.FALSE));
496 }
497
498 /**
499 * Sends a {@code "exceptionCaught"} event to the first
500 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
501 * the specified {@link Channel} once the io-thread runs again.
502 */
503 public static ChannelFuture fireExceptionCaughtLater(final Channel channel, final Throwable cause) {
504 return channel.getPipeline().execute(new Runnable() {
505
506 public void run() {
507 fireExceptionCaught(channel, cause);
508 }
509 });
510 }
511
512 /**
513 * Sends a {@code "exceptionCaught"} event to the
514 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
515 * from the handler associated with the specified
516 * {@link ChannelHandlerContext} once the io-thread runs again.
517 */
518 public static ChannelFuture fireExceptionCaughtLater(final ChannelHandlerContext ctx, final Throwable cause) {
519 return ctx.getPipeline().execute(new Runnable() {
520
521 public void run() {
522 fireExceptionCaught(ctx, cause);
523 }
524 });
525 }
526
527 /**
528 * Sends a {@code "exceptionCaught"} event to the first
529 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
530 * the specified {@link Channel}.
531 */
532 public static void fireExceptionCaught(Channel channel, Throwable cause) {
533 channel.getPipeline().sendUpstream(
534 new DefaultExceptionEvent(channel, cause));
535 }
536
537 /**
538 * Sends a {@code "exceptionCaught"} event to the
539 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
540 * from the handler associated with the specified
541 * {@link ChannelHandlerContext}.
542 */
543 public static void fireExceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
544 ctx.sendUpstream(new DefaultExceptionEvent(ctx.getChannel(), cause));
545 }
546
547 private static void fireChildChannelStateChanged(
548 Channel channel, Channel childChannel) {
549 channel.getPipeline().sendUpstream(
550 new DefaultChildChannelStateEvent(channel, childChannel));
551 }
552
553 /**
554 * Sends a {@code "bind"} request to the last
555 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
556 * the specified {@link Channel}.
557 *
558 * @param channel the channel to bind
559 * @param localAddress the local address to bind to
560 *
561 * @return the {@link ChannelFuture} which will be notified when the
562 * bind operation is done
563 */
564 public static ChannelFuture bind(Channel channel, SocketAddress localAddress) {
565 if (localAddress == null) {
566 throw new NullPointerException("localAddress");
567 }
568 ChannelFuture future = future(channel);
569 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
570 channel, future, ChannelState.BOUND, localAddress));
571 return future;
572 }
573
574 /**
575 * Sends a {@code "bind"} request to the
576 * {@link ChannelDownstreamHandler} which is placed in the closest
577 * downstream from the handler associated with the specified
578 * {@link ChannelHandlerContext}.
579 *
580 * @param ctx the context
581 * @param future the future which will be notified when the bind
582 * operation is done
583 * @param localAddress the local address to bind to
584 */
585 public static void bind(
586 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress localAddress) {
587 if (localAddress == null) {
588 throw new NullPointerException("localAddress");
589 }
590 ctx.sendDownstream(new DownstreamChannelStateEvent(
591 ctx.getChannel(), future, ChannelState.BOUND, localAddress));
592 }
593
594 /**
595 * Sends a {@code "unbind"} request to the
596 * {@link ChannelDownstreamHandler} which is placed in the closest
597 * downstream from the handler associated with the specified
598 * {@link ChannelHandlerContext}.
599 *
600 * @param ctx the context
601 * @param future the future which will be notified when the unbind
602 * operation is done
603 */
604 public static void unbind(ChannelHandlerContext ctx, ChannelFuture future) {
605 ctx.sendDownstream(new DownstreamChannelStateEvent(
606 ctx.getChannel(), future, ChannelState.BOUND, null));
607 }
608
609 /**
610 * Sends a {@code "unbind"} request to the last
611 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
612 * the specified {@link Channel}.
613 *
614 * @param channel the channel to unbind
615 *
616 * @return the {@link ChannelFuture} which will be notified when the
617 * unbind operation is done
618 */
619 public static ChannelFuture unbind(Channel channel) {
620 ChannelFuture future = future(channel);
621 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
622 channel, future, ChannelState.BOUND, null));
623 return future;
624 }
625
626 /**
627 * Sends a {@code "connect"} request to the last
628 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
629 * the specified {@link Channel}.
630 *
631 * @param channel the channel to attempt a connection
632 * @param remoteAddress the remote address to connect to
633 *
634 * @return the {@link ChannelFuture} which will be notified when the
635 * connection attempt is done
636 */
637 public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) {
638 if (remoteAddress == null) {
639 throw new NullPointerException("remoteAddress");
640 }
641 ChannelFuture future = future(channel, true);
642 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
643 channel, future, ChannelState.CONNECTED, remoteAddress));
644 return future;
645 }
646
647 /**
648 * Sends a {@code "connect"} request to the
649 * {@link ChannelDownstreamHandler} which is placed in the closest
650 * downstream from the handler associated with the specified
651 * {@link ChannelHandlerContext}.
652 *
653 * @param ctx the context
654 * @param future the future which will be notified when the connection
655 * attempt is done
656 * @param remoteAddress the remote address to connect to
657 */
658 public static void connect(
659 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress remoteAddress) {
660 if (remoteAddress == null) {
661 throw new NullPointerException("remoteAddress");
662 }
663 ctx.sendDownstream(new DownstreamChannelStateEvent(
664 ctx.getChannel(), future, ChannelState.CONNECTED, remoteAddress));
665 }
666
667 /**
668 * Sends a {@code "write"} request to the last
669 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
670 * the specified {@link Channel}.
671 *
672 * @param channel the channel to write a message
673 * @param message the message to write to the channel
674 *
675 * @return the {@link ChannelFuture} which will be notified when the
676 * write operation is done
677 */
678 public static ChannelFuture write(Channel channel, Object message) {
679 return write(channel, message, null);
680 }
681
682 /**
683 * Sends a {@code "write"} request to the
684 * {@link ChannelDownstreamHandler} which is placed in the closest
685 * downstream from the handler associated with the specified
686 * {@link ChannelHandlerContext}.
687 *
688 * @param ctx the context
689 * @param future the future which will be notified when the write
690 * operation is done
691 */
692 public static void write(
693 ChannelHandlerContext ctx, ChannelFuture future, Object message) {
694 write(ctx, future, message, null);
695 }
696
697 /**
698 * Sends a {@code "write"} request to the last
699 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
700 * the specified {@link Channel}.
701 *
702 * @param channel the channel to write a message
703 * @param message the message to write to the channel
704 * @param remoteAddress the destination of the message.
705 * {@code null} to use the default remote address
706 *
707 * @return the {@link ChannelFuture} which will be notified when the
708 * write operation is done
709 */
710 public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) {
711 ChannelFuture future = future(channel);
712 channel.getPipeline().sendDownstream(
713 new DownstreamMessageEvent(channel, future, message, remoteAddress));
714 return future;
715 }
716
717 /**
718 * Sends a {@code "write"} request to the
719 * {@link ChannelDownstreamHandler} which is placed in the closest
720 * downstream from the handler associated with the specified
721 * {@link ChannelHandlerContext}.
722 *
723 * @param ctx the context
724 * @param future the future which will be notified when the write
725 * operation is done
726 * @param message the message to write to the channel
727 * @param remoteAddress the destination of the message.
728 * {@code null} to use the default remote address.
729 */
730 public static void write(
731 ChannelHandlerContext ctx, ChannelFuture future,
732 Object message, SocketAddress remoteAddress) {
733 ctx.sendDownstream(
734 new DownstreamMessageEvent(ctx.getChannel(), future, message, remoteAddress));
735 }
736
737 /**
738 * Sends a {@code "setInterestOps"} request to the last
739 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
740 * the specified {@link Channel}.
741 *
742 * @param channel the channel to change its interestOps
743 * @param interestOps the new interestOps
744 *
745 * @return the {@link ChannelFuture} which will be notified when the
746 * interestOps is changed
747 */
748 public static ChannelFuture setInterestOps(Channel channel, int interestOps) {
749 validateInterestOps(interestOps);
750 interestOps = filterDownstreamInterestOps(interestOps);
751
752 ChannelFuture future = future(channel);
753 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
754 channel, future, ChannelState.INTEREST_OPS, interestOps));
755 return future;
756 }
757
758 /**
759 * Sends a {@code "setInterestOps"} request to the
760 * {@link ChannelDownstreamHandler} which is placed in the closest
761 * downstream from the handler associated with the specified
762 * {@link ChannelHandlerContext}.
763 *
764 * @param ctx the context
765 * @param future the future which will be notified when the interestOps is
766 * changed.
767 */
768 public static void setInterestOps(
769 ChannelHandlerContext ctx, ChannelFuture future, int interestOps) {
770 validateInterestOps(interestOps);
771 interestOps = filterDownstreamInterestOps(interestOps);
772
773 ctx.sendDownstream(
774 new DownstreamChannelStateEvent(
775 ctx.getChannel(), future, ChannelState.INTEREST_OPS, interestOps));
776 }
777
778 /**
779 * Sends a {@code "disconnect"} request to the last
780 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
781 * the specified {@link Channel}.
782 *
783 * @param channel the channel to disconnect
784 *
785 * @return the {@link ChannelFuture} which will be notified on disconnection
786 */
787 public static ChannelFuture disconnect(Channel channel) {
788 ChannelFuture future = future(channel);
789 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
790 channel, future, ChannelState.CONNECTED, null));
791 return future;
792 }
793
794 /**
795 * Sends a {@code "disconnect"} request to the
796 * {@link ChannelDownstreamHandler} which is placed in the closest
797 * downstream from the handler associated with the specified
798 * {@link ChannelHandlerContext}.
799 *
800 * @param ctx the context
801 * @param future the future which will be notified on disconnection
802 */
803 public static void disconnect(
804 ChannelHandlerContext ctx, ChannelFuture future) {
805 ctx.sendDownstream(new DownstreamChannelStateEvent(
806 ctx.getChannel(), future, ChannelState.CONNECTED, null));
807 }
808
809 /**
810 * Sends a {@code "close"} request to the last
811 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
812 * the specified {@link Channel}.
813 *
814 * @param channel the channel to close
815 *
816 * @return the {@link ChannelFuture} which will be notified on closure
817 */
818 public static ChannelFuture close(Channel channel) {
819 ChannelFuture future = channel.getCloseFuture();
820 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
821 channel, future, ChannelState.OPEN, Boolean.FALSE));
822 return future;
823 }
824
825 /**
826 * Sends a {@code "close"} request to the
827 * {@link ChannelDownstreamHandler} which is placed in the closest
828 * downstream from the handler associated with the specified
829 * {@link ChannelHandlerContext}.
830 *
831 * @param ctx the context
832 * @param future the future which will be notified on closure
833 */
834 public static void close(
835 ChannelHandlerContext ctx, ChannelFuture future) {
836 ctx.sendDownstream(new DownstreamChannelStateEvent(
837 ctx.getChannel(), future, ChannelState.OPEN, Boolean.FALSE));
838 }
839
840 private static void validateInterestOps(int interestOps) {
841 switch (interestOps) {
842 case Channel.OP_NONE:
843 case Channel.OP_READ:
844 case Channel.OP_WRITE:
845 case Channel.OP_READ_WRITE:
846 break;
847 default:
848 throw new IllegalArgumentException(
849 "Invalid interestOps: " + interestOps);
850 }
851 }
852
853 private static int filterDownstreamInterestOps(int interestOps) {
854 return interestOps & ~Channel.OP_WRITE;
855 }
856
857 private Channels() {
858 // Unused
859 }
860 }