java Anti Spam ENgine SourceForge.net Logo
The pure java Anti Spam ENgine
Overview
Features
Getting Started
Download
User Guide
FAQ
Forums SourceForge Link
Javadoc New Window
License
Commercial Use
Project Home SourceForge Link
 
java.net member!

Building Plugins

One of the most powerful features of jASEN is the ability to incorporate your own scanning logic into the engine

In fact, as time progresses we will be adding more and more functionality to the engine via this very method

A plugin is essentially a java class which implements the JasenPlugin interface (as defined by org.jasen.interfaces.JasenPlugin). This interface only defines two methods which must be implemented:

The init(...) method initializes the plugin. This is called ONCE ONLY by the engine when loading the plugins defined in the jasen-config file

The method will be provided with a java.util.Properties object derived from the properties file specified for the plugin in the jasen-config file
/**
 * Initializes the plugin with the given properties
 * @param properties
 * @throws JasenException
 */
public void init(Properties properties) throws JasenException;
The test(...) method is called when the engine requires the plugin to perform its test against a message

Refer to the javadoc for detailed description of the classes passed and returned to/from this method
/**
 * Computess the "spamminess" of a message.
 * @param engine A reference to the current engine instance.
 * @param rawMessage The original MimeMessage passed to the engine.
 * @param parsedMessage The parsed JasenMessage returned from the MimeParser.
 * @param data The data returned from the HTML Parser / Tokenizer combination.
 * @param parser The parser used to parse mail headers
 * @return A JasenTestResult
 * @throws JasenException If an error occurs while performing the test
 */
public JasenTestResult test(Jasen engine, MimeMessage rawMessage, JasenMessage parsedMessage, ParserData data, ReceivedHeaderParser parser) throws JasenException;
The destroy() method is called when the engine is unloaded or restarted.

/**
 * Destroys the plugin.  This is called when the core jASEN engine is destroyed
 * @throws JasenException
 */
public void destroy() throws JasenException;	

Sample Plugin

Below is a sample plugin which simply returns a fixed probability based on a configuration defined in its properties file

Plugin Class

public class TestPlugin implements JasenPlugin
{
    private float fResult = 0.5f;

    public TestPlugin() {
        super ();
    }

    public void init(Properties properties) throws JasenException {
        if(properties != null) {
            // Get the result value
            String stResult = properties.getProperty("result");
            if(stResult != null) {
                fResult = Float.parseFloat(strMin);
            }
        }
    }

    public JasenTestResult test(Jasen engine, 
                                MimeMessage rawMessage, 
                                JasenMessage parsedMessage, 
                                ParserData data, 
                                ReceivedHeaderParser parser) throws JasenException {

        ProbabilityTestResult result = new ProbabilityTestResult();
        result.setProbability(fResult);
        return result;
    }
	

    public void destroy() throws JasenException {
        // Does nothing
    }	
}

TestPlugin.properties
# Properties file for TestPlugin

# Hard-coded result
result=0.75
jasen-config
...
<plugin name="TestPlugin" priority="1" type="org.jasen.plugins.TestPlugin" properties="default/TestPlugin.properties"/>
...

Implementation Notes and Recommendations

There are a few rules/pointers which should be understood when creating plugins:
  1. Plugins MUST be thread safe. Do NOT maintain state locally within a plugin. Plugin instances are shared across threads in a mult-threaded implementation (think Servlets)
  2. If a properties file is not specified, or could not be found for a plugin, null is passed to the init method
  3. ProbabilityTestResults should ALWAYS be returned with a value between 0.0 and 1.0 such that:
    0.0 < result < 1.0
  4. PointTestResults should ALWAYS be given a min value of > 0.0 and a max value of < 1.0 such that:
    0.0 < min <= max < 1.0
  5. Be mindful of the priority of the plugin with respect to its relative importance and performance impact. Plugins which are of low importance but have a high [negative] impact on performance should be configured to execute after plugins with a higher importance or reduced performance impact.

    This way, if an important/high performance plugin is able to determine within the threshold specified that an email is (or is not) spam then the less important, slower plugins may not need to execute at all.
  6. Avoid any mime parsing or tokenizing inside the plugin. All the required parsing should already have been done and be available from the objects provided.

    If the information you require in a plugin is not present in one of the objects provided in the test(...) method and you feel that it ought to be, then you can either let us know and we will consider including it into the next release, or you can write your own (extended) version of the relevant class (eg MimeMessageParser).
  7. If performing any DNS lookups or InetAddress resolutions, use the DNSResolver and InetAddressResolver available inside the core engine object (Jasen class) provided in the test(...) method.
  8. Never return null from the test(...) method... You'll get an exception
  9. If your plugin does not appear to be executing, check the following:
    • Make sure you have added it to the core jasen configuration file
    • Check that preceding plugins aren't returning absolute results or results which exceed the given threshold thereby ceasing further processing
    • You have correctly configured the its properties file (if required) in the jasen-config and that this properties file is available
  10. No more tips.. just wanted an even 10 :)