View Javadoc

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: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13  7월 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 
296         private final Object message;
297 
298         private final WriteFuture future;
299 
300         private final SocketAddress destination;
301 
302         /**
303          * Creates a new instance without {@link WriteFuture}.  You'll get
304          * an instance of {@link WriteFuture} even if you called this constructor
305          * because {@link #getFuture()} will return a bogus future.
306          */
307         public WriteRequest(Object message) {
308             this(message, null, null);
309         }
310 
311         /**
312          * Creates a new instance with {@link WriteFuture}.
313          */
314         public WriteRequest(Object message, WriteFuture future) {
315             this(message, future, null);
316         }
317 
318         /**
319          * Creates a new instance.
320          * 
321          * @param message a message to write
322          * @param future a future that needs to be notified when an operation is finished
323          * @param destination the destination of the message.  This property will be
324          *                    ignored unless the transport supports it.
325          */
326         public WriteRequest(Object message, WriteFuture future,
327                 SocketAddress destination) {
328             if (message == null) {
329                 throw new NullPointerException("message");
330             }
331 
332             if (future == null) {
333                 future = UNUSED_FUTURE;
334             }
335 
336             this.message = message;
337             this.future = future;
338             this.destination = destination;
339         }
340 
341         /**
342          * Returns {@link WriteFuture} that is associated with this write request.
343          */
344         public WriteFuture getFuture() {
345             return future;
346         }
347 
348         /**
349          * Returns a message object to be written.
350          */
351         public Object getMessage() {
352             return message;
353         }
354 
355         /**
356          * Returne the destination of this write request.
357          * 
358          * @return <tt>null</tt> for the default destination
359          */
360         public SocketAddress getDestination() {
361             return destination;
362         }
363 
364         public String toString() {
365             return message.toString();
366         }
367     }
368 }