package com.limegroup.gnutella.spam;
import java.util.Arrays;
/**
* Like a KeywordToken but also holds part of the meta-data name which this
* token belongs to, so the filter can specifically rate for example videos with
* "Type: Adult" as spam
*/
public class XMLKeywordToken extends AbstractToken {
private static final long serialVersionUID = 3617573808026760503L;
public static final int TYPE = TYPE_XML_KEYWORD;
/**
* must be positive
*
* This is a heuristic value to prevent an token from becoming bad after
* only a small number of bad evaluations.
*/
private static final byte INITAL_GOOD = 20;
/**
* must be positive
*
* This value determines how dynamic the filter is. A low MAX value will
* allow this Token to get a bad rating after occourring only a few times in
* spam, a high value will make it very improbable that the filter will
* change its mind about a certain token without user-intervention
*/
private static final int MAX = 100;
private final byte[] _keyword;
private final byte[] _xmlField;
private byte _good;
private byte _bad;
private final int _hashCode;
XMLKeywordToken(String xmlField, byte[] keyword) {
_good = 90; // give every keyword initial credit
_bad = 0;
_keyword = keyword;
_xmlField = xmlField.getBytes();
int hash = xmlField.hashCode();
for(int i = 0;i < keyword.length; i++)
hash = (37 * hash) + keyword[i];
_hashCode = hash;
}
/**
* implements interface <tt>Token</tt>
*/
public float getRating() {
return (float) Math.pow(1.f * _bad / (_good + _bad + 1), 2);
}
/**
* implements interface <tt>Token</tt>
*/
public void rate(int rating) {
_age = 0;
switch (rating) {
case RATING_GOOD:
_good++;
break;
case RATING_SPAM:
_bad++;
break;
case RATING_USER_MARKED_GOOD:
_bad = 0;
break;
case RATING_USER_MARKED_SPAM:
_bad = (byte) Math.min(10 + _bad, MAX);
break;
case RATING_CLEARED:
_bad = 0;
_good = 90;
break;
default:
throw new IllegalArgumentException("unknown type of rating");
}
if (_good >= MAX || _bad >= MAX) {
_good = (byte) (_good * 9 / 10);
_bad = (byte) (_bad * 9 / 10);
}
}
/**
* implements interface <tt>Token</tt>
*/
public int getType() {
return TYPE;
}
public final int hashCode() {
return _hashCode;
}
public final boolean equals(Object o) {
if (o == null)
return false;
if (!(o instanceof XMLKeywordToken))
return false;
if (_hashCode != o.hashCode()) {
return false;
}
return Arrays.equals(_xmlField, ((XMLKeywordToken)o)._xmlField)
&& Arrays.equals(_keyword, ((XMLKeywordToken)o)._keyword);
}
/**
* overrides method from <tt>Object</tt>
*/
public String toString() {
return new String(_xmlField) + "::" + new String(_keyword) + " : "
+ _good + " : " + _bad;
}
}