56c72168b84808c17400f305d4ae8f7f1f1aa289
[mir.git] / source / mircoders / abuse / FilterEngine.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30
31 package mircoders.abuse;
32
33 import java.text.SimpleDateFormat;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.Date;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.TimeZone;
42
43 import mir.config.MirPropertiesConfiguration;
44 import mir.entity.Entity;
45 import mir.entity.adapter.EntityAdapter;
46 import mir.entity.adapter.EntityAdapterModel;
47 import mir.entity.adapter.EntityIteratorAdapter;
48 import mir.log.LoggerWrapper;
49 import mir.session.Request;
50 import mir.storage.StorageObjectExc;
51 import mircoders.global.MirGlobal;
52 import mircoders.storage.DatabaseFilter;
53 import mircoders.storage.DatabaseFilterGroup;
54
55 public class FilterEngine {
56   private Map filterTypes;
57   private List filterTypeIds;
58
59   private List filterGroups;
60   private Map idToFilterGroup;
61   private LoggerWrapper logger;
62   private EntityAdapterModel model;
63   private SimpleDateFormat dateFormat;
64   private MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
65
66   public FilterEngine(EntityAdapterModel aModel) {
67     logger = new LoggerWrapper("Global.Abuse.FilterEngine");
68     filterGroups = new ArrayList();
69     idToFilterGroup = new HashMap();
70
71     filterTypes = new HashMap();
72     filterTypeIds = new ArrayList();
73     try {
74       Iterator i = MirGlobal.localizer().openPostings().getAntiAbuseFilterTypes().iterator();
75       while (i.hasNext()) {
76         FilterType filterType = (FilterType) i.next();
77
78         filterTypes.put(filterType.getName(), filterType);
79         filterTypeIds.add(filterType.getName());
80       }
81     }
82     catch (Throwable t) {
83       throw new RuntimeException(t.getMessage());
84     }
85
86     model = aModel;
87
88     dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
89     dateFormat.setTimeZone(TimeZone.getTimeZone(configuration.getString("Mir.DefaultTimezone")));
90     reload();
91   }
92
93   public Filter testPosting(Entity anEntity, Request aRequest) {
94     Iterator i = filterGroups.iterator();
95     while (i.hasNext()) {
96       FilterGroup group = (FilterGroup) i.next();
97       Iterator j = group.getFilters().iterator();
98       while (j.hasNext()) {
99         Filter filter = (Filter) j.next();
100         try {
101           if (filter.test(anEntity, aRequest)) {
102             return filter;
103           }
104         }
105         catch (Throwable t) {
106           logger.warn("Exception thrown while testing filter " + filter.getType() + " ( " + filter.getExpression() + ") " + t.toString());
107         }
108       }
109     }
110
111     return null;
112   }
113
114   public List getFilterTypes() {
115     try {
116       List result = new ArrayList();
117
118       Iterator i = filterTypeIds.iterator();
119       while (i.hasNext()) {
120         String id = (String) i.next();
121
122         Map action = new HashMap();
123         action.put("resource", id);
124         action.put("identifier", id);
125
126         result.add(action);
127       }
128
129       return result;
130     }
131     catch (Throwable t) {
132       throw new RuntimeException("can't get article actions");
133     }
134   }
135
136   public class FilterGroup {
137     private List filters;
138     private Entity entity;
139     private Map idToFilter;
140
141     public FilterGroup(Entity anEntity) {
142       this (anEntity, Collections.EMPTY_LIST);
143     }
144
145     public FilterGroup(Entity anEntity, List aFilters) {
146       entity = anEntity;
147       filters = new ArrayList();
148       idToFilter = new HashMap();
149       Iterator i = aFilters.iterator();
150
151       while (i.hasNext()) {
152         Entity entity = (Entity) i.next();
153         try {
154           Filter filter = new Filter(entity);
155           introduceFilter(filter);
156         }
157         catch (AbuseExc e) {
158         }
159       }
160     }
161
162     public Entity getEntity() {
163       return entity;
164     }
165
166     public EntityAdapter getEntityAdapter() {
167       return model.makeEntityAdapter("filterGroup",  entity);
168     }
169
170     public List getFilterEntityAdapterList() {
171       List result = new ArrayList();
172
173       Iterator i = filters.iterator();
174       while (i.hasNext()) {
175         Filter filter = (Filter) i.next();
176         result.add(filter.getEntityAdapter());
177       }
178
179       return result;
180     }
181
182     public List getFilters() {
183       return filters;
184     }
185
186     public Filter getFilterForId(String anId) {
187       Filter result = (Filter) idToFilter.get(anId);
188       if (result==null) {
189         throw new NullPointerException("No such filter");
190       }
191
192       return result;
193     }
194
195     private void introduceFilter(Filter aFilter) {
196       filters.add(aFilter);
197       idToFilter.put(aFilter.getEntity().getId(), aFilter);
198     }
199
200     private void removeFilter(Filter aFilter) {
201       filters.remove(aFilter);
202       idToFilter.remove(aFilter.getEntity().getId());
203     }
204
205     private void deleteFilter(String anId) {
206       Filter filter = getFilterForId(anId);
207       removeFilter(filter);
208       DatabaseFilter.getInstance().delete(anId);
209     }
210
211     public void populateFilterEntity(Entity anEntity, String aType, String anExpression,
212                              String aComments, String aTag, String anArticleAction,
213                              String aCommentAction) {
214
215       anEntity.setFieldValue("type", aType);
216       anEntity.setFieldValue("expression", anExpression);
217       anEntity.setFieldValue("comment", aComments);
218       anEntity.setFieldValue("tag", aTag);
219       anEntity.setFieldValue("articleaction", anArticleAction);
220       anEntity.setFieldValue("commentaction", aCommentAction);
221     }
222
223     public String updateFilter(String anId, String aType, String anExpression,
224                              String aComments, String aTag, String anArticleAction,
225                              String aCommentAction) {
226
227       try {
228         getFilterTypeForId(aType).constructFilterInstance(anExpression);
229       }
230       catch (AbuseExc e) {
231         return e.getMessage();
232       }
233
234       Entity entity = getFilterForId(anId).getEntity();
235       populateFilterEntity(entity, aType, anExpression, aComments, aTag,
236           anArticleAction, aCommentAction);
237       entity.update();
238
239       return "";
240     }
241
242     public String createFilter(String aType, String anExpression,
243                              String aComments, String aTag, String anArticleAction,
244                              String aCommentAction) throws StorageObjectExc {
245       FilterInstance instance;
246
247       try {
248         instance = getFilterTypeForId(aType).constructFilterInstance(anExpression);
249       }
250       catch (AbuseExc e) {
251         return e.getMessage();
252       }
253
254       Entity entity = DatabaseFilter.getInstance().createNewEntity();
255       populateFilterEntity(entity, aType, anExpression, aComments, aTag,
256           anArticleAction, aCommentAction);
257       entity.setFieldValue("priority", "1");
258       entity.setFieldValue("filter_group_id", getEntity().getId());
259       entity.insert();
260
261       Filter filter = new Filter(entity, instance);
262       introduceFilter(filter);
263
264       return "";
265     }
266
267     public String getName() {
268       return entity.getFieldValue("name");
269     }
270   }
271
272   public class Filter {
273     private Entity entity;
274     private FilterInstance instance;
275
276     public Filter(Entity anEntity) throws AbuseExc {
277       this(anEntity, getFilterTypeForId(anEntity.getFieldValue("type")).constructFilterInstance(anEntity.getFieldValue("expression")));
278     }
279
280     public Filter(Entity anEntity, FilterInstance anInstance) {
281       entity = anEntity;
282       instance = anInstance;
283     }
284
285     public Entity getEntity() {
286       return entity;
287     }
288
289     public EntityAdapter getEntityAdapter() {
290       return model.makeEntityAdapter("filter", entity);
291     }
292
293     public void update(String aType, String anExpression, String aComments, String aTag,
294                        String anArticleAction, String aCommentAction) throws AbuseExc {
295
296       instance = getFilterTypeForId(aType).constructFilterInstance(anExpression);
297
298       entity.setFieldValue("type", aType);
299       entity.setFieldValue("expression", anExpression);
300       entity.setFieldValue("tag", aType);
301       entity.setFieldValue("comment", aComments);
302       entity.setFieldValue("articleaction", anArticleAction);
303       entity.setFieldValue("commentaction", aCommentAction);
304       entity.setFieldValue("last_hit", null);
305       entity.update();
306    }
307
308     public void updateLastHit(Date aDate) {
309       entity.setFieldValue("last_hit", dateFormat.format(aDate));
310       entity.update();
311     }
312
313     public String getType() {
314       return entity.getFieldValue("type");
315     }
316
317     public String getExpression() {
318       return entity.getFieldValue("expression");
319     }
320
321     public String getTag() {
322       return entity.getFieldValue("tag");
323     }
324
325     public String getComment() {
326       return entity.getFieldValue("comment");
327     }
328
329     public String getArticleAction() {
330       return entity.getFieldValue("articleaction");
331     }
332
333     public String getCommentAction() {
334       return entity.getFieldValue("commentaction");
335     }
336
337     public FilterInstance getInstance() {
338       return instance;
339     }
340
341     public boolean test(Entity anEntity, Request aRequest) {
342       return instance.test(anEntity, aRequest);
343     }
344   }
345
346   public synchronized void reload() {
347     filterGroups.clear();
348     idToFilterGroup.clear();
349
350     try {
351       Iterator i = new EntityIteratorAdapter("", "priority asc", 100, model, "filterGroup");
352       while (i.hasNext()) {
353         EntityAdapter entityAdapter = (EntityAdapter) i.next();
354         List filters = new ArrayList();
355         Iterator j = (Iterator) entityAdapter.get("to_filters");
356         while (j.hasNext()) {
357           filters.add(((EntityAdapter) j.next()).getEntity());
358         }
359
360         FilterGroup filterGroup = new FilterGroup(entityAdapter.getEntity(), filters);
361         introduceFilterGroup(filterGroup);
362       }
363     }
364     catch (Throwable e) {
365       logger.error("Can't load filters: " + e.getMessage());
366     }
367   }
368
369   public synchronized List getFilterGroups() {
370     List result = new ArrayList();
371     Iterator i = filterGroups.iterator();
372     while (i.hasNext()) {
373       result.add(((FilterGroup) i.next()).getEntityAdapter());
374     }
375
376     return result;
377   }
378
379   public synchronized void updateFilterGroup(String anId, String aName) {
380     FilterGroup filterGroup = getFilterGroupForId(anId);
381     filterGroup.getEntity().setFieldValue("name", aName);
382     filterGroup.getEntity().update();
383   }
384
385   public synchronized void addFilterGroup(String aName) throws StorageObjectExc {
386     Entity entity = DatabaseFilterGroup.getInstance().createNewEntity();
387     entity.setFieldValue("name", aName);
388     entity.setFieldValue("priority", "1");
389     entity.insert();
390
391     FilterGroup filterGroup = new FilterGroup(entity);
392     introduceFilterGroup(filterGroup);
393   }
394
395   public synchronized void deleteFilterGroup(String anId) {
396
397     FilterGroup filterGroup = getFilterGroupForId(anId);
398     removeFilterGroup(filterGroup);
399     DatabaseFilter.getInstance().deleteByWhereClause("filter_group_id = " + anId);
400     DatabaseFilterGroup.getInstance().delete(anId);
401   }
402
403   public synchronized void deleteFilter(String aGroupId, String anId) {
404     getFilterGroupForId(aGroupId).deleteFilter(anId);
405   }
406
407
408   public synchronized String updateFilter(String aGroupId, String anId,
409                                         String aType, String anExpression,
410                                         String aComments,
411                                         String aTag,
412                                         String anArticleAction,
413                                         String aCommentAction) {
414     return getFilterGroupForId(aGroupId).updateFilter(anId, aType,
415         anExpression, aComments, aTag, anArticleAction, aCommentAction);
416   }
417
418   public synchronized String addFilter(String aGroupId,
419                                        String aType, String anExpression,
420                                        String aComments,
421                                        String aTag,
422                                        String anArticleAction,
423                                        String aCommentAction) throws StorageObjectExc {
424     return getFilterGroupForId(aGroupId).createFilter(aType, anExpression,
425         aComments, aTag, anArticleAction, aCommentAction);
426   }
427
428
429   public FilterGroup getFilterGroupForId(String anId) {
430     FilterGroup result = (FilterGroup) idToFilterGroup.get(anId);
431     if (result == null) {
432       throw new NullPointerException("No such filter group");
433     }
434
435     return result;
436   }
437
438   public Filter getFilterForId(String aGroupId, String anId) {
439     return getFilterGroupForId(aGroupId).getFilterForId(anId);
440   }
441
442
443   public List getFilters(String aFilterGroupId) {
444     return getFilterGroupForId(aFilterGroupId).getFilterEntityAdapterList();
445   }
446
447   private void introduceFilterGroup(FilterGroup aFilterGroup) {
448     filterGroups.add(aFilterGroup);
449     idToFilterGroup.put(aFilterGroup.getEntity().getId(), aFilterGroup);
450   }
451
452   private void removeFilterGroup(FilterGroup aFilterGroup) {
453     filterGroups.remove(aFilterGroup);
454     idToFilterGroup.remove(aFilterGroup.getEntity().getId());
455   }
456
457   private FilterType getFilterTypeForId(String anId) {
458     return (FilterType) filterTypes.get(anId);
459   }
460 }