View Javadoc
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 org.jboss.netty.buffer.ChannelBuffer;
19  import org.jboss.netty.logging.InternalLogger;
20  import org.jboss.netty.logging.InternalLoggerFactory;
21  
22  import java.util.List;
23  
24  
25  /**
26   * A {@link ChannelUpstreamHandler} which provides an individual handler method
27   * for each event type.  This handler down-casts the received upstream event
28   * into more meaningful sub-type event and calls an appropriate handler method
29   * with the down-cast event.  The names of the methods are identical to the
30   * upstream event names, as introduced in the {@link ChannelEvent} documentation.
31   * <p>
32   * Please use {@link SimpleChannelHandler} if you need to implement both
33   * {@link ChannelUpstreamHandler} and {@link ChannelDownstreamHandler}.
34   *
35   * <h3>Overriding the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} method</h3>
36   * <p>
37   * You can override the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream}
38   * method just like overriding an ordinary Java method.  Please make sure to
39   * call {@code super.handleUpstream()} so that other handler methods are invoked
40   * properly:
41   * </p>
42   * <pre>public class MyChannelHandler extends {@link SimpleChannelUpstreamHandler} {
43   *
44   *     {@code @Override}
45   *     public void handleUpstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
46   *
47   *         // Log all channel state changes.
48   *         if (e instanceof {@link ChannelStateEvent}) {
49   *             logger.info("Channel state changed: " + e);
50   *         }
51   *
52   *         <strong>super.handleUpstream(ctx, e);</strong>
53   *     }
54   * }</pre>
55   */
56  public class SimpleChannelUpstreamHandler implements ChannelUpstreamHandler {
57  
58      private static final InternalLogger logger =
59          InternalLoggerFactory.getInstance(SimpleChannelUpstreamHandler.class.getName());
60  
61      /**
62       * {@inheritDoc}  Down-casts the received upstream event into more
63       * meaningful sub-type event and calls an appropriate handler method with
64       * the down-casted event.
65       */
66      public void handleUpstream(
67              ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
68  
69          if (e instanceof MessageEvent) {
70              messageReceived(ctx, (MessageEvent) e);
71          } else if (e instanceof WriteCompletionEvent) {
72              WriteCompletionEvent evt = (WriteCompletionEvent) e;
73              writeComplete(ctx, evt);
74          } else if (e instanceof ChildChannelStateEvent) {
75              ChildChannelStateEvent evt = (ChildChannelStateEvent) e;
76              if (evt.getChildChannel().isOpen()) {
77                  childChannelOpen(ctx, evt);
78              } else {
79                  childChannelClosed(ctx, evt);
80              }
81          } else if (e instanceof ChannelStateEvent) {
82              ChannelStateEvent evt = (ChannelStateEvent) e;
83              switch (evt.getState()) {
84              case OPEN:
85                  if (Boolean.TRUE.equals(evt.getValue())) {
86                      channelOpen(ctx, evt);
87                  } else {
88                      channelClosed(ctx, evt);
89                  }
90                  break;
91              case BOUND:
92                  if (evt.getValue() != null) {
93                      channelBound(ctx, evt);
94                  } else {
95                      channelUnbound(ctx, evt);
96                  }
97                  break;
98              case CONNECTED:
99                  if (evt.getValue() != null) {
100                     channelConnected(ctx, evt);
101                 } else {
102                     channelDisconnected(ctx, evt);
103                 }
104                 break;
105             case INTEREST_OPS:
106                 channelInterestChanged(ctx, evt);
107                 break;
108             default:
109                 ctx.sendUpstream(e);
110             }
111         } else if (e instanceof ExceptionEvent) {
112             exceptionCaught(ctx, (ExceptionEvent) e);
113         } else {
114             ctx.sendUpstream(e);
115         }
116     }
117 
118     /**
119      * Invoked when a message object (e.g: {@link ChannelBuffer}) was received
120      * from a remote peer.
121      */
122     public void messageReceived(
123             ChannelHandlerContext ctx, MessageEvent e) throws Exception {
124         ctx.sendUpstream(e);
125     }
126 
127     /**
128      * Invoked when an exception was raised by an I/O thread or a
129      * {@link ChannelHandler}.
130      */
131     public void exceptionCaught(
132             ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
133         ChannelPipeline pipeline = ctx.getPipeline();
134 
135         ChannelHandler last = pipeline.getLast();
136         if (!(last instanceof ChannelUpstreamHandler) && ctx instanceof DefaultChannelPipeline) {
137             // The names comes in the order of which they are insert when using DefaultChannelPipeline
138             List<String> names = ctx.getPipeline().getNames();
139             for (int i = names.size() - 1; i >= 0; i--) {
140                 ChannelHandler handler = ctx.getPipeline().get(names.get(i));
141                 if (handler instanceof ChannelUpstreamHandler) {
142                     // find the last handler
143                     last = handler;
144                     break;
145                 }
146             }
147         }
148         if (this == last) {
149             logger.warn(
150                     "EXCEPTION, please implement " + getClass().getName() +
151                     ".exceptionCaught() for proper handling.", e.getCause());
152         }
153         ctx.sendUpstream(e);
154     }
155 
156     /**
157      * Invoked when a {@link Channel} is open, but not bound nor connected.
158      * <br/>
159      *
160      * <strong>Be aware that this event is fired from within the I/O thread.  You should never
161      * execute any heavy operation in there as it will block the dispatching to other workers!</strong>
162      */
163     public void channelOpen(
164             ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
165         ctx.sendUpstream(e);
166     }
167 
168     /**
169      * Invoked when a {@link Channel} is open and bound to a local address,
170      * but not connected.
171      * <br/>
172      *
173      * <strong>Be aware that this event is fired from within the I/O thread.  You should never
174      * execute any heavy operation in there as it will block the dispatching to other workers!</strong>
175      */
176     public void channelBound(
177             ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
178         ctx.sendUpstream(e);
179     }
180 
181     /**
182      * Invoked when a {@link Channel} is open, bound to a local address, and
183      * connected to a remote address.
184      * <br/>
185      *
186      * <strong>Be aware that this event is fired from within the I/O thread.  You should never
187      * execute any heavy operation in there as it will block the dispatching to other workers!</strong>
188      */
189     public void channelConnected(
190             ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
191         ctx.sendUpstream(e);
192     }
193 
194     /**
195      * Invoked when a {@link Channel}'s {@link Channel#getInterestOps() interestOps}
196      * was changed.
197      */
198     public void channelInterestChanged(
199             ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
200         ctx.sendUpstream(e);
201     }
202 
203     /**
204      * Invoked when a {@link Channel} was disconnected from its remote peer.
205      */
206     public void channelDisconnected(
207             ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
208         ctx.sendUpstream(e);
209     }
210 
211     /**
212      * Invoked when a {@link Channel} was unbound from the current local address.
213      */
214     public void channelUnbound(
215             ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
216         ctx.sendUpstream(e);
217     }
218 
219     /**
220      * Invoked when a {@link Channel} was closed and all its related resources
221      * were released.
222      */
223     public void channelClosed(
224             ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
225         ctx.sendUpstream(e);
226     }
227 
228     /**
229      * Invoked when something was written into a {@link Channel}.
230      */
231     public void writeComplete(
232             ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception {
233         ctx.sendUpstream(e);
234     }
235 
236     /**
237      * Invoked when a child {@link Channel} was open.
238      * (e.g. a server channel accepted a connection)
239      */
240     public void childChannelOpen(
241             ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
242         ctx.sendUpstream(e);
243     }
244 
245     /**
246      * Invoked when a child {@link Channel} was closed.
247      * (e.g. the accepted connection was closed)
248      */
249     public void childChannelClosed(
250             ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
251         ctx.sendUpstream(e);
252     }
253 }