KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xsocket > stream > HandlerChain


1 // $Id: HandlerChain.java 1312 2007-06-09 12:39:47Z grro $
2

3 /*
4  * Copyright (c) xsocket.org, 2006 - 2007. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
21  * The latest copy of this software may be found on http://www.xsocket.org/
22  */

23
24 package org.xsocket.stream;
25
26 import java.io.IOException JavaDoc;
27 import java.lang.reflect.Array JavaDoc;
28 import java.lang.reflect.Field JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Arrays JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.logging.Level JavaDoc;
33 import java.util.logging.Logger JavaDoc;
34
35 import org.xsocket.Resource;
36
37
38
39
40 /**
41  * Implements a handler chain. Each handler of the chain will be called (in the registering order),
42  * until one handler signal by the return value true, that the event has been handled. In
43  * this case the remaing handlers will not be called.
44  *
45  * <br>
46  * E.g.
47  * <pre>
48  * ...
49  * HandlerChain tcpBasedSpamfilter = new HandlerChain();
50  * tcpBasedSpamfilter.addLast(new BlackIPFilter());
51  * tcpBasedSpamfilter.addLast(new FirstConnectRefuseFilter());
52  *
53  * HandlerChain mainChain = new HandlerChain();
54  * mainChain.addLast(tcpBasedSpamfilter);
55  * mainChain.addLast(new SmtpProtocolHandler());
56  *
57  * IMultithreadedServer smtpServer = new MultithreadedServer(port, mainChain);
58  * StreamUtils.start(server);
59  * ...
60  *
61  * </pre>
62
63  *
64  *
65  * @author grro@xsocket.org
66  */

67 public final class HandlerChain implements IHandler, IConnectHandler, IDisconnectHandler, IDataHandler, ITimeoutHandler, IConnectionScoped, org.xsocket.ILifeCycle {
68
69     private static final Logger JavaDoc LOG = Logger.getLogger(HandlerChain.class.getName());
70     
71     private IHandler[] handlers = new IHandler[0];
72     private Integer JavaDoc[] connectionScopedIndex = new Integer JavaDoc[0];
73
74     private Integer JavaDoc[] connectHandlerChain = new Integer JavaDoc[0];
75     private Integer JavaDoc[] disconnectHandlerChain = new Integer JavaDoc[0];
76     private Integer JavaDoc[] dataHandlerChain = new Integer JavaDoc[0];
77     private Integer JavaDoc[] timeoutHandlerChain = new Integer JavaDoc[0];
78     private Integer JavaDoc[] lifeCycleChain = new Integer JavaDoc[0];
79
80     private List JavaDoc<HandlerChain> enclosingChains = new ArrayList JavaDoc<HandlerChain>();
81     
82     
83     @Resource
84     private IServerContext ctx = null;
85
86     
87     
88
89     /**
90      * constructor
91      *
92      */

93     public HandlerChain() {
94         
95     }
96
97     
98     /**
99      * constructor
100      *
101      * @param handlers the initial handlers
102      */

103     public HandlerChain(List JavaDoc<IHandler> handlers) {
104         for (IHandler hdl : handlers) {
105             addLast(hdl);
106         }
107     }
108     
109     /**
110      * add a handler to the end og the chain
111      *
112      * @param handler the handler to add
113      */

114     public void addLast(IHandler handler) {
115         int pos = handlers.length;
116         handlers = incArray(handlers, handler);
117         
118         if (handler instanceof IConnectHandler) {
119             connectHandlerChain = incArray(connectHandlerChain, pos);
120         }
121         
122         if (handler instanceof IDisconnectHandler) {
123             disconnectHandlerChain = incArray(disconnectHandlerChain, pos);
124         }
125
126         
127         if (handler instanceof IDataHandler) {
128             dataHandlerChain = incArray(dataHandlerChain, pos);
129         }
130
131         if (handler instanceof ITimeoutHandler) {
132             timeoutHandlerChain = incArray(timeoutHandlerChain, pos);
133         }
134         
135         if (handler instanceof org.xsocket.ILifeCycle) {
136             lifeCycleChain = incArray(lifeCycleChain, pos);
137         }
138
139         
140         // if handler chain
141
if (handler instanceof HandlerChain) {
142             ((HandlerChain) handler).addEnclosingChain(this);
143         }
144                 
145         
146         // handle scope
147
if (handler instanceof IConnectionScoped) {
148             updateScope(pos, true);
149         } else {
150             updateScope(pos, false);
151         }
152     }
153     
154     
155     private void addEnclosingChain(HandlerChain enclosingChain) {
156         if (enclosingChains == null) {
157             enclosingChains = new ArrayList JavaDoc<HandlerChain>();
158         }
159         enclosingChains.add(enclosingChain);
160     }
161     
162
163     private void updateScope(IHandler handler, boolean isConnectionScoped) {
164         for (int i = 0; i < handlers.length; i++) {
165             if (handlers[i] == handler) {
166                 updateScope(i, isConnectionScoped);
167                 return;
168             }
169         }
170     }
171     
172     private void updateScope(int pos, boolean isConnectionScoped) {
173         if (isConnectionScoped) {
174             connectionScopedIndex = incArray(connectionScopedIndex, pos);
175             
176             if (enclosingChains != null) {
177                 for (HandlerChain chain : enclosingChains) {
178                     chain.updateScope(this, true);
179                 }
180             }
181         }
182     }
183
184     
185     /**
186      * {@inheritDoc}
187      */

188     public void onInit() {
189         
190         for (IHandler handler : handlers) {
191             Field JavaDoc[] fields = handler.getClass().getDeclaredFields();
192             for (Field JavaDoc field : fields) {
193                 if (field.getAnnotation(Resource.class) != null) {
194                     field.setAccessible(true);
195                     try {
196                         field.set(handler, ctx);
197                     } catch (IllegalAccessException JavaDoc iae) {
198                         LOG.warning("couldn't set HandlerContext for attribute " + field.getName() + ". Reason " + iae.toString());
199                     }
200                     
201                 }
202             }
203         }
204         
205         
206         for (Integer JavaDoc pos : lifeCycleChain) {
207             ((org.xsocket.ILifeCycle) handlers[pos]).onInit();
208         }
209     }
210
211
212     /**
213      * {@inheritDoc}
214      */

215     public void onDestroy() {
216         for (Integer JavaDoc pos : lifeCycleChain) {
217             ((org.xsocket.ILifeCycle) handlers[pos]).onDestroy();
218         }
219     }
220     
221     
222     /**
223      * {@inheritDoc}
224      */

225     public boolean onConnect(INonBlockingConnection connection) throws IOException JavaDoc {
226         for (Integer JavaDoc pos : connectHandlerChain) {
227             boolean result = ((IConnectHandler) handlers[pos]).onConnect(connection);
228             if (result == true) {
229                 return true;
230             }
231         }
232         
233         return false;
234     }
235     
236
237     /**
238      * {@inheritDoc}
239      */

240     public boolean onDisconnect(INonBlockingConnection connection) throws IOException JavaDoc {
241         for (Integer JavaDoc pos : disconnectHandlerChain) {
242             boolean result = ((IDisconnectHandler) handlers[pos]).onDisconnect(connection);
243             if (result == true) {
244                 return true;
245             }
246         }
247         
248         return false;
249     }
250
251     /**
252      * {@inheritDoc}
253      */

254     public boolean onData(INonBlockingConnection connection) throws IOException JavaDoc {
255         for (Integer JavaDoc pos : dataHandlerChain) {
256             boolean result = ((IDataHandler) handlers[pos]).onData(connection);
257             if (result == true) {
258                 return true;
259             }
260         }
261         
262         return false;
263     }
264     
265
266     /**
267      * {@inheritDoc}
268      */

269     public boolean onConnectionTimeout(INonBlockingConnection connection) throws IOException JavaDoc {
270         for (Integer JavaDoc pos : timeoutHandlerChain) {
271             boolean result = ((ITimeoutHandler) handlers[pos]).onConnectionTimeout(connection);
272             if (result == true) {
273                 return true;
274             }
275         }
276         
277         return false;
278     }
279
280     
281     /**
282      * {@inheritDoc}
283      */

284     public boolean onIdleTimeout(INonBlockingConnection connection) throws IOException JavaDoc {
285         for (Integer JavaDoc pos : timeoutHandlerChain) {
286             boolean result = ((ITimeoutHandler) handlers[pos]).onIdleTimeout(connection);
287             if (result == true) {
288                 return true;
289             }
290         }
291         
292         return false;
293
294     }
295
296     
297     /**
298      * only for test purposes
299      *
300      * @param pos the postion of the handler
301      * @return handler
302      */

303     IHandler getHandler(int pos) {
304         return handlers[pos];
305     };
306     
307     
308     
309     /**
310      * {@inheritDoc}
311      */

312     @Override JavaDoc
313     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
314         
315         if (connectionScopedIndex.length > 0) {
316             HandlerChain clone = (HandlerChain) super.clone();
317             clone.handlers = handlers.clone();
318             
319             for (int i =0; i < connectionScopedIndex.length; i++) {
320                 int position = connectionScopedIndex[i];
321                 clone.handlers[position] = (IHandler) ((IConnectionScoped) handlers[position]).clone();
322             }
323             
324             return clone;
325         
326         } else {
327             if (LOG.isLoggable(Level.FINEST)) {
328                 LOG.finest(this.getClass().getSimpleName() + " doesn't contain connection-specific handlers. return current instance as clone");
329             }
330             return this;
331         }
332     }
333
334     @SuppressWarnings JavaDoc("unchecked")
335     private static <T> T[] incArray(T[] original, T newElement) {
336         T[] newArray = (T[]) copyOf(original, original.length + 1, original.getClass());
337         newArray[original.length] = newElement;
338         
339         return newArray;
340     }
341     
342     /**
343      * @see Arrays (Java 1.6)
344      */

345     @SuppressWarnings JavaDoc("unchecked")
346     private static <T,U> T[] copyOf(U[] original, int newLength, Class JavaDoc<? extends T[]> newType) {
347          T[] copy = ((Object JavaDoc)newType == (Object JavaDoc)Object JavaDoc[].class)
348                         ? (T[]) new Object JavaDoc[newLength]
349                         : (T[]) Array.newInstance(newType.getComponentType(), newLength);
350          System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
351      return copy;
352     }
353 }
354
Popular Tags