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; } }