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
20 import org.jboss.netty.buffer.ChannelBuffer;
21 import org.jboss.netty.logging.InternalLogger;
22 import org.jboss.netty.logging.InternalLoggerFactory;
23
24
25 /**
26 * A {@link ChannelHandler} which provides an individual handler method
27 * for each event type. This handler down-casts the received upstream or
28 * or downstream event into more meaningful sub-type event and calls an
29 * appropriate handler method with the down-cast event. For an upstream
30 * event, the names of the methods are identical to the upstream event names,
31 * as introduced in the {@link ChannelEvent} documentation. For a
32 * downstream event, the names of the methods starts with the name of the
33 * operation and ends with {@code "Requested"}
34 * (e.g. {@link #writeRequested(ChannelHandlerContext, MessageEvent) writeRequested}.)
35 * <p>
36 * Please use {@link SimpleChannelUpstreamHandler} or
37 * {@link SimpleChannelDownstreamHandler} if you want to intercept only
38 * upstream or downstream events.
39 *
40 * <h3>Overriding the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream}
41 * and {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream} method</h3>
42 * <p>
43 * You can override the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream}
44 * and {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream}
45 * method just like overriding an ordinary Java method. Please make sure to
46 * call {@code super.handleUpstream()} or {@code super.handleDownstream()} so
47 * that other handler methods are invoked properly:
48 * </p>
49 * <pre>public class MyChannelHandler extends {@link SimpleChannelHandler} {
50 *
51 * {@code @Override}
52 * public void handleUpstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
53 *
54 * // Log all channel state changes.
55 * if (e instanceof {@link ChannelStateEvent}) {
56 * logger.info("Channel state changed: " + e);
57 * }
58 *
59 * <strong>super.handleUpstream(ctx, e);</strong>
60 * }
61 *
62 * {@code @Override}
63 * public void handleDownstream({@link ChannelHandlerContext} ctx, {@link ChannelEvent} e) throws Exception {
64 *
65 * // Log all channel state changes.
66 * if (e instanceof {@link MessageEvent}) {
67 * logger.info("Writing:: " + e);
68 * }
69 *
70 * <strong>super.handleDownstream(ctx, e);</strong>
71 * }
72 * }</pre>
73 */
74 public class SimpleChannelHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler {
75
76 private static final InternalLogger logger =
77 InternalLoggerFactory.getInstance(SimpleChannelHandler.class.getName());
78
79 /**
80 * {@inheritDoc} Down-casts the received upstream event into more
81 * meaningful sub-type event and calls an appropriate handler method with
82 * the down-casted event.
83 */
84 public void handleUpstream(
85 ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
86
87 if (e instanceof MessageEvent) {
88 messageReceived(ctx, (MessageEvent) e);
89 } else if (e instanceof WriteCompletionEvent) {
90 WriteCompletionEvent evt = (WriteCompletionEvent) e;
91 writeComplete(ctx, evt);
92 } else if (e instanceof ChildChannelStateEvent) {
93 ChildChannelStateEvent evt = (ChildChannelStateEvent) e;
94 if (evt.getChildChannel().isOpen()) {
95 childChannelOpen(ctx, evt);
96 } else {
97 childChannelClosed(ctx, evt);
98 }
99 } else if (e instanceof ChannelStateEvent) {
100 ChannelStateEvent evt = (ChannelStateEvent) e;
101 switch (evt.getState()) {
102 case OPEN:
103 if (Boolean.TRUE.equals(evt.getValue())) {
104 channelOpen(ctx, evt);
105 } else {
106 channelClosed(ctx, evt);
107 }
108 break;
109 case BOUND:
110 if (evt.getValue() != null) {
111 channelBound(ctx, evt);
112 } else {
113 channelUnbound(ctx, evt);
114 }
115 break;
116 case CONNECTED:
117 if (evt.getValue() != null) {
118 channelConnected(ctx, evt);
119 } else {
120 channelDisconnected(ctx, evt);
121 }
122 break;
123 case INTEREST_OPS:
124 channelInterestChanged(ctx, evt);
125 break;
126 default:
127 ctx.sendUpstream(e);
128 }
129 } else if (e instanceof ExceptionEvent) {
130 exceptionCaught(ctx, (ExceptionEvent) e);
131 } else {
132 ctx.sendUpstream(e);
133 }
134 }
135
136 /**
137 * Invoked when a message object (e.g: {@link ChannelBuffer}) was received
138 * from a remote peer.
139 */
140 public void messageReceived(
141 ChannelHandlerContext ctx, MessageEvent e) throws Exception {
142 ctx.sendUpstream(e);
143 }
144
145 /**
146 * Invoked when an exception was raised by an I/O thread or a
147 * {@link ChannelHandler}.
148 */
149 public void exceptionCaught(
150 ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
151 if (this == ctx.getPipeline().getLast()) {
152 logger.warn(
153 "EXCEPTION, please implement " + getClass().getName() +
154 ".exceptionCaught() for proper handling.", e.getCause());
155 }
156 ctx.sendUpstream(e);
157 }
158
159 /**
160 * Invoked when a {@link Channel} is open, but not bound nor connected.
161 */
162 public void channelOpen(
163 ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
164 ctx.sendUpstream(e);
165 }
166
167 /**
168 * Invoked when a {@link Channel} is open and bound to a local address,
169 * but not connected.
170 */
171 public void channelBound(
172 ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
173 ctx.sendUpstream(e);
174 }
175
176 /**
177 * Invoked when a {@link Channel} is open, bound to a local address, and
178 * connected to a remote address.
179 */
180 public void channelConnected(
181 ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
182 ctx.sendUpstream(e);
183 }
184
185 /**
186 * Invoked when a {@link Channel}'s {@link Channel#getInterestOps() interestOps}
187 * was changed.
188 */
189 public void channelInterestChanged(
190 ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
191 ctx.sendUpstream(e);
192 }
193
194 /**
195 * Invoked when a {@link Channel} was disconnected from its remote peer.
196 */
197 public void channelDisconnected(
198 ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
199 ctx.sendUpstream(e);
200 }
201
202 /**
203 * Invoked when a {@link Channel} was unbound from the current local address.
204 */
205 public void channelUnbound(
206 ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
207 ctx.sendUpstream(e);
208 }
209
210 /**
211 * Invoked when a {@link Channel} was closed and all its related resources
212 * were released.
213 */
214 public void channelClosed(
215 ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
216 ctx.sendUpstream(e);
217 }
218
219 /**
220 * Invoked when something was written into a {@link Channel}.
221 */
222 public void writeComplete(
223 ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception {
224 ctx.sendUpstream(e);
225 }
226
227 /**
228 * Invoked when a child {@link Channel} was open.
229 * (e.g. a server channel accepted a connection)
230 */
231 public void childChannelOpen(
232 ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
233 ctx.sendUpstream(e);
234 }
235
236 /**
237 * Invoked when a child {@link Channel} was closed.
238 * (e.g. the accepted connection was closed)
239 */
240 public void childChannelClosed(
241 ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
242 ctx.sendUpstream(e);
243 }
244
245 /**
246 * {@inheritDoc} Down-casts the received downstream event into more
247 * meaningful sub-type event and calls an appropriate handler method with
248 * the down-casted event.
249 */
250 public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e)
251 throws Exception {
252
253 if (e instanceof MessageEvent) {
254 writeRequested(ctx, (MessageEvent) e);
255 } else if (e instanceof ChannelStateEvent) {
256 ChannelStateEvent evt = (ChannelStateEvent) e;
257 switch (evt.getState()) {
258 case OPEN:
259 if (!Boolean.TRUE.equals(evt.getValue())) {
260 closeRequested(ctx, evt);
261 }
262 break;
263 case BOUND:
264 if (evt.getValue() != null) {
265 bindRequested(ctx, evt);
266 } else {
267 unbindRequested(ctx, evt);
268 }
269 break;
270 case CONNECTED:
271 if (evt.getValue() != null) {
272 connectRequested(ctx, evt);
273 } else {
274 disconnectRequested(ctx, evt);
275 }
276 break;
277 case INTEREST_OPS:
278 setInterestOpsRequested(ctx, evt);
279 break;
280 default:
281 ctx.sendDownstream(e);
282 }
283 } else {
284 ctx.sendDownstream(e);
285 }
286 }
287
288 /**
289 * Invoked when {@link Channel#write(Object)} is called.
290 */
291 public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
292 ctx.sendDownstream(e);
293 }
294
295 /**
296 * Invoked when {@link Channel#bind(SocketAddress)} was called.
297 */
298 public void bindRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
299 ctx.sendDownstream(e);
300 }
301
302 /**
303 * Invoked when {@link Channel#connect(SocketAddress)} was called.
304 */
305 public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
306 ctx.sendDownstream(e);
307 }
308
309 /**
310 * Invoked when {@link Channel#setInterestOps(int)} was called.
311 */
312 public void setInterestOpsRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
313 ctx.sendDownstream(e);
314 }
315
316 /**
317 * Invoked when {@link Channel#disconnect()} was called.
318 */
319 public void disconnectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
320 ctx.sendDownstream(e);
321 }
322
323 /**
324 * Invoked when {@link Channel#unbind()} was called.
325 */
326 public void unbindRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
327 ctx.sendDownstream(e);
328 }
329
330 /**
331 * Invoked when {@link Channel#close()} was called.
332 */
333 public void closeRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
334 ctx.sendDownstream(e);
335 }
336 }