KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > myvietnam > mvncore > security > FloodControl


1 /*
2  * $Header: /cvsroot/mvnforum/myvietnam/src/net/myvietnam/mvncore/security/FloodControl.java,v 1.12 2006/04/15 02:59:19 minhnn Exp $
3  * $Author: minhnn $
4  * $Revision: 1.12 $
5  * $Date: 2006/04/15 02:59:19 $
6  *
7  * ====================================================================
8  *
9  * Copyright (C) 2002-2006 by MyVietnam.net
10  *
11  * All copyright notices regarding MyVietnam and MyVietnam CoreLib
12  * MUST remain intact in the scripts and source code.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27  *
28  * Correspondence and Marketing Questions can be sent to:
29  * info at MyVietnam net
30  *
31  * @author: Minh Nguyen
32  * @author: Mai Nguyen
33  */

34 package net.myvietnam.mvncore.security;
35
36 import java.util.*;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import net.myvietnam.mvncore.exception.FloodException;
41 import net.myvietnam.mvncore.util.DateUtil;
42
43 /**
44  * This class is used to control the number of actions per hour. This is usually
45  * used to prevent the flood of any action. You should call FloodControl.setOption()
46  * when your application is inited.
47  * <p>
48  * Note that the action id from 0 to 999 is belong to mvnCore, application used it
49  * should not use the value in this range
50  */

51 public class FloodControl {
52
53     private static Log log = LogFactory.getLog(FloodControl.class);
54
55     /** The value from 0 to 999 should belong to mvnCore */
56     public static int MAX_MVNCORE_ACTION_ID = 999;
57
58     private static Map actionControlMap = new TreeMap();
59
60     static final long REMOVE_INTERVAL = DateUtil.MINUTE * 2;//2 minutes
61

62     private FloodControl() {
63     }
64
65     /**
66      * To set the mamximum number of actions per hour for an action.
67      * If the caller does not call this method, the the action has no limit
68      * @param action Integer the action that want to set the option
69      * @param actionsPerHour int the maximum number of actions per hour
70      */

71     public static void setOption(Integer JavaDoc action, int actionsPerHour) {
72         getControlledAction(action).setActionsPerHour(actionsPerHour);
73     }
74
75     public static int getActionsPerHour(Integer JavaDoc action) {
76         return getControlledAction(action).getActionsPerHour();
77     }
78
79     /**
80      * Check that an action of an IP has reach the maximum number of allowed times
81      * @param action Integer the action to check
82      * @param strIP String the IP to check
83      * @return boolean true if it has reached the maximum
84      */

85     public static boolean reachMaximum(Integer JavaDoc action, String JavaDoc strIP) {
86         return getControlledAction(action).reachMaximum(strIP);
87     }
88
89     /**
90      * This is a utility method to ensure that the action has not reached the mamximum.
91      * It calls the method reachMaximum and throw an exception if it reached the maximum.
92      * A program could use this method to use the default error message, otherwise
93      * it has to use reachMaximum
94      * @param action Integer the action to ensure
95      * @param strIP String the IP to ensure
96      * @throws FloodException if it reached the maximum
97      * @see FloodControl#reachMaximum(Integer, String)
98      */

99     public static void ensureNotReachMaximum(Integer JavaDoc action, String JavaDoc strIP) throws FloodException {
100         if (reachMaximum(action, strIP)) {
101             log.info("Attempt to exceed the maximum number of actions: ActionID = " + action + " and IP = " + strIP);
102             //@todo : localize me
103
throw new FloodException("You have reached the maximum number of actions for this page (actionID = " + action + "). Please try this page later. This is to prevent forum from being flooded.");
104         }
105     }
106
107     /**
108      * Increase the number of action. This method should be called the the program
109      * has done this action. Forget to call this method will void the reachMaximum method.
110      * @param action Integer the action to increase the number of times
111      * @param strIP String the IP to increase the number of times
112      */

113     public static void increaseCount(Integer JavaDoc action, String JavaDoc strIP) {
114         getControlledAction(action).increaseCount(strIP);
115     }
116
117     /**
118      * Reset the action history. This method is useful in such a case in the login
119      * process that after login successfully, the value should be reset. Please note
120      * that this is just an example and usually no need to use this method.
121      * @param action Integer
122      * @param strIP String
123      */

124     public static void resetActionHistory(Integer JavaDoc action, String JavaDoc strIP) {
125         getControlledAction(action).resetActionHistory(strIP);
126     }
127
128     /**
129      * Return the instance of ControlledAction for the action. It will create
130      * new instance if no previous instance for this action exist.
131      * @param action Integer
132      * @return ControlledAction
133      */

134     private static synchronized ControlledAction getControlledAction(Integer JavaDoc action) {
135         ControlledAction controlledAction = (ControlledAction)actionControlMap.get(action);
136         if (controlledAction == null) {
137             controlledAction = new ControlledAction();
138             actionControlMap.put(action, controlledAction);
139         }
140         return controlledAction;
141     }
142 }
143
144 /**
145  * For one action that handles a list of all IP
146  */

147 class ControlledAction {
148     private int actionsPerHour = 0;
149     private Map ipMap = new TreeMap();
150     private long lastRemoveTime = 0;
151
152     void setActionsPerHour(int actionsPerHour) {
153         if (actionsPerHour >= 0) {
154             this.actionsPerHour = actionsPerHour;
155         }
156     }
157
158     int getActionsPerHour() {
159         return actionsPerHour;
160     }
161
162     boolean reachMaximum(String JavaDoc strIP) {
163         removeTimeoutControlledIP();
164         return getControlledIP(strIP).reachMaximum();
165     }
166
167     void increaseCount(String JavaDoc strIP) {
168         removeTimeoutControlledIP();
169         getControlledIP(strIP).increaseCount();
170     }
171
172     void resetActionHistory(String JavaDoc strIP) {
173         removeTimeoutControlledIP();
174         getControlledIP(strIP).resetActionHistory();
175     }
176
177     private synchronized ControlledIP getControlledIP(String JavaDoc strIP) {
178         ControlledIP controlledIP = (ControlledIP)ipMap.get(strIP);
179         if (controlledIP == null) {
180             controlledIP = new ControlledIP(actionsPerHour);
181             ipMap.put(strIP, controlledIP);
182         } else {
183             // there is a ControlledIP, update the actionsPerHour
184
controlledIP.setActionsPerHour(actionsPerHour);
185         }
186         return controlledIP;
187     }
188
189     private synchronized void removeTimeoutControlledIP() {
190         long now = System.currentTimeMillis();
191         if ((now - lastRemoveTime) > FloodControl.REMOVE_INTERVAL) {
192             lastRemoveTime = now;
193             Collection ipList = ipMap.values();
194             for (Iterator iter = ipList.iterator(); iter.hasNext(); ) {
195                 ControlledIP currentControlledIP = (ControlledIP)iter.next();
196                 if (now - currentControlledIP.getLastIncrementTime() > DateUtil.HOUR) {
197                     iter.remove();
198                 }
199             }
200         }
201     }
202 }
203
204 /**
205  * For one action per one IP
206  */

207 class ControlledIP {
208     private int actionsPerHour = 0;
209     private long lastRemoveTime = 0;
210     private long lastIncrementTime = 0;
211     private ArrayList actionHistoryList = new ArrayList();
212
213     ControlledIP(int actionsPerHour) {
214         if (actionsPerHour >= 0) {
215             this.actionsPerHour = actionsPerHour;
216         }
217     }
218
219     void setActionsPerHour(int actionsPerHour) {
220         if (actionsPerHour >= 0) {
221             this.actionsPerHour = actionsPerHour;
222         }
223     }
224
225     long getLastIncrementTime() {
226         return lastIncrementTime;
227     }
228
229     void increaseCount() {
230         long now = System.currentTimeMillis();
231         lastIncrementTime = now;
232         actionHistoryList.add(new Long JavaDoc(now));
233     }
234
235     void resetActionHistory() {
236         lastRemoveTime = 0;
237         lastIncrementTime = 0;
238         actionHistoryList.clear();
239     }
240
241     boolean reachMaximum() {
242         if (actionsPerHour == 0) {//unlimited
243
return false;
244         }
245
246         if (actionHistoryList.size() < actionsPerHour) {
247             return false;
248         }
249
250         // now try to remove timeout actions
251
removeTimeoutActions();
252
253         return (actionHistoryList.size() >= actionsPerHour);
254     }
255
256     private synchronized void removeTimeoutActions() {
257         long now = System.currentTimeMillis();
258         if (now - lastRemoveTime > FloodControl.REMOVE_INTERVAL) {
259             lastRemoveTime = now;
260             for (Iterator iter = actionHistoryList.iterator(); iter.hasNext(); ) {
261                 Long JavaDoc currentAction = (Long JavaDoc)iter.next();
262                 if ((now - currentAction.longValue()) > DateUtil.HOUR) {
263                     iter.remove();
264                 }
265             } //for
266
}
267     }
268 }
269
Popular Tags