* anti-abuse upgrade: filters now stored in the database (experimental)
[mir.git] / source / mircoders / abuse / FilterEngine.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.abuse;\r
32 \r
33 import mir.entity.Entity;\r
34 import mir.entity.adapter.EntityAdapter;\r
35 import mir.entity.adapter.EntityAdapterModel;\r
36 import mir.entity.adapter.EntityIteratorAdapter;\r
37 import mir.log.LoggerWrapper;\r
38 import mir.storage.StorageObjectExc;\r
39 import mir.session.Request;\r
40 import mir.config.MirPropertiesConfiguration;\r
41 import mircoders.storage.DatabaseFilter;\r
42 import mircoders.storage.DatabaseFilterGroup;\r
43 import mircoders.global.MirGlobal;\r
44 \r
45 import java.util.*;\r
46 import java.text.SimpleDateFormat;\r
47 \r
48 public class FilterEngine {\r
49   private Map filterTypes;\r
50   private List filterTypeIds;\r
51 \r
52   private List filterGroups;\r
53   private Map idToFilterGroup;\r
54   private LoggerWrapper logger;\r
55   private EntityAdapterModel model;\r
56   private SimpleDateFormat dateFormat;\r
57   private MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();\r
58 \r
59   public FilterEngine(EntityAdapterModel aModel) {\r
60     logger = new LoggerWrapper("Global.Abuse.FilterEngine");\r
61     filterGroups = new ArrayList();\r
62     idToFilterGroup = new HashMap();\r
63 \r
64     filterTypes = new HashMap();\r
65     filterTypeIds = new ArrayList();\r
66     try {\r
67       Iterator i = MirGlobal.localizer().openPostings().getAntiAbuseFilterTypes().iterator();\r
68       while (i.hasNext()) {\r
69         FilterType filterType = (FilterType) i.next();\r
70 \r
71         filterTypes.put(filterType.getName(), filterType);\r
72         filterTypeIds.add(filterType.getName());\r
73       }\r
74     }\r
75     catch (Throwable t) {\r
76       throw new RuntimeException(t.getMessage());\r
77     }\r
78 \r
79     model = aModel;\r
80 \r
81     dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
82     dateFormat.setTimeZone(TimeZone.getTimeZone(configuration.getString("Mir.DefaultTimezone")));\r
83     reload();\r
84   }\r
85 \r
86   public Filter testPosting(Entity anEntity, Request aRequest) {\r
87     Iterator i = filterGroups.iterator();\r
88     while (i.hasNext()) {\r
89       FilterGroup group = (FilterGroup) i.next();\r
90       Iterator j = group.getFilters().iterator();\r
91       while (j.hasNext()) {\r
92         Filter filter = (Filter) j.next();\r
93         try {\r
94           if (filter.test(anEntity, aRequest)) {\r
95             return filter;\r
96           }\r
97         }\r
98         catch (Throwable t) {\r
99           logger.warn("Exception thrown while testing filter " + filter.getType() + " ( " + filter.getExpression() + ") " + t.toString());\r
100         }\r
101       }\r
102     }\r
103 \r
104     return null;\r
105   }\r
106 \r
107   public List getFilterTypes() {\r
108     try {\r
109       List result = new ArrayList();\r
110 \r
111       Iterator i = filterTypeIds.iterator();\r
112       while (i.hasNext()) {\r
113         String id = (String) i.next();\r
114 \r
115         Map action = new HashMap();\r
116         action.put("resource", id);\r
117         action.put("identifier", id);\r
118 \r
119         result.add(action);\r
120       }\r
121 \r
122       return result;\r
123     }\r
124     catch (Throwable t) {\r
125       throw new RuntimeException("can't get article actions");\r
126     }\r
127   }\r
128 \r
129   public class FilterGroup {\r
130     private List filters;\r
131     private Entity entity;\r
132     private Map idToFilter;\r
133 \r
134     public FilterGroup(Entity anEntity) {\r
135       this (anEntity, Collections.EMPTY_LIST);\r
136     }\r
137 \r
138     public FilterGroup(Entity anEntity, List aFilters) {\r
139       entity = anEntity;\r
140       filters = new ArrayList();\r
141       idToFilter = new HashMap();\r
142       Iterator i = aFilters.iterator();\r
143 \r
144       while (i.hasNext()) {\r
145         Entity entity = (Entity) i.next();\r
146         try {\r
147           Filter filter = new Filter(entity);\r
148           introduceFilter(filter);\r
149         }\r
150         catch (AbuseExc e) {\r
151         }\r
152       }\r
153     }\r
154 \r
155     public Entity getEntity() {\r
156       return entity;\r
157     }\r
158 \r
159     public EntityAdapter getEntityAdapter() {\r
160       return model.makeEntityAdapter("filterGroup",  entity);\r
161     }\r
162 \r
163     public List getFilterEntityAdapterList() {\r
164       List result = new ArrayList();\r
165 \r
166       Iterator i = filters.iterator();\r
167       while (i.hasNext()) {\r
168         Filter filter = (Filter) i.next();\r
169         result.add(filter.getEntityAdapter());\r
170       }\r
171 \r
172       return result;\r
173     }\r
174 \r
175     public List getFilters() {\r
176       return filters;\r
177     }\r
178 \r
179     public Filter getFilterForId(String anId) {\r
180       Filter result = (Filter) idToFilter.get(anId);\r
181       if (result==null) {\r
182         throw new NullPointerException("No such filter");\r
183       }\r
184 \r
185       return result;\r
186     }\r
187 \r
188     private void introduceFilter(Filter aFilter) {\r
189       filters.add(aFilter);\r
190       idToFilter.put(aFilter.getEntity().getId(), aFilter);\r
191     }\r
192 \r
193     private void removeFilter(Filter aFilter) {\r
194       filters.remove(aFilter);\r
195       idToFilter.remove(aFilter.getEntity().getId());\r
196     }\r
197 \r
198     private void deleteFilter(String anId) {\r
199       Filter filter = getFilterForId(anId);\r
200       removeFilter(filter);\r
201       DatabaseFilter.getInstance().delete(anId);\r
202     }\r
203 \r
204     public void populateFilterEntity(Entity anEntity, String aType, String anExpression,\r
205                              String aComments, String aTag, String anArticleAction,\r
206                              String aCommentAction) {\r
207 \r
208       anEntity.setFieldValue("type", aType);\r
209       anEntity.setFieldValue("expression", anExpression);\r
210       anEntity.setFieldValue("comment", aComments);\r
211       anEntity.setFieldValue("tag", aTag);\r
212       anEntity.setFieldValue("articleaction", anArticleAction);\r
213       anEntity.setFieldValue("commentaction", aCommentAction);\r
214     }\r
215 \r
216     public String updateFilter(String anId, String aType, String anExpression,\r
217                              String aComments, String aTag, String anArticleAction,\r
218                              String aCommentAction) {\r
219 \r
220       try {\r
221         getFilterTypeForId(aType).constructFilterInstance(anExpression);\r
222       }\r
223       catch (AbuseExc e) {\r
224         return e.getMessage();\r
225       }\r
226 \r
227       Entity entity = getFilterForId(anId).getEntity();\r
228       populateFilterEntity(entity, aType, anExpression, aComments, aTag,\r
229           anArticleAction, aCommentAction);\r
230       entity.update();\r
231 \r
232       return "";\r
233     }\r
234 \r
235     public String createFilter(String aType, String anExpression,\r
236                              String aComments, String aTag, String anArticleAction,\r
237                              String aCommentAction) throws StorageObjectExc {\r
238       FilterInstance instance;\r
239 \r
240       try {\r
241         instance = getFilterTypeForId(aType).constructFilterInstance(anExpression);\r
242       }\r
243       catch (AbuseExc e) {\r
244         return e.getMessage();\r
245       }\r
246 \r
247       Entity entity = DatabaseFilter.getInstance().createNewEntity();\r
248       populateFilterEntity(entity, aType, anExpression, aComments, aTag,\r
249           anArticleAction, aCommentAction);\r
250       entity.setFieldValue("priority", "1");\r
251       entity.setFieldValue("filter_group_id", getEntity().getId());\r
252       entity.insert();\r
253 \r
254       Filter filter = new Filter(entity, instance);\r
255       introduceFilter(filter);\r
256 \r
257       return "";\r
258     }\r
259 \r
260     public String getName() {\r
261       return entity.getFieldValue("name");\r
262     }\r
263   }\r
264 \r
265   public class Filter {\r
266     private Entity entity;\r
267     private FilterInstance instance;\r
268 \r
269     public Filter(Entity anEntity) throws AbuseExc {\r
270       this(anEntity, getFilterTypeForId(anEntity.getFieldValue("type")).constructFilterInstance(anEntity.getFieldValue("expression")));\r
271     }\r
272 \r
273     public Filter(Entity anEntity, FilterInstance anInstance) {\r
274       entity = anEntity;\r
275       instance = anInstance;\r
276     }\r
277 \r
278     public Entity getEntity() {\r
279       return entity;\r
280     }\r
281 \r
282     public EntityAdapter getEntityAdapter() {\r
283       return model.makeEntityAdapter("filter", entity);\r
284     }\r
285 \r
286     public void update(String aType, String anExpression, String aComments, String aTag,\r
287                        String anArticleAction, String aCommentAction) throws AbuseExc {\r
288 \r
289       instance = getFilterTypeForId(aType).constructFilterInstance(anExpression);\r
290 \r
291       entity.setFieldValue("type", aType);\r
292       entity.setFieldValue("expression", anExpression);\r
293       entity.setFieldValue("tag", aType);\r
294       entity.setFieldValue("comment", aComments);\r
295       entity.setFieldValue("articleaction", anArticleAction);\r
296       entity.setFieldValue("commentaction", aCommentAction);\r
297       entity.setFieldValue("last_hit", null);\r
298       entity.update();\r
299    }\r
300 \r
301     public void updateLastHit(Date aDate) {\r
302       entity.setFieldValue("last_hit", dateFormat.format(aDate));\r
303       entity.update();\r
304     }\r
305 \r
306     public String getType() {\r
307       return entity.getFieldValue("type");\r
308     }\r
309 \r
310     public String getExpression() {\r
311       return entity.getFieldValue("expression");\r
312     }\r
313 \r
314     public String getTag() {\r
315       return entity.getFieldValue("tag");\r
316     }\r
317 \r
318     public String getComment() {\r
319       return entity.getFieldValue("comment");\r
320     }\r
321 \r
322     public String getArticleAction() {\r
323       return entity.getFieldValue("articleaction");\r
324     }\r
325 \r
326     public String getCommentAction() {\r
327       return entity.getFieldValue("commentaction");\r
328     }\r
329 \r
330     public FilterInstance getInstance() {\r
331       return instance;\r
332     }\r
333 \r
334     public boolean test(Entity anEntity, Request aRequest) {\r
335       return instance.test(anEntity, aRequest);\r
336     }\r
337   }\r
338 \r
339   public synchronized void reload() {\r
340     filterGroups.clear();\r
341     idToFilterGroup.clear();\r
342 \r
343     Iterator i = new EntityIteratorAdapter("", "priority asc", 100, model, "filterGroup");\r
344 \r
345     while (i.hasNext()) {\r
346       EntityAdapter entityAdapter = (EntityAdapter) i.next();\r
347       List filters = new ArrayList();\r
348       Iterator j = (Iterator) entityAdapter.get("to_filters");\r
349       while (j.hasNext()) {\r
350         filters.add(((EntityAdapter) j.next()).getEntity());\r
351       }\r
352 \r
353       FilterGroup filterGroup = new FilterGroup(entityAdapter.getEntity(), filters);\r
354       introduceFilterGroup(filterGroup);\r
355     }\r
356   }\r
357 \r
358   public synchronized List getFilterGroups() {\r
359     List result = new ArrayList();\r
360     Iterator i = filterGroups.iterator();\r
361     while (i.hasNext()) {\r
362       result.add(((FilterGroup) i.next()).getEntityAdapter());\r
363     }\r
364 \r
365     return result;\r
366   }\r
367 \r
368   public synchronized void updateFilterGroup(String anId, String aName) {\r
369     FilterGroup filterGroup = getFilterGroupForId(anId);\r
370     filterGroup.getEntity().setFieldValue("name", aName);\r
371     filterGroup.getEntity().update();\r
372   }\r
373 \r
374   public synchronized void addFilterGroup(String aName) throws StorageObjectExc {\r
375     Entity entity = DatabaseFilterGroup.getInstance().createNewEntity();\r
376     entity.setFieldValue("name", aName);\r
377     entity.setFieldValue("priority", "1");\r
378     entity.insert();\r
379 \r
380     FilterGroup filterGroup = new FilterGroup(entity);\r
381     introduceFilterGroup(filterGroup);\r
382   }\r
383 \r
384   public synchronized void deleteFilterGroup(String anId) {\r
385 \r
386     FilterGroup filterGroup = getFilterGroupForId(anId);\r
387     removeFilterGroup(filterGroup);\r
388     DatabaseFilter.getInstance().deleteByWhereClause("filter_group_id = " + anId);\r
389     DatabaseFilterGroup.getInstance().delete(anId);\r
390   }\r
391 \r
392   public synchronized void deleteFilter(String aGroupId, String anId) {\r
393     getFilterGroupForId(aGroupId).deleteFilter(anId);\r
394   }\r
395 \r
396 \r
397   public synchronized String updateFilter(String aGroupId, String anId,\r
398                                         String aType, String anExpression,\r
399                                         String aComments,\r
400                                         String aTag,\r
401                                         String anArticleAction,\r
402                                         String aCommentAction) {\r
403     return getFilterGroupForId(aGroupId).updateFilter(anId, aType,\r
404         anExpression, aComments, aTag, anArticleAction, aCommentAction);\r
405   }\r
406 \r
407   public synchronized String addFilter(String aGroupId,\r
408                                        String aType, String anExpression,\r
409                                        String aComments,\r
410                                        String aTag,\r
411                                        String anArticleAction,\r
412                                        String aCommentAction) throws StorageObjectExc {\r
413     return getFilterGroupForId(aGroupId).createFilter(aType, anExpression,\r
414         aComments, aTag, anArticleAction, aCommentAction);\r
415   }\r
416 \r
417 \r
418   public FilterGroup getFilterGroupForId(String anId) {\r
419     FilterGroup result = (FilterGroup) idToFilterGroup.get(anId);\r
420     if (result == null) {\r
421       throw new NullPointerException("No such filter group");\r
422     }\r
423 \r
424     return result;\r
425   }\r
426 \r
427   public Filter getFilterForId(String aGroupId, String anId) {\r
428     return getFilterGroupForId(aGroupId).getFilterForId(anId);\r
429   }\r
430 \r
431 \r
432   public List getFilters(String aFilterGroupId) {\r
433     return getFilterGroupForId(aFilterGroupId).getFilterEntityAdapterList();\r
434   }\r
435 \r
436   private void introduceFilterGroup(FilterGroup aFilterGroup) {\r
437     filterGroups.add(aFilterGroup);\r
438     idToFilterGroup.put(aFilterGroup.getEntity().getId(), aFilterGroup);\r
439   }\r
440 \r
441   private void removeFilterGroup(FilterGroup aFilterGroup) {\r
442     filterGroups.remove(aFilterGroup);\r
443     idToFilterGroup.remove(aFilterGroup.getEntity().getId());\r
444   }\r
445 \r
446   private FilterType getFilterTypeForId(String anId) {\r
447     return (FilterType) filterTypes.get(anId);\r
448   }\r
449 }\r