1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.common;
21
22 import java.net.SocketAddress;
23
24 import org.apache.mina.filter.ReferenceCountingIoFilter;
25
26 /**
27 * A filter which intercepts {@link IoHandler} events like Servlet
28 * filters. Filters can be used for these purposes:
29 * <ul>
30 * <li>Event logging,</li>
31 * <li>Performance measurement,</li>
32 * <li>Authorization,</li>
33 * <li>Overload control,</li>
34 * <li>Message transformation (e.g. encryption and decryption, ...),</li>
35 * <li>and many more.</li>
36 * </ul>
37 * <p>
38 * <strong>Please NEVER implement your filters to wrap
39 * {@link IoSession}s.</strong> Users can cache the reference to the
40 * session, which might malfunction if any filters are added or removed later.
41 *
42 * <h3>The Life Cycle</h3>
43 * {@link IoFilter}s are activated only when they are inside {@link IoFilterChain}.
44 * <p>
45 * When you add an {@link IoFilter} to an {@link IoFilterChain}:
46 * <ol>
47 * <li>{@link #init()} is invoked by {@link ReferenceCountingIoFilter} if
48 * the filter is added at the first time.</li>
49 * <li>{@link #onPreAdd(IoFilterChain, String, NextFilter)} is invoked to notify
50 * that the filter will be added to the chain.</li>
51 * <li>The filter is added to the chain, and all events and I/O requests
52 * pass through the filter from now.</li>
53 * <li>{@link #onPostAdd(IoFilterChain, String, NextFilter)} is invoked to notify
54 * that the filter is added to the chain.</li>
55 * <li>The filter is removed from the chain if {@link #onPostAdd(IoFilterChain, String, org.apache.mina.common.IoFilter.NextFilter)}
56 * threw an exception. {@link #destroy()} is also invoked by
57 * {@link ReferenceCountingIoFilter} if the filter is the last filter which
58 * was added to {@link IoFilterChain}s.</li>
59 * </ol>
60 * <p>
61 * When you remove an {@link IoFilter} from an {@link IoFilterChain}:
62 * <ol>
63 * <li>{@link #onPreRemove(IoFilterChain, String, NextFilter)} is invoked to
64 * notify that the filter will be removed from the chain.</li>
65 * <li>The filter is removed from the chain, and any events and I/O requests
66 * don't pass through the filter from now.</li>
67 * <li>{@link #onPostRemove(IoFilterChain, String, NextFilter)} is invoked to
68 * notify that the filter is removed from the chain.</li>
69 * <li>{@link #destroy()} is invoked by {@link ReferenceCountingIoFilter} if
70 * the removed filter was the last one.</li>
71 * </ol>
72 *
73 * @author The Apache Directory Project (mina-dev@directory.apache.org)
74 * @version $Rev: 599822 $, $Date: 2007-11-30 22:54:07 +0900 (Fri, 30 Nov 2007) $
75 *
76 * @see IoFilterAdapter
77 */
78 public interface IoFilter {
79 /**
80 * Invoked by {@link ReferenceCountingIoFilter} when this filter
81 * is added to a {@link IoFilterChain} at the first time, so you can
82 * initialize shared resources. Please note that this method is never
83 * called if you don't wrap a filter with {@link ReferenceCountingIoFilter}.
84 */
85 void init() throws Exception;
86
87 /**
88 * Invoked by {@link ReferenceCountingIoFilter} when this filter
89 * is not used by any {@link IoFilterChain} anymore, so you can destroy
90 * shared resources. Please note that this method is never called if
91 * you don't wrap a filter with {@link ReferenceCountingIoFilter}.
92 */
93 void destroy() throws Exception;
94
95 /**
96 * Invoked before this filter is added to the specified <tt>parent</tt>.
97 * Please note that this method can be invoked more than once if
98 * this filter is added to more than one parents. This method is not
99 * invoked before {@link #init()} is invoked.
100 *
101 * @param parent the parent who called this method
102 * @param name the name assigned to this filter
103 * @param nextFilter the {@link NextFilter} for this filter. You can reuse
104 * this object until this filter is removed from the chain.
105 */
106 void onPreAdd(IoFilterChain parent, String name, NextFilter nextFilter)
107 throws Exception;
108
109 /**
110 * Invoked after this filter is added to the specified <tt>parent</tt>.
111 * Please note that this method can be invoked more than once if
112 * this filter is added to more than one parents. This method is not
113 * invoked before {@link #init()} is invoked.
114 *
115 * @param parent the parent who called this method
116 * @param name the name assigned to this filter
117 * @param nextFilter the {@link NextFilter} for this filter. You can reuse
118 * this object until this filter is removed from the chain.
119 */
120 void onPostAdd(IoFilterChain parent, String name, NextFilter nextFilter)
121 throws Exception;
122
123 /**
124 * Invoked before this filter is removed from the specified <tt>parent</tt>.
125 * Please note that this method can be invoked more than once if
126 * this filter is removed from more than one parents.
127 * This method is always invoked before {@link #destroy()} is invoked.
128 *
129 * @param parent the parent who called this method
130 * @param name the name assigned to this filter
131 * @param nextFilter the {@link NextFilter} for this filter. You can reuse
132 * this object until this filter is removed from the chain.
133 */
134 void onPreRemove(IoFilterChain parent, String name, NextFilter nextFilter)
135 throws Exception;
136
137 /**
138 * Invoked after this filter is removed from the specified <tt>parent</tt>.
139 * Please note that this method can be invoked more than once if
140 * this filter is removed from more than one parents.
141 * This method is always invoked before {@link #destroy()} is invoked.
142 *
143 * @param parent the parent who called this method
144 * @param name the name assigned to this filter
145 * @param nextFilter the {@link NextFilter} for this filter. You can reuse
146 * this object until this filter is removed from the chain.
147 */
148 void onPostRemove(IoFilterChain parent, String name, NextFilter nextFilter)
149 throws Exception;
150
151 /**
152 * Filters {@link IoHandler#sessionCreated(IoSession)} event.
153 */
154 void sessionCreated(NextFilter nextFilter, IoSession session)
155 throws Exception;
156
157 /**
158 * Filters {@link IoHandler#sessionOpened(IoSession)} event.
159 */
160 void sessionOpened(NextFilter nextFilter, IoSession session)
161 throws Exception;
162
163 /**
164 * Filters {@link IoHandler#sessionClosed(IoSession)} event.
165 */
166 void sessionClosed(NextFilter nextFilter, IoSession session)
167 throws Exception;
168
169 /**
170 * Filters {@link IoHandler#sessionIdle(IoSession,IdleStatus)}
171 * event.
172 */
173 void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status)
174 throws Exception;
175
176 /**
177 * Filters {@link IoHandler#exceptionCaught(IoSession,Throwable)}
178 * event.
179 */
180 void exceptionCaught(NextFilter nextFilter, IoSession session,
181 Throwable cause) throws Exception;
182
183 /**
184 * Filters {@link IoHandler#messageReceived(IoSession,Object)}
185 * event.
186 */
187 void messageReceived(NextFilter nextFilter, IoSession session,
188 Object message) throws Exception;
189
190 /**
191 * Filters {@link IoHandler#messageSent(IoSession,Object)}
192 * event.
193 */
194 void messageSent(NextFilter nextFilter, IoSession session, Object message)
195 throws Exception;
196
197 /**
198 * Filters {@link IoSession#close()} method invocation.
199 */
200 void filterClose(NextFilter nextFilter, IoSession session) throws Exception;
201
202 /**
203 * Filters {@link IoSession#write(Object)} method invocation.
204 */
205 void filterWrite(NextFilter nextFilter, IoSession session,
206 WriteRequest writeRequest) throws Exception;
207
208 /**
209 * Represents the next {@link IoFilter} in {@link IoFilterChain}.
210 */
211 public interface NextFilter {
212 /**
213 * Forwards <tt>sessionCreated</tt> event to next filter.
214 */
215 void sessionCreated(IoSession session);
216
217 /**
218 * Forwards <tt>sessionOpened</tt> event to next filter.
219 */
220 void sessionOpened(IoSession session);
221
222 /**
223 * Forwards <tt>sessionClosed</tt> event to next filter.
224 */
225 void sessionClosed(IoSession session);
226
227 /**
228 * Forwards <tt>sessionIdle</tt> event to next filter.
229 */
230 void sessionIdle(IoSession session, IdleStatus status);
231
232 /**
233 * Forwards <tt>exceptionCaught</tt> event to next filter.
234 */
235 void exceptionCaught(IoSession session, Throwable cause);
236
237 /**
238 * Forwards <tt>messageReceived</tt> event to next filter.
239 */
240 void messageReceived(IoSession session, Object message);
241
242 /**
243 * Forwards <tt>messageSent</tt> event to next filter.
244 */
245 void messageSent(IoSession session, Object message);
246
247 /**
248 * Forwards <tt>filterWrite</tt> event to next filter.
249 */
250 void filterWrite(IoSession session, WriteRequest writeRequest);
251
252 /**
253 * Forwards <tt>filterClose</tt> event to next filter.
254 */
255 void filterClose(IoSession session);
256 }
257
258 /**
259 * Represents write request fired by {@link IoSession#write(Object)}.
260 */
261 public static class WriteRequest {
262 private static final WriteFuture UNUSED_FUTURE = new WriteFuture() {
263 public boolean isWritten() {
264 return false;
265 }
266
267 public void setWritten(boolean written) {
268 }
269
270 public IoSession getSession() {
271 return null;
272 }
273
274 public void join() {
275 }
276
277 public boolean join(long timeoutInMillis) {
278 return true;
279 }
280
281 public boolean isReady() {
282 return true;
283 }
284
285 public void addListener(IoFutureListener listener) {
286 throw new IllegalStateException(
287 "You can't add a listener to a dummy future.");
288 }
289
290 public void removeListener(IoFutureListener listener) {
291 throw new IllegalStateException(
292 "You can't add a listener to a dummy future.");
293 }
294
295 public Object getLock() {
296 return this;
297 }
298 };
299
300 private final Object message;
301
302 private final WriteFuture future;
303
304 private final SocketAddress destination;
305
306 /**
307 * Creates a new instance without {@link WriteFuture}. You'll get
308 * an instance of {@link WriteFuture} even if you called this constructor
309 * because {@link #getFuture()} will return a bogus future.
310 */
311 public WriteRequest(Object message) {
312 this(message, null, null);
313 }
314
315 /**
316 * Creates a new instance with {@link WriteFuture}.
317 */
318 public WriteRequest(Object message, WriteFuture future) {
319 this(message, future, null);
320 }
321
322 /**
323 * Creates a new instance.
324 *
325 * @param message a message to write
326 * @param future a future that needs to be notified when an operation is finished
327 * @param destination the destination of the message. This property will be
328 * ignored unless the transport supports it.
329 */
330 public WriteRequest(Object message, WriteFuture future,
331 SocketAddress destination) {
332 if (message == null) {
333 throw new NullPointerException("message");
334 }
335
336 if (future == null) {
337 future = UNUSED_FUTURE;
338 }
339
340 this.message = message;
341 this.future = future;
342 this.destination = destination;
343 }
344
345 /**
346 * Returns {@link WriteFuture} that is associated with this write request.
347 */
348 public WriteFuture getFuture() {
349 return future;
350 }
351
352 /**
353 * Returns a message object to be written.
354 */
355 public Object getMessage() {
356 return message;
357 }
358
359 /**
360 * Returne the destination of this write request.
361 *
362 * @return <tt>null</tt> for the default destination
363 */
364 public SocketAddress getDestination() {
365 return destination;
366 }
367
368 @Override
369 public String toString() {
370 return message.toString();
371 }
372 }
373 }