log fixed
[mir.git] / source / mircoders / global / Abuse.java
1 /*\r
2  * Copyright (C) 2001, 2002 The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with  any library licensed under the Apache Software License,\r
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
23  * (or with modified versions of the above that use the same license as the above),\r
24  * and distribute linked combinations including the two.  You must obey the\r
25  * GNU General Public License in all respects for all of the code used other than\r
26  * the above mentioned libraries.  If you modify this file, you may extend this\r
27  * exception to your version of the file, but you are not obligated to do so.\r
28  * If you do not wish to do so, delete this exception statement from your version.\r
29  */\r
30 \r
31 package mircoders.global;\r
32 \r
33 import java.io.File;\r
34 import java.io.FileNotFoundException;\r
35 import java.io.FileOutputStream;\r
36 import java.util.Arrays;\r
37 import java.util.Date;\r
38 import java.util.GregorianCalendar;\r
39 import java.util.HashMap;\r
40 import java.util.Iterator;\r
41 import java.util.List;\r
42 import java.util.Map;\r
43 import java.util.Random;\r
44 import java.util.Vector;\r
45 import javax.servlet.http.Cookie;\r
46 import javax.servlet.http.HttpServletResponse;\r
47 \r
48 import org.apache.commons.collections.ExtendedProperties;\r
49 import mir.config.MirPropertiesConfiguration;\r
50 import mir.entity.Entity;\r
51 import mir.log.LoggerWrapper;\r
52 import mir.session.Request;\r
53 import mir.util.GeneratorFormatAdapters;\r
54 import mir.util.StringRoutines;\r
55 import mircoders.entity.EntityComment;\r
56 import mircoders.entity.EntityContent;\r
57 import mircoders.entity.EntityUsers;\r
58 import mircoders.localizer.MirAdminInterfaceLocalizer;\r
59 import mircoders.localizer.MirAntiAbuseFilterType;\r
60 \r
61 \r
62 public class Abuse {\r
63   private List filterRules;\r
64   private Map filterTypes;\r
65   private List filterTypeIds;\r
66   private int maxIdentifier;\r
67   private LoggerWrapper logger;\r
68   private LoggerWrapper adminUsageLogger;\r
69   private int logSize;\r
70   private boolean logEnabled;\r
71   private boolean openPostingDisabled;\r
72   private boolean openPostingPassword;\r
73   private boolean cookieOnBlock;\r
74   private String articleBlockAction;\r
75   private String commentBlockAction;\r
76   private List log;\r
77   private String configFile = MirGlobal.config().getStringWithHome("Abuse.Config");\r
78 \r
79   private MirPropertiesConfiguration configuration;\r
80 \r
81   private static String cookieName=MirGlobal.config().getString("Abuse.CookieName");\r
82   private static int cookieMaxAge = 60*60*MirGlobal.config().getInt("Abuse.CookieMaxAge");\r
83 \r
84   public Abuse() {\r
85     logger = new LoggerWrapper("Global.Abuse");\r
86     adminUsageLogger = new LoggerWrapper("AdminUsage");\r
87     filterRules = new Vector();\r
88     maxIdentifier = 0;\r
89     log = new Vector();\r
90 \r
91     try {\r
92       configuration = MirPropertiesConfiguration.instance();\r
93     }\r
94     catch (Throwable e) {\r
95       throw new RuntimeException("Can't get configuration: " + e.getMessage());\r
96     }\r
97 \r
98     logSize = 100;\r
99     logEnabled = false;\r
100     articleBlockAction = "";\r
101     commentBlockAction = "";\r
102     openPostingPassword = false;\r
103     openPostingDisabled = false;\r
104     cookieOnBlock = false;\r
105 \r
106     try {\r
107       filterTypes = new HashMap();\r
108       filterTypeIds = new Vector();\r
109 \r
110       Iterator i = MirGlobal.localizer().openPostings().getAntiAbuseFilterTypes().iterator();\r
111 \r
112       while (i.hasNext()) {\r
113         MirAntiAbuseFilterType filterType = (MirAntiAbuseFilterType) i.next();\r
114         filterTypes.put(filterType.getName(), filterType);\r
115         filterTypeIds.add(filterType.getName());\r
116       }\r
117     }\r
118     catch (Throwable t) {\r
119       throw new RuntimeException("Can't get filter types: " + t.getMessage());\r
120     }\r
121 \r
122     load();\r
123   }\r
124 \r
125   private void setCookie(HttpServletResponse aResponse) {\r
126     Random random = new Random();\r
127 \r
128     Cookie cookie = new Cookie(cookieName, Integer.toString(random.nextInt(1000000000)));\r
129     cookie.setMaxAge(cookieMaxAge);\r
130     cookie.setPath("/");\r
131 \r
132     if (aResponse!=null)\r
133       aResponse.addCookie(cookie);\r
134   }\r
135 \r
136   private boolean checkCookie(List aCookies) {\r
137     if (getCookieOnBlock()) {\r
138       Iterator i = aCookies.iterator();\r
139 \r
140       while (i.hasNext()) {\r
141         Cookie cookie = (Cookie) i.next();\r
142 \r
143         if (cookie.getName().equals(cookieName)) {\r
144           logger.debug("cookie match");\r
145           return true;\r
146         }\r
147       }\r
148     }\r
149 \r
150     return false;\r
151   }\r
152 \r
153   FilterRule findMatchingFilter(Entity anEntity, Request aRequest) {\r
154     Iterator iterator = filterRules.iterator();\r
155 \r
156     while (iterator.hasNext()) {\r
157       FilterRule rule = (FilterRule) iterator.next();\r
158 \r
159       if (rule.test(anEntity, aRequest))\r
160         return rule;\r
161     }\r
162 \r
163     return null;\r
164   }\r
165 \r
166   public void checkComment(EntityComment aComment, Request aRequest, HttpServletResponse aResponse) {\r
167     logComment(aComment, aRequest);\r
168 \r
169     try {\r
170       long time = System.currentTimeMillis();\r
171 \r
172       FilterRule filterRule = findMatchingFilter(aComment, aRequest);\r
173 \r
174       if (filterRule!=null) {\r
175         logger.debug("Match for " + filterRule.getType()+" rule '"+ filterRule.getExpression()+"'");\r
176         filterRule.setLastHit(new GregorianCalendar().getTime());\r
177         MirGlobal.performCommentOperation(null, aComment, filterRule.getCommentAction());\r
178         setCookie(aResponse);\r
179       }\r
180 \r
181       logger.debug("checkComment: " + (System.currentTimeMillis()-time) + "ms");\r
182     }\r
183     catch (Throwable t) {\r
184       t.printStackTrace(logger.asPrintWriter(logger.DEBUG_MESSAGE));\r
185       logger.error("Abuse.checkComment: " + t.toString());\r
186     }\r
187   }\r
188 \r
189   public void checkArticle(EntityContent anArticle, Request aRequest, HttpServletResponse aResponse) {\r
190     logArticle(anArticle, aRequest);\r
191 \r
192     try {\r
193       long time = System.currentTimeMillis();\r
194 \r
195       FilterRule filterRule = findMatchingFilter(anArticle, aRequest);\r
196 \r
197       if (filterRule!=null) {\r
198         logger.debug("Match for " + filterRule.getType() + " rule '" + filterRule.getExpression()+"'");\r
199         filterRule.setLastHit(new GregorianCalendar().getTime());\r
200         MirGlobal.performArticleOperation(null, anArticle, filterRule.getArticleAction());\r
201         setCookie(aResponse);\r
202       }\r
203 \r
204       logger.info("checkArticle: " + (System.currentTimeMillis()-time) + "ms");\r
205     }\r
206     catch (Throwable t) {\r
207       t.printStackTrace(logger.asPrintWriter(logger.DEBUG_MESSAGE));\r
208       logger.error("Abuse.checkArticle: " + t.toString());\r
209     }\r
210   }\r
211 \r
212   public boolean getLogEnabled() {\r
213     return logEnabled;\r
214   }\r
215 \r
216   public void setLogEnabled(boolean anEnabled) {\r
217     if (!configuration.getString("Abuse.DisallowIPLogging", "0").equals("1"))\r
218       logEnabled = anEnabled;\r
219     truncateLog();\r
220   }\r
221 \r
222   public int getLogSize() {\r
223     return logSize;\r
224   }\r
225 \r
226   public void setLogSize(int aSize) {\r
227     logSize = aSize;\r
228     truncateLog();\r
229   }\r
230 \r
231   public boolean getOpenPostingDisabled() {\r
232     return openPostingDisabled;\r
233   }\r
234 \r
235   public void setOpenPostingDisabled(boolean anOpenPostingDisabled) {\r
236     openPostingDisabled = anOpenPostingDisabled;\r
237   }\r
238 \r
239   public boolean getOpenPostingPassword() {\r
240     return openPostingPassword;\r
241   }\r
242 \r
243   public void setOpenPostingPassword(boolean anOpenPostingPassword) {\r
244     openPostingPassword = anOpenPostingPassword;\r
245   }\r
246 \r
247   public boolean getCookieOnBlock() {\r
248     return cookieOnBlock;\r
249   }\r
250 \r
251   public void setCookieOnBlock(boolean aCookieOnBlock) {\r
252     cookieOnBlock = aCookieOnBlock;\r
253   }\r
254 \r
255   public String getArticleBlockAction() {\r
256     return articleBlockAction;\r
257   }\r
258 \r
259   public void setArticleBlockAction(String anAction) {\r
260     articleBlockAction = anAction;\r
261   }\r
262 \r
263   public String getCommentBlockAction() {\r
264     return commentBlockAction;\r
265   }\r
266 \r
267   public void setCommentBlockAction(String anAction) {\r
268     commentBlockAction = anAction;\r
269   }\r
270 \r
271   public List getLog() {\r
272     synchronized(log) {\r
273       try {\r
274         List result = new Vector();\r
275 \r
276         Iterator i = log.iterator();\r
277         while (i.hasNext()) {\r
278           LogEntry logEntry = (LogEntry) i.next();\r
279           Map entry = new HashMap();\r
280 \r
281           entry.put("ip", logEntry.getIpNumber());\r
282           entry.put("id", logEntry.getId());\r
283           entry.put("timestamp", new GeneratorFormatAdapters.DateFormatAdapter(logEntry.getTimeStamp(), MirPropertiesConfiguration.instance().getString("Mir.DefaultTimezone")));\r
284           if (logEntry.getIsArticle())\r
285             entry.put("type", "content");\r
286           else\r
287             entry.put("type", "comment");\r
288           entry.put("browser", logEntry.getBrowserString());\r
289 \r
290           result.add(entry);\r
291         }\r
292 \r
293         return result;\r
294       }\r
295       catch (Throwable t) {\r
296         throw new RuntimeException(t.toString());\r
297       }\r
298     }\r
299   }\r
300 \r
301   public void logComment(Entity aComment, Request aRequest) {\r
302     String ipAddress = aRequest.getHeader("ip");\r
303     String id = aComment.getId();\r
304     String browser = aRequest.getHeader("User-Agent");\r
305 \r
306     logComment(ipAddress, id, new Date(), browser);\r
307   }\r
308 \r
309   public void logArticle(Entity anArticle, Request aRequest) {\r
310     String ipAddress = aRequest.getHeader("ip");\r
311     String id = anArticle.getId();\r
312     String browser = aRequest.getHeader("User-Agent");\r
313 \r
314     logArticle(ipAddress, id, new Date(), browser);\r
315   }\r
316 \r
317   public void logComment(String anIp, String anId, Date aTimeStamp, String aBrowser) {\r
318     appendLog(new LogEntry(aTimeStamp, anIp, aBrowser, anId, false));\r
319   }\r
320 \r
321   public void logArticle(String anIp, String anId, Date aTimeStamp, String aBrowser) {\r
322     appendLog(new LogEntry(aTimeStamp, anIp, aBrowser, anId, true));\r
323   }\r
324 \r
325   public void load() {\r
326     try {\r
327       ExtendedProperties configuration = new ExtendedProperties();\r
328 \r
329       try {\r
330         configuration = new ExtendedProperties(configFile);\r
331       }\r
332       catch (FileNotFoundException e) {\r
333       }\r
334 \r
335       getFilterConfig(filterRules, "abuse.filter", configuration);\r
336 \r
337       setOpenPostingDisabled(configuration.getString("abuse.openPostingDisabled", "0").equals("1"));\r
338       setOpenPostingPassword(configuration.getString("abuse.openPostingPassword", "0").equals("1"));\r
339       setCookieOnBlock(configuration.getString("abuse.cookieOnBlock", "0").equals("1"));\r
340       setLogEnabled(configuration.getString("abuse.logEnabled", "0").equals("1"));\r
341       setLogSize(configuration.getInt("abuse.logSize", 10));\r
342       setArticleBlockAction(configuration.getString("abuse.articleBlockAction", ""));\r
343       setCommentBlockAction(configuration.getString("abuse.commentBlockAction", ""));\r
344     }\r
345     catch (Throwable t) {\r
346       throw new RuntimeException(t.toString());\r
347     }\r
348   }\r
349   public void save() {\r
350     try {\r
351       ExtendedProperties configuration = new ExtendedProperties();\r
352 \r
353       setFilterConfig(filterRules, "abuse.filter", configuration);\r
354 \r
355       configuration.addProperty("abuse.openPostingDisabled", getOpenPostingDisabled()?"1":"0");\r
356       configuration.addProperty("abuse.openPostingPassword", getOpenPostingPassword()?"1":"0");\r
357       configuration.addProperty("abuse.cookieOnBlock", getCookieOnBlock()?"1":"0");\r
358       configuration.addProperty("abuse.logEnabled", getLogEnabled()?"1":"0");\r
359       configuration.addProperty("abuse.logSize", Integer.toString(getLogSize()));\r
360       configuration.addProperty("abuse.articleBlockAction", getArticleBlockAction());\r
361       configuration.addProperty("abuse.commentBlockAction", getCommentBlockAction());\r
362 \r
363       configuration.save(new FileOutputStream(new File(configFile)), "Anti abuse configuration");\r
364     }\r
365     catch (Throwable t) {\r
366       throw new RuntimeException(t.toString());\r
367     }\r
368   }\r
369 \r
370   public List getFilterTypes() {\r
371     try {\r
372       List result = new Vector();\r
373 \r
374       Iterator i = filterTypeIds.iterator();\r
375       while (i.hasNext()) {\r
376         String id = (String) i.next();\r
377 \r
378         Map action = new HashMap();\r
379         action.put("resource", id);\r
380         action.put("identifier", id);\r
381 \r
382         result.add(action);\r
383       }\r
384 \r
385       return result;\r
386     }\r
387     catch (Throwable t) {\r
388       throw new RuntimeException("can't get article actions");\r
389     }\r
390   }\r
391 \r
392   public List getArticleActions() {\r
393     try {\r
394       List result = new Vector();\r
395 \r
396       Iterator i = MirGlobal.localizer().adminInterface().simpleArticleOperations().iterator();\r
397       while (i.hasNext()) {\r
398         MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =\r
399             (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();\r
400 \r
401         Map action = new HashMap();\r
402         action.put("resource", operation.getName());\r
403         action.put("identifier", operation.getName());\r
404 \r
405         result.add(action);\r
406       }\r
407 \r
408       return result;\r
409     }\r
410     catch (Throwable t) {\r
411       throw new RuntimeException("can't get article actions");\r
412     }\r
413   }\r
414 \r
415   public List getCommentActions() {\r
416     try {\r
417       List result = new Vector();\r
418 \r
419       Iterator i = MirGlobal.localizer().adminInterface().simpleCommentOperations().iterator();\r
420       while (i.hasNext()) {\r
421         MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =\r
422             (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();\r
423 \r
424         Map action = new HashMap();\r
425         action.put("resource", operation.getName());\r
426         action.put("identifier", operation.getName());\r
427 \r
428         result.add(action);\r
429       }\r
430 \r
431       return result;\r
432     }\r
433     catch (Throwable t) {\r
434       throw new RuntimeException("can't get comment actions");\r
435     }\r
436   }\r
437 \r
438   public List getFilters() {\r
439     List result = new Vector();\r
440 \r
441     synchronized(filterRules) {\r
442       Iterator i = filterRules.iterator();\r
443       while (i.hasNext()) {\r
444         FilterRule filter = (FilterRule) i.next();\r
445         result.add(filter.clone());\r
446       }\r
447       return result;\r
448     }\r
449   }\r
450 \r
451   public String addFilter(String aType, String anExpression, String aComments, String aCommentAction, String anArticleAction) {\r
452     return addFilter(filterRules, aType, anExpression, aComments, aCommentAction, anArticleAction);\r
453   }\r
454 \r
455   public FilterRule getFilter(String anId) {\r
456     synchronized (filterRules) {\r
457       FilterRule result = (FilterRule) findFilter(filterRules, anId);\r
458       if (result==null)\r
459         return result;\r
460       else\r
461         return (FilterRule) result.clone();\r
462     }\r
463   }\r
464 \r
465   public String setFilter(String anIdentifier, String aType, String anExpression, String aComments, String aCommentAction, String anArticleAction) {\r
466     return setFilter(filterRules, anIdentifier, aType, anExpression, aComments, aCommentAction, anArticleAction);\r
467   }\r
468 \r
469   public void deleteFilter(String anIdentifier) {\r
470     deleteFilter(filterRules, anIdentifier);\r
471   }\r
472 \r
473   private String addFilter(List aFilters, String aType, String anExpression, String aComments, String aCommentAction, String anArticleAction) {\r
474     MirAntiAbuseFilterType type = (MirAntiAbuseFilterType) filterTypes.get(aType);\r
475 \r
476     if (type==null)\r
477       return "invalidtype";\r
478 \r
479     if (!type.validate(anExpression)) {\r
480       return "invalidexpression";\r
481     }\r
482 \r
483     FilterRule filter = new FilterRule();\r
484 \r
485     filter.setId(generateId());\r
486     filter.setExpression(anExpression);\r
487     filter.setType(aType);\r
488     filter.setComments(aComments);\r
489     filter.setArticleAction(anArticleAction);\r
490     filter.setCommentAction(aCommentAction);\r
491 \r
492     synchronized (aFilters) {\r
493       aFilters.add(filter);\r
494     }\r
495 \r
496     return null;\r
497   }\r
498 \r
499   private String setFilter(List aFilters, String anIdentifier, String aType, String anExpression, String aComments, String aCommentAction, String anArticleAction) {\r
500     MirAntiAbuseFilterType type = (MirAntiAbuseFilterType) filterTypes.get(aType);\r
501 \r
502     if (type==null)\r
503       return "invalidtype";\r
504 \r
505     if (!type.validate(anExpression)) {\r
506       return "invalidexpression";\r
507     }\r
508 \r
509     synchronized (aFilters) {\r
510       FilterRule filter = findFilter(aFilters, anIdentifier);\r
511 \r
512       if (filter!=null) {\r
513         filter.setExpression(anExpression);\r
514         filter.setType(aType);\r
515         filter.setCommentAction(aCommentAction);\r
516         filter.setArticleAction(anArticleAction);\r
517         filter.setComments(aComments);\r
518       }\r
519 \r
520       return null;\r
521     }\r
522   }\r
523 \r
524   private FilterRule findFilter(List aFilters, String anIdentifier) {\r
525     synchronized (aFilters) {\r
526       Iterator i = aFilters.iterator();\r
527       while (i.hasNext()) {\r
528         FilterRule filter = (FilterRule) i.next();\r
529 \r
530         if (filter.getId().equals(anIdentifier)) {\r
531           return filter;\r
532         }\r
533       }\r
534     }\r
535 \r
536     return null;\r
537   }\r
538 \r
539   private void deleteFilter(List aFilters, String anIdentifier) {\r
540     synchronized (aFilters) {\r
541       FilterRule filter = findFilter(aFilters, anIdentifier);\r
542 \r
543       if (filter!=null) {\r
544         aFilters.remove(filter);\r
545       }\r
546     }\r
547   }\r
548 \r
549   private String generateId() {\r
550     synchronized(this) {\r
551       maxIdentifier = maxIdentifier+1;\r
552 \r
553       return Integer.toString(maxIdentifier);\r
554     }\r
555   }\r
556 \r
557   public class FilterRule {\r
558     private String identifier;\r
559     private String expression;\r
560     private String type;\r
561     private String comments;\r
562     private String articleAction;\r
563     private String commentAction;\r
564     private Date lastHit;\r
565 \r
566     public FilterRule() {\r
567       expression = "";\r
568       type = "";\r
569       identifier = "";\r
570       comments = "";\r
571       articleAction = articleBlockAction;\r
572       commentAction = commentBlockAction;\r
573       lastHit = null;\r
574     }\r
575 \r
576     public Date getLastHit() {\r
577       return lastHit;\r
578     }\r
579 \r
580     public void setLastHit(Date aDate) {\r
581       lastHit = aDate;\r
582     }\r
583 \r
584     public String getId() {\r
585       return identifier;\r
586     }\r
587 \r
588     public void setId(String anId) {\r
589       identifier = anId;\r
590     }\r
591 \r
592     public String getExpression() {\r
593       return expression;\r
594     }\r
595 \r
596     public void setExpression(String anExpression) {\r
597       expression = anExpression;\r
598     }\r
599 \r
600     public String getType() {\r
601       return type;\r
602     }\r
603 \r
604     public void setType(String aType) {\r
605       type = aType;\r
606     }\r
607 \r
608     public void setComments(String aComments) {\r
609       comments = aComments;\r
610     }\r
611 \r
612     public String getComments() {\r
613       return comments;\r
614     }\r
615 \r
616     public String getArticleAction() {\r
617       return articleAction;\r
618     }\r
619 \r
620     public void setArticleAction(String anArticleAction) {\r
621       articleAction = anArticleAction;\r
622     }\r
623 \r
624     public String getCommentAction() {\r
625       return commentAction;\r
626     }\r
627 \r
628     public void setCommentAction(String aCommentAction) {\r
629       commentAction = aCommentAction;\r
630     }\r
631 \r
632     public boolean test(Entity anEntity, Request aRequest) {\r
633       MirAntiAbuseFilterType filterType = (MirAntiAbuseFilterType) filterTypes.get(type);\r
634       try {\r
635         if (filterType != null)\r
636           return filterType.test(expression, anEntity, aRequest);\r
637       }\r
638       catch (Throwable t) {\r
639         logger.error("error while testing "+type+"-filter '"+expression+"'");\r
640       }\r
641 \r
642       return false;\r
643     };\r
644 \r
645     public Object clone() {\r
646       FilterRule result = new FilterRule();\r
647       result.setComments(getComments());\r
648       result.setExpression(getExpression());\r
649       result.setId(getId());\r
650       result.setType(getType());\r
651       result.setArticleAction(getArticleAction());\r
652       result.setCommentAction(getCommentAction());\r
653       result.setLastHit(getLastHit());\r
654 \r
655       return result;\r
656     }\r
657   }\r
658 \r
659   private void setFilterConfig(List aFilters, String aConfigKey, ExtendedProperties aConfiguration) {\r
660     synchronized(aFilters) {\r
661       Iterator i = aFilters.iterator();\r
662 \r
663       while (i.hasNext()) {\r
664         FilterRule filter = (FilterRule) i.next();\r
665 \r
666         String comments = StringRoutines.replaceStringCharacters(filter.getComments(), new char[] { '\\', ':'}, new String[] { "\\\\", "\\:"} );\r
667 \r
668         aConfiguration.addProperty(aConfigKey, filter.getType()+":"+filter.getExpression()+":"+filter.getArticleAction() + ":" + filter.getCommentAction() + ":" +\r
669            comments);\r
670       }\r
671     }\r
672   }\r
673 \r
674   private void getFilterConfig(List aFilters, String aConfigKey, ExtendedProperties aConfiguration) {\r
675     synchronized(aFilters) {\r
676       aFilters.clear();\r
677 \r
678       if (aConfiguration.getStringArray(aConfigKey)!=null) {\r
679 \r
680         Iterator i = Arrays.asList(aConfiguration.getStringArray(aConfigKey)).\r
681             iterator();\r
682 \r
683         while (i.hasNext()) {\r
684           String filter = (String) i.next();\r
685           List parts = StringRoutines.splitStringWithEscape(filter, ':', '\\');\r
686           if (parts.size() == 2) {\r
687             parts.add(articleBlockAction);\r
688             parts.add(commentBlockAction);\r
689             parts.add("");\r
690           }\r
691 \r
692           if (parts.size() == 5) {\r
693             addFilter( (String) parts.get(0), (String) parts.get(1), (String) parts.get(4), (String) parts.get(3), (String) parts.get(2));\r
694           }\r
695         }\r
696       }\r
697     }\r
698   }\r
699 \r
700   private static class LogEntry {\r
701     private String ipNumber;\r
702     private String browserString;\r
703     private String id;\r
704     private Date timeStamp;\r
705     private boolean isArticle;\r
706 \r
707     public LogEntry(Date aTimeStamp, String anIpNumber, String aBrowserString, String anId, boolean anIsArticle) {\r
708       ipNumber = anIpNumber;\r
709       browserString = aBrowserString;\r
710       id = anId;\r
711       isArticle = anIsArticle;\r
712       timeStamp=aTimeStamp;\r
713     }\r
714 \r
715     public String getIpNumber() {\r
716       return ipNumber;\r
717     }\r
718 \r
719     public String getBrowserString() {\r
720       return browserString;\r
721     }\r
722 \r
723     public String getId() {\r
724       return id;\r
725     }\r
726 \r
727     public Date getTimeStamp() {\r
728       return timeStamp;\r
729     }\r
730 \r
731     public boolean getIsArticle() {\r
732       return isArticle;\r
733     }\r
734   }\r
735 \r
736   private void truncateLog() {\r
737     synchronized(log) {\r
738       if (!logEnabled)\r
739         log.clear();\r
740       else {\r
741         while (log.size()>0 && log.size()>logSize) {\r
742           log.remove(0);\r
743         }\r
744       }\r
745     }\r
746   };\r
747 \r
748   private void appendLog(LogEntry anEntry) {\r
749     synchronized (log) {\r
750       if (logEnabled) {\r
751         log.add(anEntry);\r
752         truncateLog();\r
753       }\r
754     }\r
755   }\r
756 \r
757   public void logAdminUsage(EntityUsers aUser, String aDescription) {\r
758     try {\r
759       String user = "unknown (" + aUser.toString() +")";\r
760       if (user!=null)\r
761         user = aUser.getValue("login");\r
762       adminUsageLogger.info(user + ": " + aDescription);\r
763     }\r
764     catch (Throwable t) {\r
765       logger.error("Error while logging admin usage ("+aUser.toString()+", "+aDescription+"): " +t.toString());\r
766     }\r
767   }\r
768 }