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 * Sends a {@code "writeComplete"} event to the first
316 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
317 * the specified {@link Channel}.
318 */
319 public static void fireWriteComplete(Channel channel, long amount) {
320 if (amount == 0) {
321 return;
322 }
323
324 channel.getPipeline().sendUpstream(
325 new DefaultWriteCompletionEvent(channel, amount));
326 }
327
328 /**
329 * Sends a {@code "writeComplete"} event to the
330 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
331 * from the handler associated with the specified
332 * {@link ChannelHandlerContext}.
333 */
334 public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) {
335 ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount));
336 }
337
338 /**
339 * Sends a {@code "channelInterestChanged"} event to the first
340 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
341 * the specified {@link Channel} once the io-thread runs again.
342 */
343 public static ChannelFuture fireChannelInterestChangedLater(final Channel channel) {
344 return channel.getPipeline().execute(new Runnable() {
345
346 public void run() {
347 fireChannelInterestChanged(channel);
348 }
349 });
350 }
351
352 /**
353 * Sends a {@code "channelInterestChanged"} event to the first
354 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
355 * the specified {@link Channel}.
356 */
357 public static void fireChannelInterestChanged(Channel channel) {
358 channel.getPipeline().sendUpstream(
359 new UpstreamChannelStateEvent(
360 channel, ChannelState.INTEREST_OPS, Channel.OP_READ));
361 }
362
363 /**
364 * Sends a {@code "channelInterestChanged"} event to the
365 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
366 * from the handler associated with the specified
367 * {@link ChannelHandlerContext}.
368 */
369 public static void fireChannelInterestChanged(
370 ChannelHandlerContext ctx) {
371
372 ctx.sendUpstream(
373 new UpstreamChannelStateEvent(
374 ctx.getChannel(), ChannelState.INTEREST_OPS, Channel.OP_READ));
375 }
376
377 /**
378 * Sends a {@code "channelDisconnected"} event to the first
379 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
380 * the specified {@link Channel} once the io-thread runs again.
381 */
382 public static ChannelFuture fireChannelDisconnectedLater(final Channel channel) {
383 return channel.getPipeline().execute(new Runnable() {
384
385 public void run() {
386 fireChannelDisconnected(channel);
387 }
388 });
389 }
390 /**
391 * Sends a {@code "channelDisconnected"} event to the first
392 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
393 * the specified {@link Channel}.
394 */
395 public static void fireChannelDisconnected(Channel channel) {
396 channel.getPipeline().sendUpstream(
397 new UpstreamChannelStateEvent(
398 channel, ChannelState.CONNECTED, null));
399 }
400
401 /**
402 * Sends a {@code "channelDisconnected"} event to the
403 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
404 * from the handler associated with the specified
405 * {@link ChannelHandlerContext}.
406 */
407 public static void fireChannelDisconnected(ChannelHandlerContext ctx) {
408 ctx.sendUpstream(new UpstreamChannelStateEvent(
409 ctx.getChannel(), ChannelState.CONNECTED, null));
410 }
411
412 /**
413 * Sends a {@code "channelUnbound"} event to the first
414 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
415 * the specified {@link Channel} once the io-thread runs again.
416 */
417 public static ChannelFuture fireChannelUnboundLater(final Channel channel) {
418 return channel.getPipeline().execute(new Runnable() {
419
420 public void run() {
421 fireChannelUnbound(channel);
422 }
423 });
424 }
425
426 /**
427 * Sends a {@code "channelUnbound"} event to the first
428 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
429 * the specified {@link Channel}.
430 */
431 public static void fireChannelUnbound(Channel channel) {
432 channel.getPipeline().sendUpstream(new UpstreamChannelStateEvent(
433 channel, ChannelState.BOUND, null));
434 }
435
436 /**
437 * Sends a {@code "channelUnbound"} event to the
438 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
439 * from the handler associated with the specified
440 * {@link ChannelHandlerContext}.
441 */
442 public static void fireChannelUnbound(ChannelHandlerContext ctx) {
443
444 ctx.sendUpstream(new UpstreamChannelStateEvent(
445 ctx.getChannel(), ChannelState.BOUND, null));
446 }
447
448 /**
449 * Sends a {@code "channelClosed"} event to the first
450 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
451 * the specified {@link Channel} once the io-thread runs again.
452 */
453 public static ChannelFuture fireChannelClosedLater(final Channel channel) {
454 return channel.getPipeline().execute(new Runnable() {
455
456 public void run() {
457 fireChannelClosed(channel);
458 }
459 });
460 }
461
462 /**
463 * Sends a {@code "channelClosed"} event to the first
464 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
465 * the specified {@link Channel}.
466 */
467 public static void fireChannelClosed(Channel channel) {
468 channel.getPipeline().sendUpstream(
469 new UpstreamChannelStateEvent(
470 channel, ChannelState.OPEN, Boolean.FALSE));
471
472 // Notify the parent handler.
473 if (channel.getParent() != null) {
474 fireChildChannelStateChanged(channel.getParent(), channel);
475 }
476 }
477
478 /**
479 * Sends a {@code "channelClosed"} event to the
480 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
481 * from the handler associated with the specified
482 * {@link ChannelHandlerContext}.
483 */
484 public static void fireChannelClosed(ChannelHandlerContext ctx) {
485 ctx.sendUpstream(
486 new UpstreamChannelStateEvent(
487 ctx.getChannel(), ChannelState.OPEN, Boolean.FALSE));
488 }
489
490 /**
491 * Sends a {@code "exceptionCaught"} event to the first
492 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
493 * the specified {@link Channel} once the io-thread runs again.
494 */
495 public static ChannelFuture fireExceptionCaughtLater(final Channel channel, final Throwable cause) {
496 return channel.getPipeline().execute(new Runnable() {
497
498 public void run() {
499 fireExceptionCaught(channel, cause);
500 }
501 });
502 }
503
504 /**
505 * Sends a {@code "exceptionCaught"} event to the
506 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
507 * from the handler associated with the specified
508 * {@link ChannelHandlerContext} once the io-thread runs again.
509 */
510 public static ChannelFuture fireExceptionCaughtLater(final ChannelHandlerContext ctx, final Throwable cause) {
511 return ctx.getPipeline().execute(new Runnable() {
512
513 public void run() {
514 fireExceptionCaught(ctx, cause);
515 }
516 });
517 }
518
519 /**
520 * Sends a {@code "exceptionCaught"} event to the first
521 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
522 * the specified {@link Channel}.
523 */
524 public static void fireExceptionCaught(Channel channel, Throwable cause) {
525 channel.getPipeline().sendUpstream(
526 new DefaultExceptionEvent(channel, cause));
527 }
528
529 /**
530 * Sends a {@code "exceptionCaught"} event to the
531 * {@link ChannelUpstreamHandler} which is placed in the closest upstream
532 * from the handler associated with the specified
533 * {@link ChannelHandlerContext}.
534 */
535 public static void fireExceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
536 ctx.sendUpstream(new DefaultExceptionEvent(ctx.getChannel(), cause));
537 }
538
539 private static void fireChildChannelStateChanged(
540 Channel channel, Channel childChannel) {
541 channel.getPipeline().sendUpstream(
542 new DefaultChildChannelStateEvent(channel, childChannel));
543 }
544
545 /**
546 * Sends a {@code "bind"} request to the last
547 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
548 * the specified {@link Channel}.
549 *
550 * @param channel the channel to bind
551 * @param localAddress the local address to bind to
552 *
553 * @return the {@link ChannelFuture} which will be notified when the
554 * bind operation is done
555 */
556 public static ChannelFuture bind(Channel channel, SocketAddress localAddress) {
557 if (localAddress == null) {
558 throw new NullPointerException("localAddress");
559 }
560 ChannelFuture future = future(channel);
561 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
562 channel, future, ChannelState.BOUND, localAddress));
563 return future;
564 }
565
566 /**
567 * Sends a {@code "bind"} request to the
568 * {@link ChannelDownstreamHandler} which is placed in the closest
569 * downstream from the handler associated with the specified
570 * {@link ChannelHandlerContext}.
571 *
572 * @param ctx the context
573 * @param future the future which will be notified when the bind
574 * operation is done
575 * @param localAddress the local address to bind to
576 */
577 public static void bind(
578 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress localAddress) {
579 if (localAddress == null) {
580 throw new NullPointerException("localAddress");
581 }
582 ctx.sendDownstream(new DownstreamChannelStateEvent(
583 ctx.getChannel(), future, ChannelState.BOUND, localAddress));
584 }
585
586 /**
587 * Sends a {@code "unbind"} request to the
588 * {@link ChannelDownstreamHandler} which is placed in the closest
589 * downstream from the handler associated with the specified
590 * {@link ChannelHandlerContext}.
591 *
592 * @param ctx the context
593 * @param future the future which will be notified when the unbind
594 * operation is done
595 */
596 public static void unbind(ChannelHandlerContext ctx, ChannelFuture future) {
597 ctx.sendDownstream(new DownstreamChannelStateEvent(
598 ctx.getChannel(), future, ChannelState.BOUND, null));
599 }
600
601 /**
602 * Sends a {@code "unbind"} request to the last
603 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
604 * the specified {@link Channel}.
605 *
606 * @param channel the channel to unbind
607 *
608 * @return the {@link ChannelFuture} which will be notified when the
609 * unbind operation is done
610 */
611 public static ChannelFuture unbind(Channel channel) {
612 ChannelFuture future = future(channel);
613 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
614 channel, future, ChannelState.BOUND, null));
615 return future;
616 }
617
618 /**
619 * Sends a {@code "connect"} request to the last
620 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
621 * the specified {@link Channel}.
622 *
623 * @param channel the channel to attempt a connection
624 * @param remoteAddress the remote address to connect to
625 *
626 * @return the {@link ChannelFuture} which will be notified when the
627 * connection attempt is done
628 */
629 public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) {
630 if (remoteAddress == null) {
631 throw new NullPointerException("remoteAddress");
632 }
633 ChannelFuture future = future(channel, true);
634 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
635 channel, future, ChannelState.CONNECTED, remoteAddress));
636 return future;
637 }
638
639 /**
640 * Sends a {@code "connect"} request to the
641 * {@link ChannelDownstreamHandler} which is placed in the closest
642 * downstream from the handler associated with the specified
643 * {@link ChannelHandlerContext}.
644 *
645 * @param ctx the context
646 * @param future the future which will be notified when the connection
647 * attempt is done
648 * @param remoteAddress the remote address to connect to
649 */
650 public static void connect(
651 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress remoteAddress) {
652 if (remoteAddress == null) {
653 throw new NullPointerException("remoteAddress");
654 }
655 ctx.sendDownstream(new DownstreamChannelStateEvent(
656 ctx.getChannel(), future, ChannelState.CONNECTED, remoteAddress));
657 }
658
659 /**
660 * Sends a {@code "write"} request to the last
661 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
662 * the specified {@link Channel}.
663 *
664 * @param channel the channel to write a message
665 * @param message the message to write to the channel
666 *
667 * @return the {@link ChannelFuture} which will be notified when the
668 * write operation is done
669 */
670 public static ChannelFuture write(Channel channel, Object message) {
671 return write(channel, message, null);
672 }
673
674 /**
675 * Sends a {@code "write"} request to the
676 * {@link ChannelDownstreamHandler} which is placed in the closest
677 * downstream from the handler associated with the specified
678 * {@link ChannelHandlerContext}.
679 *
680 * @param ctx the context
681 * @param future the future which will be notified when the write
682 * operation is done
683 */
684 public static void write(
685 ChannelHandlerContext ctx, ChannelFuture future, Object message) {
686 write(ctx, future, message, null);
687 }
688
689 /**
690 * Sends a {@code "write"} request to the last
691 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
692 * the specified {@link Channel}.
693 *
694 * @param channel the channel to write a message
695 * @param message the message to write to the channel
696 * @param remoteAddress the destination of the message.
697 * {@code null} to use the default remote address
698 *
699 * @return the {@link ChannelFuture} which will be notified when the
700 * write operation is done
701 */
702 public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) {
703 ChannelFuture future = future(channel);
704 channel.getPipeline().sendDownstream(
705 new DownstreamMessageEvent(channel, future, message, remoteAddress));
706 return future;
707 }
708
709 /**
710 * Sends a {@code "write"} request to the
711 * {@link ChannelDownstreamHandler} which is placed in the closest
712 * downstream from the handler associated with the specified
713 * {@link ChannelHandlerContext}.
714 *
715 * @param ctx the context
716 * @param future the future which will be notified when the write
717 * operation is done
718 * @param message the message to write to the channel
719 * @param remoteAddress the destination of the message.
720 * {@code null} to use the default remote address.
721 */
722 public static void write(
723 ChannelHandlerContext ctx, ChannelFuture future,
724 Object message, SocketAddress remoteAddress) {
725 ctx.sendDownstream(
726 new DownstreamMessageEvent(ctx.getChannel(), future, message, remoteAddress));
727 }
728
729 /**
730 * Sends a {@code "setInterestOps"} request to the last
731 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
732 * the specified {@link Channel}.
733 *
734 * @param channel the channel to change its interestOps
735 * @param interestOps the new interestOps
736 *
737 * @return the {@link ChannelFuture} which will be notified when the
738 * interestOps is changed
739 */
740 public static ChannelFuture setInterestOps(Channel channel, int interestOps) {
741 validateInterestOps(interestOps);
742 interestOps = filterDownstreamInterestOps(interestOps);
743
744 ChannelFuture future = future(channel);
745 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
746 channel, future, ChannelState.INTEREST_OPS, interestOps));
747 return future;
748 }
749
750 /**
751 * Sends a {@code "setInterestOps"} request to the
752 * {@link ChannelDownstreamHandler} which is placed in the closest
753 * downstream from the handler associated with the specified
754 * {@link ChannelHandlerContext}.
755 *
756 * @param ctx the context
757 * @param future the future which will be notified when the interestOps is
758 * changed.
759 */
760 public static void setInterestOps(
761 ChannelHandlerContext ctx, ChannelFuture future, int interestOps) {
762 validateInterestOps(interestOps);
763 interestOps = filterDownstreamInterestOps(interestOps);
764
765 ctx.sendDownstream(
766 new DownstreamChannelStateEvent(
767 ctx.getChannel(), future, ChannelState.INTEREST_OPS, interestOps));
768 }
769
770 /**
771 * Sends a {@code "disconnect"} request to the last
772 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
773 * the specified {@link Channel}.
774 *
775 * @param channel the channel to disconnect
776 *
777 * @return the {@link ChannelFuture} which will be notified on disconnection
778 */
779 public static ChannelFuture disconnect(Channel channel) {
780 ChannelFuture future = future(channel);
781 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
782 channel, future, ChannelState.CONNECTED, null));
783 return future;
784 }
785
786 /**
787 * Sends a {@code "disconnect"} request to the
788 * {@link ChannelDownstreamHandler} which is placed in the closest
789 * downstream from the handler associated with the specified
790 * {@link ChannelHandlerContext}.
791 *
792 * @param ctx the context
793 * @param future the future which will be notified on disconnection
794 */
795 public static void disconnect(
796 ChannelHandlerContext ctx, ChannelFuture future) {
797 ctx.sendDownstream(new DownstreamChannelStateEvent(
798 ctx.getChannel(), future, ChannelState.CONNECTED, null));
799 }
800
801 /**
802 * Sends a {@code "close"} request to the last
803 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of
804 * the specified {@link Channel}.
805 *
806 * @param channel the channel to close
807 *
808 * @return the {@link ChannelFuture} which will be notified on closure
809 */
810 public static ChannelFuture close(Channel channel) {
811 ChannelFuture future = channel.getCloseFuture();
812 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(
813 channel, future, ChannelState.OPEN, Boolean.FALSE));
814 return future;
815 }
816
817 /**
818 * Sends a {@code "close"} request to the
819 * {@link ChannelDownstreamHandler} which is placed in the closest
820 * downstream from the handler associated with the specified
821 * {@link ChannelHandlerContext}.
822 *
823 * @param ctx the context
824 * @param future the future which will be notified on closure
825 */
826 public static void close(
827 ChannelHandlerContext ctx, ChannelFuture future) {
828 ctx.sendDownstream(new DownstreamChannelStateEvent(
829 ctx.getChannel(), future, ChannelState.OPEN, Boolean.FALSE));
830 }
831
832 private static void validateInterestOps(int interestOps) {
833 switch (interestOps) {
834 case Channel.OP_NONE:
835 case Channel.OP_READ:
836 case Channel.OP_WRITE:
837 case Channel.OP_READ_WRITE:
838 break;
839 default:
840 throw new IllegalArgumentException(
841 "Invalid interestOps: " + interestOps);
842 }
843 }
844
845 private static int filterDownstreamInterestOps(int interestOps) {
846 return interestOps & ~Channel.OP_WRITE;
847 }
848
849 private Channels() {
850 // Unused
851 }
852 }