Subsections
A more complicated exampleIn the words of Emeril, let's ``kick up our example a few notches'' now by adding some real world functionality. I'm going to add the following capability to my earlier example:
An EmailMessage classThe first thing I'm going to do is create a simple EmailMessage class. The contents of this class are shown in the code below:
package email2;
public class EmailMessage
{
private String from;
private String to;
private String subject;
private String contents;
private boolean attachment;
public EmailMessage()
{
}
public void setFrom(String from) {
this.from = from;
}
public void setTo(String to) {
this.to = to;
}
public void setSubject(String subject) {
this.subject = subject;
}
public void setContents(String contents) {
this.contents = contents;
}
public void setAttachment(boolean attachment) {
this.attachment = attachment;
}
public String getFrom() {
return from;
}
public String getTo() {
return to;
}
public String getSubject() {
return subject;
}
public String getContents() {
return contents;
}
public boolean hasAttachment() {
return attachment;
}
}
This is a very basic Java class with no real functionality other than getters and setters. That being said, it's a nice simple class for the points I'm trying to convey.
EmailRuleSetApp2The next thing to look at is the revised ``driver'' application for this example. Before looking at it, here is a quick list of changes to it:
With that quick introduction, here is the source code for the new application named EmailRuleSetApp2:
package email2;
import java.util.Iterator;
import com.ibm.able.Able;
import com.ibm.able.AbleException;
import com.ibm.able.rules.AbleRuleSet;
import java.util.List;
import java.util.ArrayList;
public class EmailRuleSetApp2
{
public static void main(String[] args)
{
try
{
// retrieve the rule set
String rules = "C:/Projects/BorlandConference2004/AI/ABLE/JB_ABLE_Test/src/email2/email.arl";
AbleRuleSet ruleSet = new AbleRuleSet();
ruleSet.parseFromARL(rules);
ruleSet.init();
// create our (fake) data
EmailMessage message = new EmailMessage();
message.setFrom("Your Mother");
message.setTo("al@missiondata.com");
message.setSubject("");
message.setContents("blah blah blah");
message.setAttachment(true);
// create a fake rejection list. note that this is really read from a
// config file the user can control.
List subjectKeywordsToReject = new ArrayList();
subjectKeywordsToReject.add("viagra");
subjectKeywordsToReject.add("vicodin");
// create a fake whitelist, i.e., the users I know and will always allow mail from
List whitelist = new ArrayList();
whitelist.add("wife@devdaily.com");
whitelist.add("mom@devdaily.com");
whitelist.add("borland.com");
Object[] data = new Object[]{
message,
subjectKeywordsToReject,
whitelist};
Object[] input = null;
Object[] output = null;
Able.startTraceLogging(Able.TRC_LOW, Able.MSG_NONE, null);
Able.TraceLog.text(Able.TRC_LOW, "Starting Run ----------");
output = (Object[]) ruleSet.process(input = data);
System.err.println("Output is: " + output[0]);
}
catch (AbleException ae)
{
if (ae.getExceptions() == null)
{
System.out.println(ae.getLocalizedMessage());
} else
{
Iterator it = ae.getExceptions().iterator();
while (it.hasNext())
{
Exception e = (Exception) it.next();
System.out.println(e.getLocalizedMessage());
}
}
} catch (Exception exp)
{
System.out.println(exp.getLocalizedMessage());
exp.printStackTrace();
}
System.exit(0);
}
}
Rules engine changesThe next thing to review is the changes to the rule set that I used in the simple example. Here is a quick list of the changes to the rules engine:
The new rules set is shown next, followed by a discussion of how it works.
ruleset Email
{
import java.util.List;
import email2.EmailMessage;
import email2.EmailRuleUtils;
variables
{
EmailRuleUtils emailRuleUtils = new EmailRuleUtils();
EmailMessage message = new EmailMessage();
String result = new String("");
List subjectFieldRejectionPatterns;
List whitelist;
}
inputs{message,subjectFieldRejectionPatterns,whitelist};
outputs{result};
void process() using Forward
{
// do this so a maximum of one rule is fired
: setControlParameter(ARL.ControlStrategy, ARL.FIRE_ONE_RULE);
SenderUnknownAndSubjectIsEmpty [1000]:
If ( emailRuleUtils.senderIsUnknown(message.getFrom(),whitelist) and emailRuleUtils.isBlankOrNull(message.getSubject()) )
result = "SPAM (SenderUnknownAndSubjectIsEmpty)";
SenderUnknownAndAttachment [990]:
If (emailRuleUtils.senderIsUnknown(message.getFrom(),whitelist) and message.hasAttachment())
result = "SPAM (SenderUnknownAndAttachment)";
SubjectFieldMatchesPattern [900]:
If (emailRuleUtils.fieldMatchesSpamPattern(message.getSubject(),subjectFieldRejectionPatterns))
result = "SPAM (SubjectFieldMatchesPattern)";
Default :
result = "NOT SPAM";
}
void postProcess()
{
: println("Ruleset concludes the email is a " + result + " email.");
}
}
A simple utility classThe last set of changes I've made is to create a new utility class named EmailRuleUtils. This class contains two methods that can be called from the rules engine, fieldMatchesSpamPattern and senderIsUnknown. I've put this logic in a separate class for several reasons. First, I prefer the obvious separation of concerns between the application, the rules engine, and these helper methods. Second, I like to have these methods in an IDE like JBuilder, where I can develop code more quickly and efficiently. Third, I like to be able to create unit tests against simple helper methods like these. The source code for the EmailRuleUtils class is shown next.
package email2;
import java.util.regex.Pattern;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.List;
public class EmailRuleUtils
{
public boolean isBlankOrNull(String string)
{
if ( string==null || string.trim().equals("") ) return true;
else return false;
}
/**
* If the given field matches any of the patterns in the supplied list of patterns,
* this method will return true.
* @param currentField Pass in things like the Subject field, From field, Reply-to, etc.
* @param knownPatternsToReject A List of patterns that the supplied field will be tested against.
* @return boolean
*/
public boolean fieldMatchesSpamPattern(String currentField, List knownPatternsToReject)
{
if ( currentField == null ) return true;
currentField = currentField.toLowerCase();
Iterator it = knownPatternsToReject.iterator();
while ( it.hasNext() )
{
String keywordToReject = ((String)it.next()).toLowerCase();
Pattern aPattern = Pattern.compile(keywordToReject,Pattern.CASE_INSENSITIVE);
Matcher aMatcher = aPattern.matcher(currentField);
if ( aMatcher.find() ) return true;
}
// the given string didn't match a rejection pattern? return false.
return false;
}
public boolean senderIsUnknown(String sender, List whitelist)
{
if ( sender == null ) return true;
sender = sender.toLowerCase();
Iterator it = whitelist.iterator();
while ( it.hasNext() )
{
String emailAddress = ((String)it.next()).toLowerCase();
Pattern aPattern = Pattern.compile(emailAddress,Pattern.CASE_INSENSITIVE);
Matcher aMatcher = aPattern.matcher(sender);
if ( aMatcher.find() ) return false;
}
return true;
}
}
Running this exampleLooking at the code samples provided can you guess what the output of the program will be? In this particular example the output is ``Output is: SPAM (SenderUnknownAndSubjectIsEmpty)``. This is because this rule was set to the highest priority and it fired first. Once it fired, the process() method exited.
Create your own testsFor your own exercise you can try different things like changing the priority of the rules, and varying the inputs to see how to make the other rules fire. The important thing for me is that once you get through these basic hurdles, you can start enjoying ABLE faster, and start experimenting with some of the really powerful things that are under the hood.
Next: More of the ABLE Up: AI Previous: Getting started with a |