2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
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.
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.
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
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.
31 package mircoders.abuse;
33 import mir.entity.Entity;
34 import mir.entity.adapter.EntityAdapter;
35 import mir.entity.adapter.EntityAdapterModel;
36 import mir.entity.adapter.EntityIteratorAdapter;
37 import mir.log.LoggerWrapper;
38 import mir.session.Request;
39 import mir.storage.DatabaseExc;
40 import mir.storage.DatabaseHelper;
41 import mircoders.global.MirGlobal;
42 import mircoders.storage.DatabaseFilter;
43 import mircoders.storage.DatabaseFilterGroup;
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.Date;
48 import java.util.HashMap;
49 import java.util.Iterator;
50 import java.util.List;
52 /** The FilterEngine manages a list of all filters and filter groups.
53 * Use the testPosting() method to apply all filters on an
54 * Entity (for ex. an article or a comment)
56 public class FilterEngine {
57 private final Map filterTypes = new HashMap();
58 private final List filterTypeIds = new ArrayList();
60 private final List filterGroups = new ArrayList();
61 private final Map idToFilterGroup = new HashMap();
62 private final LoggerWrapper logger = new LoggerWrapper("Global.Abuse.FilterEngine");
63 private EntityAdapterModel model;
65 public FilterEngine(EntityAdapterModel aModel) {
67 Iterator i = MirGlobal.localizer().openPostings().getAntiAbuseFilterTypes().iterator();
69 FilterType filterType = (FilterType) i.next();
71 filterTypes.put(filterType.getName(), filterType);
72 filterTypeIds.add(filterType.getName());
76 throw new RuntimeException(t.getMessage());
84 /** applies all filters from all filter groups to an Entity.
85 * The entity may be, for example, an article, or a comment.
86 * It returns a filter that matches if it finds one, null otherwise
88 public synchronized Filter testPosting(Entity anEntity, Request aRequest) {
89 Iterator i = filterGroups.iterator();
91 FilterGroup group = (FilterGroup) i.next();
93 Iterator j = group.getFilters().iterator();
95 Filter filter = (Filter) j.next();
97 if (filter.test(anEntity, aRequest)) {
101 catch (Throwable t) {
102 logger.warn("Exception thrown while testing filter " + filter.getType() + " ( " + filter.getExpression() + ") " + t.toString());
110 public List getFilterTypes() {
112 List result = new ArrayList();
114 Iterator i = filterTypeIds.iterator();
115 while (i.hasNext()) {
116 String id = (String) i.next();
118 Map action = new HashMap();
119 action.put("resource", id);
120 action.put("identifier", id);
127 catch (Throwable t) {
128 throw new RuntimeException("can't get article actions: " + t.getMessage());
131 /** This class reflects a row of the filter_group
132 * database table. Filters groups allow you to organize
133 * your filters. For example: group1=spammer ,
136 public class FilterGroup {
137 private List filters;
138 private Entity entity;
139 private Map idToFilter;
141 public FilterGroup(Entity anEntity) {
142 this (anEntity, Collections.EMPTY_LIST);
145 public FilterGroup(Entity anEntity, List aFilters) {
147 filters = new ArrayList();
148 idToFilter = new HashMap();
149 Iterator i = aFilters.iterator();
151 while (i.hasNext()) {
152 Entity entity = (Entity) i.next();
154 Filter filter = new Filter(entity);
155 introduceFilter(filter);
157 catch (Throwable e) {
158 logger.debug("Misbehaving filer: " + entity.toString() + ": " + e);
163 public Entity getEntity() {
167 public EntityAdapter getEntityAdapter() {
168 return model.makeEntityAdapter("filterGroup", entity);
171 public List getFilterEntityAdapterList() {
172 List result = new ArrayList();
174 Iterator i = filters.iterator();
175 while (i.hasNext()) {
176 Filter filter = (Filter) i.next();
177 result.add(filter.getEntityAdapter());
183 public List getFilters() {
187 public Filter getFilterForId(String anId) {
188 Filter result = (Filter) idToFilter.get(anId);
190 throw new NullPointerException("No such filter");
196 private void introduceFilter(Filter aFilter) {
197 filters.add(aFilter);
198 idToFilter.put(aFilter.getEntity().getId(), aFilter);
201 private void removeFilter(Filter aFilter) {
202 filters.remove(aFilter);
203 idToFilter.remove(aFilter.getEntity().getId());
206 private void deleteFilter(String anId) {
207 Filter filter = getFilterForId(anId);
208 removeFilter(filter);
209 DatabaseFilter.getInstance().delete(anId);
212 public void populateFilterEntity(Entity anEntity, String aType, String anExpression,
213 String aComments, String aTag, String anArticleAction,
214 String aCommentAction) {
216 anEntity.setFieldValue("type", aType);
217 anEntity.setFieldValue("expression", anExpression);
218 anEntity.setFieldValue("comment", aComments);
219 anEntity.setFieldValue("tag", aTag);
220 anEntity.setFieldValue("articleaction", anArticleAction);
221 anEntity.setFieldValue("commentaction", aCommentAction);
224 public String updateFilter(String anId, String aType, String anExpression,
225 String aComments, String aTag, String anArticleAction,
226 String aCommentAction) {
229 getFilterTypeForId(aType).constructFilterInstance(anExpression);
232 return e.getMessage();
235 Entity entity = getFilterForId(anId).getEntity();
236 populateFilterEntity(entity, aType, anExpression, aComments, aTag,
237 anArticleAction, aCommentAction);
243 public String createFilter(String aType, String anExpression,
244 String aComments, String aTag, String anArticleAction,
245 String aCommentAction) throws DatabaseExc {
246 FilterInstance instance;
249 instance = getFilterTypeForId(aType).constructFilterInstance(anExpression);
252 return e.getMessage();
255 Entity entity = DatabaseFilter.getInstance().createNewEntity();
256 populateFilterEntity(entity, aType, anExpression, aComments, aTag,
257 anArticleAction, aCommentAction);
260 String priority = "1";
262 if (filters.size() > 0) {
264 String lastPriorityString = ((Filter) filters.get(filters.size()-1)).getEntity().getFieldValue("priority");
265 int lastPriority = Integer.parseInt(lastPriorityString);
266 priority = Integer.toString(lastPriority + 1);
268 catch (Throwable e) {
272 entity.setFieldValue("priority", priority);
273 entity.setFieldValue("filter_group_id", getEntity().getId());
276 Filter filter = new Filter(entity, instance);
277 introduceFilter(filter);
282 public String moveFilterUp(String anId) {
283 Filter filter = getFilterForId(anId);
284 String priority = filter.getEntity().getFieldValue("priority");
285 int index = filters.indexOf(filter);
287 Filter filterBefore= (Filter) filters.remove(index-1);
288 filters.add(index, filterBefore);
289 filter.getEntity().setFieldValue("priority", filterBefore.getEntity().getFieldValue("priority"));
290 filterBefore.getEntity().setFieldValue("priority", priority);
291 filter.getEntity().update();
292 filterBefore.getEntity().update();
298 public String moveFilterToTop(String anId) {
299 Filter filter = getFilterForId(anId);
300 String priority = filter.getEntity().getFieldValue("priority");
301 int index = filters.indexOf(filter);
303 filters.remove(index);
304 Filter filterBefore= (Filter) filters.get(0);
305 filters.add(0, filter);
306 filter.getEntity().setFieldValue("priority", filterBefore.getEntity().getFieldValue("priority"));
307 filterBefore.getEntity().setFieldValue("priority", priority);
308 filter.getEntity().update();
309 filterBefore.getEntity().update();
315 public String moveFilterDown(String anId) {
316 Filter filter = getFilterForId(anId);
317 String priority = filter.getEntity().getFieldValue("priority");
318 int index = filters.indexOf(filter);
319 if (index<filters.size()-1) {
320 Filter filterAfter = (Filter) filters.remove(index+1);
321 filters.add(index, filterAfter);
322 filter.getEntity().setFieldValue("priority", filterAfter.getEntity().getFieldValue("priority"));
323 filterAfter.getEntity().setFieldValue("priority", priority);
324 filter.getEntity().update();
325 filterAfter.getEntity().update();
331 public String moveFilterToBottom(String anId) {
332 Filter filter = getFilterForId(anId);
333 String priority = filter.getEntity().getFieldValue("priority");
334 int index = filters.indexOf(filter);
335 if (index>=0 && index<filters.size()-1) {
336 filters.remove(index);
337 Filter filterBefore= (Filter) filters.get(filters.size()-1);
338 filters.add(filters.size(), filter);
339 filter.getEntity().setFieldValue("priority", filterBefore.getEntity().getFieldValue("priority"));
340 filterBefore.getEntity().setFieldValue("priority", priority);
341 filter.getEntity().update();
342 filterBefore.getEntity().update();
349 public String getName() {
350 return entity.getFieldValue("name");
354 /** This class reflects a row of the filter database table.
355 * To actually run a filter on data, use the test() method.
356 * This class will automatically retreive and use the correct
359 public class Filter {
360 private Entity entity;
361 private FilterInstance instance;
363 public Filter(Entity anEntity) throws AbuseExc {
364 this(anEntity, getFilterTypeForId(anEntity.getFieldValue("type")).constructFilterInstance(anEntity.getFieldValue("expression")));
367 public Filter(Entity anEntity, FilterInstance anInstance) {
369 instance = anInstance;
372 public Entity getEntity() {
376 public EntityAdapter getEntityAdapter() {
377 return model.makeEntityAdapter("filter", entity);
380 public void update(String aType, String anExpression, String aComments, String aTag,
381 String anArticleAction, String aCommentAction) throws AbuseExc {
383 instance = getFilterTypeForId(aType).constructFilterInstance(anExpression);
385 entity.setFieldValue("type", aType);
386 entity.setFieldValue("expression", anExpression);
387 entity.setFieldValue("tag", aType);
388 entity.setFieldValue("comment", aComments);
389 entity.setFieldValue("articleaction", anArticleAction);
390 entity.setFieldValue("commentaction", aCommentAction);
391 entity.setFieldValue("last_hit", null);
395 public void updateLastHit(Date aDate) {
396 entity.setFieldValue("last_hit",
397 DatabaseHelper.convertDateToInternalRepresenation(
398 new Date(System.currentTimeMillis())));
402 public String getType() {
403 return entity.getFieldValue("type");
406 public String getExpression() {
407 return entity.getFieldValue("expression");
410 public String getTag() {
411 return entity.getFieldValue("tag");
414 public String getComment() {
415 return entity.getFieldValue("comment");
418 public String getArticleAction() {
419 return entity.getFieldValue("articleaction");
422 public String getCommentAction() {
423 return entity.getFieldValue("commentaction");
426 public FilterInstance getInstance() {
430 public boolean test(Entity anEntity, Request aRequest) {
431 return instance.test(anEntity, aRequest);
435 public synchronized void reload() {
436 filterGroups.clear();
437 idToFilterGroup.clear();
440 Iterator i = new EntityIteratorAdapter("", "priority asc", 100, model, "filterGroup");
441 while (i.hasNext()) {
442 EntityAdapter entityAdapter = (EntityAdapter) i.next();
443 List filters = new ArrayList();
444 Iterator j = (Iterator) entityAdapter.getIterator("to_filters");
445 while (j.hasNext()) {
446 filters.add(((EntityAdapter) j.next()).getEntity());
449 FilterGroup filterGroup = new FilterGroup(entityAdapter.getEntity(), filters);
450 introduceFilterGroup(filterGroup);
453 catch (Throwable e) {
454 logger.error("Can't load filters: " + e.getMessage(), e);
458 public synchronized List getFilterGroups() {
459 List result = new ArrayList();
460 Iterator i = filterGroups.iterator();
461 while (i.hasNext()) {
462 result.add(((FilterGroup) i.next()).getEntityAdapter());
468 public synchronized void updateFilterGroup(String anId, String aName) {
469 FilterGroup filterGroup = getFilterGroupForId(anId);
470 filterGroup.getEntity().setFieldValue("name", aName);
471 filterGroup.getEntity().update();
474 public synchronized void addFilterGroup(String aName) throws DatabaseExc {
475 Entity entity = DatabaseFilterGroup.getInstance().createNewEntity();
476 entity.setFieldValue("name", aName);
478 String priority = "1";
480 if (filterGroups.size() > 0) {
482 String lastPriorityString = ((FilterGroup) filterGroups.get(filterGroups.size()-1)).getEntity().getFieldValue("priority");
483 int lastPriority = Integer.parseInt(lastPriorityString);
484 priority = Integer.toString(lastPriority + 1);
486 catch (Exception e) {
489 entity.setFieldValue("priority", priority);
492 FilterGroup filterGroup = new FilterGroup(entity);
493 introduceFilterGroup(filterGroup);
496 public synchronized void moveFilterGroupUp(String anId) {
497 FilterGroup group = (FilterGroup) idToFilterGroup.get(anId);
498 String priority = group.getEntity().getFieldValue("priority");
499 int index = filterGroups.indexOf(group);
501 FilterGroup groupBefore = (FilterGroup) filterGroups.remove(index-1);
502 filterGroups.add(index, groupBefore);
503 group.getEntity().setFieldValue("priority", groupBefore.getEntity().getFieldValue("priority"));
504 groupBefore.getEntity().setFieldValue("priority", priority);
505 group.getEntity().update();
506 groupBefore.getEntity().update();
510 public synchronized void moveFilterGroupDown(String anId) {
511 FilterGroup group = (FilterGroup) idToFilterGroup.get(anId);
512 String priority = group.getEntity().getFieldValue("priority");
513 int index = filterGroups.indexOf(group);
514 if (index<filterGroups.size()-1) {
515 FilterGroup groupAfter = (FilterGroup) filterGroups.remove(index+1);
516 filterGroups.add(index, groupAfter);
517 group.getEntity().setFieldValue("priority", groupAfter.getEntity().getFieldValue("priority"));
518 groupAfter.getEntity().setFieldValue("priority", priority);
519 group.getEntity().update();
520 groupAfter.getEntity().update();
524 public synchronized void deleteFilterGroup(String anId) {
526 FilterGroup filterGroup = getFilterGroupForId(anId);
527 removeFilterGroup(filterGroup);
528 DatabaseFilter.getInstance().deleteByWhereClause("filter_group_id = " + anId);
529 DatabaseFilterGroup.getInstance().delete(anId);
532 public synchronized void deleteFilter(String aGroupId, String anId) {
533 getFilterGroupForId(aGroupId).deleteFilter(anId);
537 public synchronized String updateFilter(String aGroupId, String anId,
538 String aType, String anExpression,
541 String anArticleAction,
542 String aCommentAction) {
543 return getFilterGroupForId(aGroupId).updateFilter(anId, aType,
544 anExpression, aComments, aTag, anArticleAction, aCommentAction);
547 public synchronized String addFilter(String aGroupId,
548 String aType, String anExpression,
551 String anArticleAction,
552 String aCommentAction) throws DatabaseExc {
553 return getFilterGroupForId(aGroupId).createFilter(aType, anExpression,
554 aComments, aTag, anArticleAction, aCommentAction);
557 public synchronized String moveFilterUp(String aGroupId, String anId) {
558 return getFilterGroupForId(aGroupId).moveFilterUp(anId);
561 public synchronized String moveFilterDown(String aGroupId, String anId) {
562 return getFilterGroupForId(aGroupId).moveFilterDown(anId);
565 public synchronized String moveFilterToTop(String aGroupId, String anId) {
566 return getFilterGroupForId(aGroupId).moveFilterToTop(anId);
569 public synchronized String moveFilterToBottom(String aGroupId, String anId) {
570 return getFilterGroupForId(aGroupId).moveFilterToBottom(anId);
575 public FilterGroup getFilterGroupForId(String anId) {
576 FilterGroup result = (FilterGroup) idToFilterGroup.get(anId);
577 if (result == null) {
578 throw new NullPointerException("No such filter group");
584 public Filter getFilterForId(String aGroupId, String anId) {
585 return getFilterGroupForId(aGroupId).getFilterForId(anId);
589 public List getFilters(String aFilterGroupId) {
590 return getFilterGroupForId(aFilterGroupId).getFilterEntityAdapterList();
593 private synchronized void introduceFilterGroup(FilterGroup aFilterGroup) {
594 filterGroups.add(aFilterGroup);
595 idToFilterGroup.put(aFilterGroup.getEntity().getId(), aFilterGroup);
598 private synchronized void removeFilterGroup(FilterGroup aFilterGroup) {
599 filterGroups.remove(aFilterGroup);
600 idToFilterGroup.remove(aFilterGroup.getEntity().getId());
603 private FilterType getFilterTypeForId(String anId) {
604 return (FilterType) filterTypes.get(anId);