This example is a sort of "Hello, World!" with MetaRBE. Demonstrates how to parse a text file and recognize patterns like digits, words, lines. In the end it shows statistics for counted words, digits and lines of text.
Sources:
- Main.java - Shows how to program session and rules
- WcSession.java - working session to read text file
- WcSessionFactory.java - Creates session object
- WcEvent.java - Describes event object
- WordMatch.java - Rule constraint for word pattern
- NumberMatch.java - Number rule constraint
Main.java
Main.java is major part of this example. It illustrates how to use MetaRBE API. We create a session, describe events, rules and actions.
package net.sf.metarbe.example.wc;
import net.sf.metarbe.ActionEvent;
import net.sf.metarbe.DuplicateNameException;
import net.sf.metarbe.EventGenerator;
import net.sf.metarbe.RuleAction;
import net.sf.metarbe.RuleContext;
import net.sf.metarbe.RuleSemanticModel;
import net.sf.metarbe.RuleRuntime;
import net.sf.metarbe.RuleServiceProvider;
import net.sf.metarbe.RuleSession;
import net.sf.metarbe.RuleSessionEvent;
import net.sf.metarbe.RuleSessionType;
import net.sf.metarbe.SessionFactoryIsNotSetException;
import net.sf.metarbe.impl.RuleSetManagerImpl;
import net.sf.metarbe.impl.RuleServiceProviderImpl;
public class Main {
public static int digits = 0;
public static int words = 0;
public static int lines = 0;
/**
* @param args
*/
public static void main(String[] args) {
if(args.length==0){
System.out.println("USAGE: java -cp metarbe.jar net.sf.metarbe.example.wc.Main <filename>");
System.exit(0);
}
RuleServiceProvider rsp = RuleServiceProviderImpl.getRuleServiceProvider();
// Create runtime instance
RuleRuntime rr = rsp.getRuleRuntime();
// Our session is not aimed to keep state of process in between invocations
rr.registerRuleSessionFactory(new WcSessionFactory(), RuleSessionType.STATELESS_SESSION);
// Create a dictionary to denote certain states in processing
final RuleSemanticModel ruleLayout = new RuleSemanticModel();
try {
// textparser is main actor here, so introduce it
ruleLayout.addContext("textparser");
// context of text parser can allow the following states
ruleLayout.addState("failed"); // text parser failed to recognize a token or system error occured
ruleLayout.addState("word-ahead"); // text parser went word ahead
ruleLayout.addState("line-ahead"); // text parser wen line of text ahead
} catch (DuplicateNameException e) {
e.printStackTrace();
}
// EventGenerator allows customize emitting event
EventGenerator eg = new EventGenerator(){
public RuleSessionEvent createEventInContext(RuleContext aRuleContext, RuleSession aSession) {
return new WcEvent(
aRuleContext,
aSession.getValue("source"),
aSession.getValue("textData").toString());
}
};
try {
// Create a session object
RuleSession ruleSession = rr.createRuleSession (ruleLayout, RuleSessionType.STATELESS_SESSION);
// Register EventGenerator instance per context state
ruleSession.addEventGenerator ( ruleLayout.getRuleContext("textparser:failed"), eg );
ruleSession.addEventGenerator ( ruleLayout.getRuleContext("textparser:word-ahead"), eg );
ruleSession.addEventGenerator ( ruleLayout.getRuleContext("textparser:line-ahead"), eg );
// Create an instance of RuleSetmanager that dispatches events to rules
RuleSetManagerImpl ad = new RuleSetManagerImpl("Text Recognition Dispatcher", ruleSession );
// Add a rule to count recognized in text digits
ad.createRule("count for digits",
ruleLayout.getRuleContext("textparser:word-ahead"),
new NumberMatch ( ),
new RuleAction ( ) {
public void onActionEvent(ActionEvent evt) {
digits++;
}
}
);
// Add a rule to count recognized in text words
ad.createRule("count for words",
ruleLayout.getRuleContext ("textparser:word-ahead"),
new WordMatch(),
new RuleAction(){
public void onActionEvent(ActionEvent evt) {
words++;
}
}
);
// Add a rule to count recognized in text lines
ad.createRule("count for lines",
ruleLayout.getRuleContext ("textparser:line-ahead"),
new RuleAction(){
public void onActionEvent (ActionEvent evt) {
lines++;
}
}
);
// Error handler is also can be a rule
ad.createRule("recognition has failed",
ruleLayout.getRuleContext ("textparser:failed"),
new RuleAction(){
public void onActionEvent(ActionEvent evt) {
System.err.println("Text recognition has failed due to: "+((WcEvent)evt.getRuleSessionEvent()).getTextData());
}
}
);
// Run processing with a filename given as cmdline argument
ad.executeRules (args[0]);
System.out.println("File "+args[0]+": lines="+lines+" words="+words+" numbers="+digits);
} catch (SessionFactoryIsNotSetException e) {
e.printStackTrace();
}
}
}
WcSession.java
This class designed to parse text file and discover elements such as words and lines. It also signals a failure if given file is not readable. In this example session implements StatelessSession interface and it is most low-level implementation. There are implementations for session to get rid of overloading overhead.
package net.sf.metarbe.example.wc;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.metarbe.EventGenerator;
import net.sf.metarbe.RuleActivator;
import net.sf.metarbe.RuleContext;
import net.sf.metarbe.RuleSemanticModel;
import net.sf.metarbe.RuleContextValidation;
import net.sf.metarbe.RuleSessionSupport;
import net.sf.metarbe.RuleSessionType;
import net.sf.metarbe.StatelessRuleSession;
public class WcSession implements StatelessRuleSession {
private RuleSessionSupport sessionSupport = new RuleSessionSupport();
protected String filename;
public WcSession ( ) {
}
public void addEventGenerator(RuleContext aRuleContext,EventGenerator anEventGenerator) {
sessionSupport.addEventGenerator(aRuleContext, anEventGenerator);
}
public void addEventGenerator(RuleContext aRuleContext, EventGenerator anEventGenerator, int idx) {
sessionSupport.addEventGenerator(aRuleContext, anEventGenerator, idx);
}
public void bindParameter(String aParamName, Object aValue) {
sessionSupport.bindParameter(aParamName, aValue);
}
public void executeRules(Object data) {
filename = (String)data;
bindParameter("source", data);
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line = null;
while((line = reader.readLine ( ))!=null){
if(line.length()==0){
sessionSupport.bindParameter("textData", "");
sessionSupport.fireEventInContext(getRuleSemanticModel().getRuleContext("textparser:line-ahead"), this);
continue;
}
String[] words = line.split(" ");
for (String word : words) {
sessionSupport.bindParameter("textData", word);
sessionSupport.fireEventInContext(getRuleSemanticModel().getRuleContext("textparser:word-ahead"), this);
}
sessionSupport.bindParameter("textData", "");
sessionSupport.fireEventInContext(getRuleSemanticModel().getRuleContext("textparser:line-ahead"), this);
}
} catch (FileNotFoundException e) {
sessionSupport.bindParameter("textData", e.getMessage());
sessionSupport.fireEventInContext(getRuleSemanticModel().getRuleContext("textparser:failed"), this);
} catch (IOException e) {
sessionSupport.bindParameter("textData", e.getMessage());
sessionSupport.fireEventInContext(getRuleSemanticModel().getRuleContext("textparser:failed"), this);
}
}
public Iterator getParameters() {
return sessionSupport.getParameters();
}
public RuleActivator getRuleActivator() {
return sessionSupport.getRuleActivator();
}
public RuleSemanticModel getRuleSemanticModel() {
return sessionSupport.getRuleSemanticModel();
}
public RuleSessionType getSessionType() {
return RuleSessionType.STATELESS_SESSION;
}
public Object getValue(String aParamName) {
return sessionSupport.getValue(aParamName);
}
public void setRuleActivator(RuleActivator aRuleActivator) {
sessionSupport.setRuleActivator(aRuleActivator);
}
public void setRuleSemanticModel(RuleSemanticModel aRuleModel) {
sessionSupport.setRuleSemanticModel(aRuleModel);
}
public Map<RuleContext, RuleContextValidation> getContextValidations() {
return sessionSupport.getContextValidations();
}
public Map<RuleContext, List<EventGenerator>> getEventGenerators() {
return getEventGenerators();
}
public void unbindParameter(String aParamName) {
sessionSupport.unbindParameter(aParamName);
}
public void release() { }
public void removeEventGenerator(RuleContext aRuleContext, EventGenerator anEventGenerator) {
sessionSupport.removeEventGenerator(aRuleContext, anEventGenerator);
}
}
WcSessionFactory.java
This factory used to create a session object. For more complex cases it can be useful in that sense that use might want to differentiate session objects depending ongiven parameter (FactoryMethod pattern)
package net.sf.metarbe.example.wc;
import net.sf.metarbe.RuleSession;
import net.sf.metarbe.RuleSessionFactory;
public class WcSessionFactory implements RuleSessionFactory {
public RuleSession createRuleSession() {
return new WcSession();
}
}
WcEvent.java
This event object is a contract between rules and session. In general is ValueObject pattern.
package net.sf.metarbe.example.wc;
import net.sf.metarbe.RuleContext;
import net.sf.metarbe.RuleSessionEvent;
public class WcEvent extends RuleSessionEvent {
private String textData;
public WcEvent(RuleContext aRuleContext, Object source, String textData) {
super(aRuleContext, source);
this.textData = textData;
}
@Override
public Object getMatchedValue() {
return getTextData();
}
public String getTextData() {
return textData;
}
}
WordMatch.java
Determines if given data is a word and not number.
package net.sf.metarbe.example.wc;
import net.sf.metarbe.RuleConstraint;
public class WordMatch implements RuleConstraint {
public boolean match(Object aValue) {
try {
Double.parseDouble(String.valueOf(aValue));
} catch (NumberFormatException e) {
return true;
}
return false;
}
}
NumberMatch.java
Determines if given data is number and not a word
package net.sf.metarbe.example.wc;
import net.sf.metarbe.RuleConstraint;
public class NumberMatch implements RuleConstraint {
public boolean match(Object aValue) {
try {
Double.parseDouble ( String.valueOf(aValue) );
} catch (NumberFormatException e) {
return false;
}
return true;
}
}