[jboss-svn-commits] JBL Code SVN: r30150 - in labs/jbossrules/trunk/drools-core/src/test: java/org/drools/reteoo/test and 5 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Sun Nov 15 02:11:38 EST 2009
Author: mark.proctor at jboss.com
Date: 2009-11-15 02:11:38 -0500 (Sun, 15 Nov 2009)
New Revision: 30150
Added:
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTester.java
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTesterTest.java
labs/jbossrules/trunk/drools-core/src/test/resources/org/
labs/jbossrules/trunk/drools-core/src/test/resources/org/drools/
labs/jbossrules/trunk/drools-core/src/test/resources/org/drools/reteoo/
labs/jbossrules/trunk/drools-core/src/test/resources/org/drools/reteoo/test/
labs/jbossrules/trunk/drools-core/src/test/resources/org/drools/reteoo/test/JoinNode.data
Log:
JBRULES-2339 Rete DSL test harness
Added: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTester.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTester.java (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTester.java 2009-11-15 07:11:38 UTC (rev 30150)
@@ -0,0 +1,784 @@
+package org.drools.reteoo.test;
+
+import java.beans.IntrospectionException;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.drools.FactHandle;
+import org.drools.RuleBaseConfiguration;
+import org.drools.WorkingMemory;
+import org.drools.base.ClassFieldAccessorCache;
+import org.drools.base.ClassFieldAccessorStore;
+import org.drools.base.ClassObjectType;
+import org.drools.base.ValueType;
+import org.drools.base.evaluators.EvaluatorRegistry;
+import org.drools.base.evaluators.Operator;
+import org.drools.command.Context;
+import org.drools.common.InternalFactHandle;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.common.PropagationContextImpl;
+import org.drools.common.SingleBetaConstraints;
+import org.drools.reteoo.BetaMemory;
+import org.drools.reteoo.BetaNode;
+import org.drools.reteoo.EntryPointNode;
+import org.drools.reteoo.JoinNode;
+import org.drools.reteoo.LeftInputAdapterNode;
+import org.drools.reteoo.LeftTuple;
+import org.drools.reteoo.LeftTupleMemory;
+import org.drools.reteoo.LeftTupleSource;
+import org.drools.reteoo.MockLeftTupleSink;
+import org.drools.reteoo.MockObjectSource;
+import org.drools.reteoo.MockTupleSource;
+import org.drools.reteoo.ObjectSink;
+import org.drools.reteoo.ObjectSource;
+import org.drools.reteoo.ObjectTypeNode;
+import org.drools.reteoo.ReteooRuleBase;
+import org.drools.reteoo.RightTuple;
+import org.drools.reteoo.RightTupleMemory;
+import org.drools.reteoo.TupleSourceTest;
+import org.drools.reteoo.ReteooBuilder.IdGenerator;
+import org.drools.reteoo.builder.BuildContext;
+import org.drools.rule.BehaviorManager;
+import org.drools.rule.Declaration;
+import org.drools.rule.Package;
+import org.drools.rule.Pattern;
+import org.drools.rule.VariableConstraint;
+import org.drools.spi.BetaNodeFieldConstraint;
+import org.drools.spi.Evaluator;
+import org.drools.spi.InternalReadAccessor;
+import org.drools.spi.PropagationContext;
+import org.drools.util.StringUtils;
+import org.mvel2.MVEL;
+
+public class ReteTester {
+
+ private ReteTesterHelper reteTesterHelper;
+ private Map<String, Object> steps;
+
+ public ReteTester() {
+
+ this.reteTesterHelper = new ReteTesterHelper();
+
+ this.steps = new HashMap<String, Object>();
+
+ this.steps.put( "ObjectTypeNode",
+ new ObjectTypeNodeStep( this.reteTesterHelper ) );
+ this.steps.put( "LeftInputAdapterNode",
+ new LeftInputAdapterNodeStep( this.reteTesterHelper ) );
+ this.steps.put( "Binding",
+ new BindingStep( this.reteTesterHelper ) );
+ this.steps.put( "JoinNode",
+ new JoinNodeStep( this.reteTesterHelper ) );
+ this.steps.put( "Facts",
+ new FactsStep( this.reteTesterHelper ) );
+ }
+
+ public Map run(List<DslStep> steps) {
+ Map context = new HashMap();
+
+ RuleBaseConfiguration conf = new RuleBaseConfiguration();
+ conf.setCompositeKeyDepth( 0 );
+
+ ReteooRuleBase rbase = new ReteooRuleBase( "ID",
+ conf );
+ BuildContext buildContext = new BuildContext( rbase,
+ rbase.getReteooBuilder().getIdGenerator() );
+ context.put( "BuildContext",
+ buildContext );
+ context.put( "ClassFieldAccessorStore",
+ this.reteTesterHelper.getStore() );
+
+ InternalWorkingMemory wm = (InternalWorkingMemory) rbase.newStatefulSession( true );
+ context.put( "WorkingMemory",
+ wm );
+
+ for ( DslStep step : steps ) {
+ String name = step.getName();
+ Object object = this.steps.get( name );
+ if ( object != null && object instanceof Step ) {
+ Step stepImpl = (Step) object;
+ try {
+ stepImpl.execute( context,
+ step.getCommands().toArray( new String[0] ) );
+ } catch ( Exception e ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
+ e );
+ }
+ } else if ( "assert".equals( name.trim() ) ) {
+ assertObject(step, context, wm);
+ } else if ( "retract".equals( name.trim() ) ) {
+ retractObject(step, context, wm);
+ } else {
+ Object node = context.get( name.trim() );
+ if ( name == null ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": step " + name + " does not exist" );
+ }
+
+ if ( node instanceof BetaNode ) {
+ BetaNode betaNode = (BetaNode) node;
+ betaNode( step, betaNode, context, wm );
+ } else {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": unknown node " + node );
+ }
+ }
+ }
+
+ return context;
+ }
+
+ private void betaNode(DslStep step, BetaNode node, Map context, InternalWorkingMemory wm) {
+ try {
+ String[] cmds = step.getCommands().toArray( new String[0] );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );
+
+
+ BetaMemory memory = (BetaMemory) wm.getNodeMemory( node );
+ for ( String cmd : cmds ) {
+ if ( cmd.trim().startsWith( "leftMemory" ) ) {
+
+ int pos = cmd.indexOf( "[" );
+ String nodeName = cmd.substring( 0,
+ pos ).trim();
+ String args = cmd.substring( pos ).trim();
+ String listString = args.replaceAll( "h(\\d+)",
+ "h[$1]" );
+ Map vars = new HashMap();
+ vars.put( "h",
+ handles );
+ List expectedLeftTuples = (List) MVEL.eval( listString,
+ vars );
+
+ LeftTupleMemory leftMemory = memory.getLeftTupleMemory();
+ LeftTuple[] leftTuples = (LeftTuple[]) leftMemory.toArray();
+
+ List actualLeftTuples = new ArrayList( leftTuples.length );
+
+ for ( LeftTuple leftTuple : leftTuples ) {
+ List<InternalFactHandle> tupleHandles = Arrays.asList( leftTuple.toFactHandles() );
+ actualLeftTuples.add( tupleHandles );
+ }
+
+ if ( !expectedLeftTuples.equals( actualLeftTuples ) ) {
+ throw new AssertionError( "line " + step.getLine() + ": left Memory expected " + expectedLeftTuples + " actually " + actualLeftTuples);
+ }
+
+
+ } else if ( cmd.trim().startsWith( "rightMemory" ) ) {
+ int pos = cmd.indexOf( "[" );
+ String nodeName = cmd.substring( 0,
+ pos ).trim();
+ String args = cmd.substring( pos ).trim();
+ String listString = args.replaceAll( "h(\\d+)",
+ "h[$1]" );
+ Map vars = new HashMap();
+ vars.put( "h",
+ handles );
+ List expectedFactHandles = (List) MVEL.eval( listString,
+ vars );
+
+ RightTupleMemory rightMemory = memory.getRightTupleMemory();
+ List<RightTuple> actualRightTuples = Arrays.asList( ( RightTuple[] ) rightMemory.toArray() );
+
+ if ( expectedFactHandles.size() != actualRightTuples.size() ) {
+ throw new AssertionError( "line " + step.getLine() + ": right Memory expected " + actualRightTuples + " actually " + actualRightTuples);
+ }
+
+ for ( int i = 0, length = actualRightTuples.size(); i < length; i++ ) {
+ if ( expectedFactHandles.get(i) != actualRightTuples.get( i ).getFactHandle() ) {
+ throw new AssertionError( "line " + step.getLine() + ": right Memory expected " + actualRightTuples + " actually " + actualRightTuples);
+ }
+ }
+
+ } else {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": command does not exist " + cmd.trim() );
+ }
+ }
+ } catch ( Exception e ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
+ e );
+ }
+ }
+
+ private void assertObject(DslStep step, Map context, InternalWorkingMemory wm) {
+ try {
+ String[] cmds = step.getCommands().toArray( new String[0] );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );
+ for ( String cmd : cmds ) {
+ try {
+ int pos = cmd.indexOf( "[" );
+ String nodeName = cmd.substring( 0,
+ pos ).trim();
+ ObjectTypeNode sink = (ObjectTypeNode) context.get( nodeName );
+ if ( sink == null ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": node " + nodeName + " does not exist" );
+ }
+
+ String args = cmd.substring( pos ).trim();
+ String listString = args.replaceAll( "h(\\d+)",
+ "h[$1]" );
+ Map vars = new HashMap();
+ vars.put( "h",
+ handles );
+ List<InternalFactHandle> list = (List<InternalFactHandle>) MVEL.eval( listString,
+ vars );
+ if ( list == null ) {
+ throw new IllegalArgumentException( cmd.trim() + " does not specify an existing fact handle" );
+ }
+
+ for ( InternalFactHandle handle : list ) {
+ if ( handle == null ) {
+ throw new IllegalArgumentException( cmd.trim() + " does not specify an existing fact handle" );
+ }
+
+ PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
+ PropagationContext.ASSERTION,
+ null,
+ null,
+ handle );
+ sink.assertObject( handle,
+ pContext,
+ wm );
+ }
+ } catch ( Exception e ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute command " + cmd,
+ e );
+
+ }
+ }
+ } catch ( Exception e ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
+ e );
+ }
+ }
+
+ private void retractObject(DslStep step, Map context, InternalWorkingMemory wm) {
+ try {
+ String[] cmds = step.getCommands().toArray( new String[0] );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) context.get( "Handles" );
+ for ( String cmd : cmds ) {
+ try {
+ int pos = cmd.indexOf( "[" );
+ String nodeName = cmd.substring( 0,
+ pos ).trim();
+ ObjectTypeNode sink = (ObjectTypeNode) context.get( nodeName );
+ if ( sink == null ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": node " + nodeName + " does not exist" );
+ }
+
+ String args = cmd.substring( pos ).trim();
+ String listString = args.replaceAll( "h(\\d+)",
+ "h[$1]" );
+ Map vars = new HashMap();
+ vars.put( "h",
+ handles );
+ List<InternalFactHandle> list = (List<InternalFactHandle>) MVEL.eval( listString,
+ vars );
+ if ( list == null ) {
+ throw new IllegalArgumentException( cmd.trim() + " does not specify an existing fact handle" );
+ }
+
+ for ( InternalFactHandle handle : list ) {
+ if ( handle == null ) {
+ throw new IllegalArgumentException( cmd.trim() + " does not specify an existing fact handle" );
+ }
+
+ PropagationContext pContext = new PropagationContextImpl( wm.getNextPropagationIdCounter(),
+ PropagationContext.RETRACTION,
+ null,
+ null,
+ handle );
+ sink.retractObject( handle, pContext, wm );
+ }
+ } catch ( Exception e ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute command " + cmd,
+ e );
+
+ }
+ }
+ } catch ( Exception e ) {
+ throw new IllegalArgumentException( "line " + step.getLine() + ": unable to execute step " + step,
+ e );
+ }
+ }
+
+ public static List<DslStep> buildDslCommands(Reader reader) {
+ try {
+ int commandIndentPos = 0;
+
+ DslStep dslCommand = null;
+ List<DslStep> commands = new ArrayList<DslStep>();
+ StringBuilder cmdContent = null;
+ List<String> cmds = null;
+
+ List<String> lines = chunkReader( reader );
+ int lineCount = 1;
+
+ for ( String line : lines ) {
+ if ( StringUtils.isEmpty( line ) ) {
+ continue;
+ }
+
+ if ( line.charAt( 0 ) != ' ' ) {
+ // finish of the last command
+ if ( dslCommand != null ) {
+ // existing dslCommand, so add arguments before starting again
+ cmds.add( cmdContent.toString() );
+ }
+
+ // start of new command
+ cmds = new ArrayList<String>();
+ dslCommand = new DslStep( lineCount,
+ line.trim(),
+ cmds );
+ commands.add( dslCommand );
+ commandIndentPos = 0;
+ } else {
+ if ( commandIndentPos == 0 ) {
+ commandIndentPos = indentPos( line );
+ cmdContent = new StringBuilder();
+ cmdContent.append( line.trim() );
+ } else {
+ if ( indentPos( line ) > commandIndentPos ) {
+ cmdContent.append( line.trim() );
+ } else {
+ cmds.add( cmdContent.toString() );
+
+ cmdContent = new StringBuilder();
+ cmdContent.append( line.trim() );
+ commandIndentPos = indentPos( line );
+ }
+ }
+ }
+ lineCount++;
+ }
+
+ // finish of the last command
+ if ( dslCommand != null ) {
+ // existing dslCommand, so add arguments before starting again
+ cmds.add( cmdContent.toString() );
+ }
+
+ return commands;
+ } catch ( Exception e ) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ public static int indentPos(String line) {
+ int i;
+ for ( i = 0; i < line.length() && line.charAt( i ) == ' '; i++ ) {
+ // iterate to first char
+ }
+
+ return i;
+ }
+
+ /**
+ * This chunks the reader into a List<String> it removes single line and block comements
+ * while preserving spacing.
+ */
+ public static List<String> chunkReader(Reader reader) {
+ List<String> lines = new ArrayList<String>();
+ BufferedReader bReader = null;
+ if ( !(reader instanceof BufferedReader) ) {
+ bReader = new BufferedReader( reader );
+ }
+ String line;
+ int pos;
+ boolean blockComment = false;
+ try {
+ while ( (line = bReader.readLine()) != null ) {
+ if ( !blockComment ) {
+ pos = line.indexOf( "/*" );
+ if ( pos != -1 ) {
+ int endPos = line.indexOf( "*/" );
+ if ( endPos != -1 ) {
+ // we end the block commend on the same time
+ blockComment = false;
+ } else {
+ // replace line till end
+ blockComment = true;
+ }
+
+ line = line.substring( 0,
+ pos ).concat( StringUtils.repeat( " ",
+ line.length() - pos ) );
+ } else {
+ // no block comment, so see if single line comment
+ pos = line.indexOf( "//" );
+ if ( pos != -1 ) {
+ // we have a single line comment
+ line = line.substring( 0,
+ pos ).concat( StringUtils.repeat( " ",
+ line.length() - pos ) );
+ }
+ }
+ } else {
+ // we are in a block comment, replace all text until end of block
+ pos = line.indexOf( "*/" );
+ if ( pos != -1 ) {
+ line = StringUtils.repeat( " ",
+ pos + 2 ).concat( line.substring( pos + 2,
+ line.length() ) );
+ blockComment = false;
+ } else {
+ line = StringUtils.repeat( " ",
+ line.length() );
+ }
+ }
+ lines.add( line );
+ }
+ } catch ( IOException e ) {
+ throw new RuntimeException( e );
+ }
+
+ return lines;
+ }
+
+ public static class DslStep {
+ private int line;
+
+ private String name;
+ private List<String> commands;
+
+ public DslStep(int line,
+ String name,
+ List<String> commands) {
+ this.line = line;
+ this.name = name;
+ this.commands = commands;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public List<String> getCommands() {
+ return commands;
+ }
+
+ public String toString() {
+ return line + " : " + name + " : " + commands;
+ }
+
+ }
+
+ public static interface Step {
+ public void execute(Map context,
+ String[] args);
+ }
+
+ public static class ObjectTypeNodeStep
+ implements
+ Step {
+
+ private ReteTesterHelper reteTesterHelper;
+
+ public ObjectTypeNodeStep(ReteTesterHelper reteTesterHelper) {
+ this.reteTesterHelper = reteTesterHelper;
+ }
+
+ public void execute(Map context,
+ String[] args) {
+ BuildContext buildContext = (BuildContext) context.get( "BuildContext" );
+ String name;
+ String type;
+
+ if ( args.length == 1 ) {
+ String[] c = args[0].split( "," );
+ name = c[0].trim();
+ type = c[1].trim();
+ } else {
+ throw new IllegalArgumentException( "Cannot arguments " + Arrays.asList( args ) );
+ }
+ ObjectTypeNode otn;
+ try {
+ EntryPointNode epn = new EntryPointNode( buildContext.getNextId(),
+ buildContext.getRuleBase().getRete(),
+ buildContext );
+ epn.attach();
+
+ otn = new ObjectTypeNode( buildContext.getNextId(),
+ epn,
+ new ClassObjectType( Class.forName( type ) ),
+ buildContext );
+ // we don't attach, as we want to manually propagate and not
+ // have the working memory propagate
+ //otn.attach();
+ } catch ( ClassNotFoundException e ) {
+ throw new IllegalArgumentException( "Cannot create OTN " + Arrays.asList( args,
+ e ) );
+ }
+ context.put( name,
+ otn );
+ }
+
+ }
+
+ public static class LeftInputAdapterNodeStep
+ implements
+ Step {
+
+ private ReteTesterHelper reteTesterHelper;
+
+ public LeftInputAdapterNodeStep(ReteTesterHelper reteTesterHelper) {
+ this.reteTesterHelper = reteTesterHelper;
+ }
+
+ public void execute(Map context,
+ String[] args) {
+ BuildContext buildContext = (BuildContext) context.get( "BuildContext" );
+ String name;
+ String source;
+
+ if ( args.length == 1 ) {
+ String[] c = args[0].split( "," );
+ name = c[0].trim();
+ source = c[1].trim();
+ } else {
+ throw new IllegalArgumentException( "Cannot arguments " + Arrays.asList( args ) );
+ }
+ ObjectTypeNode otn = (ObjectTypeNode) context.get( source );
+
+ LeftInputAdapterNode liaNode = new LeftInputAdapterNode( buildContext.getNextId(),
+ otn,
+ buildContext );
+ liaNode.attach();
+ context.put( name,
+ liaNode );
+ }
+ }
+
+ public static class BindingStep
+ implements
+ Step {
+
+ private ReteTesterHelper reteTesterHelper;
+
+ public BindingStep(ReteTesterHelper reteTesterHelper) {
+ this.reteTesterHelper = reteTesterHelper;
+ }
+
+ public void execute(Map context,
+ String[] args) {
+ BuildContext buildContext = (BuildContext) context.get( "BuildContext" );
+ String name;
+ String index;
+ String type;
+ String field;
+
+ if ( args.length != 0 ) {
+ String[] c = args[0].split( "," );
+ if ( c.length == 3 ) {
+ // TODO
+ throw new IllegalArgumentException( "Cannot create Binding " + Arrays.asList( args ) );
+ } else {
+ name = c[0].trim();
+ index = c[1].trim();
+ type = c[2].trim();
+ field = c[3].trim();
+
+ try {
+ Pattern pattern = new Pattern( Integer.parseInt( index ),
+ new ClassObjectType( Class.forName( type ) ) );
+
+ final Class clazz = ((ClassObjectType) pattern.getObjectType()).getClassType();
+ ClassFieldAccessorStore store = (ClassFieldAccessorStore) context.get( "ClassFieldAccessorStore" );
+
+ final InternalReadAccessor extractor = store.getReader( clazz,
+ field,
+ getClass().getClassLoader() );
+
+ Declaration declr = new Declaration( name,
+ extractor,
+ pattern );
+ context.put( name,
+ declr );
+ } catch ( Exception e ) {
+ throw new IllegalArgumentException( "Cannot create Binding " + Arrays.asList( args,
+ e ) );
+ }
+ }
+
+ } else {
+ throw new IllegalArgumentException( "Cannot arguments " + Arrays.asList( args ) );
+ }
+ }
+ }
+
+ public static class JoinNodeStep
+ implements
+ Step {
+
+ private ReteTesterHelper reteTesterHelper;
+
+ public JoinNodeStep(ReteTesterHelper reteTesterHelper) {
+ this.reteTesterHelper = reteTesterHelper;
+ }
+
+ public void execute(Map context,
+ String[] args) {
+ BuildContext buildContext = (BuildContext) context.get( "BuildContext" );
+
+ if ( args.length != 0 ) {
+ String[] a = args[0].split( "," );
+ String name = a[0].trim();
+ String leftInput = a[1].trim();
+ String rightInput = a[2].trim();
+
+ LeftTupleSource leftTupleSource;
+ if ( "mock".equals( leftInput ) ) {
+ leftTupleSource = new MockTupleSource( buildContext.getNextId() );
+ } else {
+ leftTupleSource = (LeftTupleSource) context.get( leftInput );
+ }
+
+ ObjectSource rightObjectSource;
+ if ( "mock".equals( rightInput ) ) {
+ rightObjectSource = new MockObjectSource( buildContext.getNextId() );
+ } else {
+ rightObjectSource = (ObjectSource) context.get( rightInput );
+ }
+
+ a = args[1].split( "," );
+ String fieldName = a[0].trim();
+ String operator = a[1].trim();
+ String var = a[2].trim();
+
+ Declaration declr = (Declaration) context.get( var );
+
+ // Pattern pattern = new Pattern(Integer.parseInt( index )) ;
+ // ObjectType objectType = new ClassObjectType( )
+ //
+
+ BetaNodeFieldConstraint betaConstraint;
+ try {
+ betaConstraint = this.reteTesterHelper.getBoundVariableConstraint( declr.getPattern(),
+ fieldName,
+ declr,
+ operator );
+ } catch ( IntrospectionException e ) {
+ throw new IllegalArgumentException();
+ }
+
+ SingleBetaConstraints constraints = new SingleBetaConstraints( betaConstraint,
+ buildContext.getRuleBase().getConfiguration() );
+
+ JoinNode joinNode = new JoinNode( buildContext.getNextId(),
+ leftTupleSource,
+ rightObjectSource,
+ constraints,
+ BehaviorManager.NO_BEHAVIORS,
+ buildContext );
+ joinNode.attach();
+ context.put( name,
+ joinNode );
+
+ } else {
+ throw new IllegalArgumentException( "Cannot arguments " + args );
+
+ }
+ }
+ }
+
+ public static class FactsStep
+ implements
+ Step {
+
+ private ReteTesterHelper reteTesterHelper;
+
+ public FactsStep(ReteTesterHelper reteTesterHelper) {
+ this.reteTesterHelper = reteTesterHelper;
+ }
+
+ public void execute(Map context,
+ String[] args) {
+ BuildContext buildContext = (BuildContext) context.get( "BuildContext" );
+
+ if ( args.length >= 1 ) {
+
+ WorkingMemory wm = (WorkingMemory) context.get( "WorkingMemory" );
+ List handles = (List) context.get( "Handles" );
+ if ( handles == null ) {
+ handles = new ArrayList();
+ context.put( "Handles",
+ handles );
+ }
+
+ for ( String arg : args ) {
+ String[] elms = arg.split( "," );
+ for ( String elm : elms ) {
+ FactHandle handle = wm.insert( MVEL.eval( elm ) );
+ handles.add( handle );
+ }
+ }
+
+ } else {
+ throw new IllegalArgumentException( "Cannot arguments " + Arrays.asList( args ) );
+ }
+ }
+ }
+
+ public static class ReteTesterHelper {
+
+ private Package pkg;
+ private ClassFieldAccessorStore store;
+ private EvaluatorRegistry registry = new EvaluatorRegistry();
+
+ public ReteTesterHelper() {
+ this.pkg = new Package( "org.drools.examples.manners" );
+ this.pkg.setClassFieldAccessorCache( new ClassFieldAccessorCache( Thread.currentThread().getContextClassLoader() ) );
+ this.store = this.pkg.getClassFieldAccessorStore();
+ this.store.setEagerWire( true );
+ }
+
+ public Package getPkg() {
+ return pkg;
+ }
+
+ public ClassFieldAccessorStore getStore() {
+ return store;
+ }
+
+ public EvaluatorRegistry getRegistry() {
+ return registry;
+ }
+
+ public BetaNodeFieldConstraint getBoundVariableConstraint(final Pattern pattern,
+ final String fieldName,
+ final Declaration declaration,
+ final String evaluatorString) throws IntrospectionException {
+ final Class clazz = ((ClassObjectType) pattern.getObjectType()).getClassType();
+
+ final InternalReadAccessor extractor = store.getReader( clazz,
+ fieldName,
+ getClass().getClassLoader() );
+
+ Evaluator evaluator = getEvaluator( clazz,
+ evaluatorString );
+
+ return new VariableConstraint( extractor,
+ declaration,
+ evaluator );
+ }
+
+ public Evaluator getEvaluator(Class cls,
+ String operator) {
+ return registry.getEvaluator( ValueType.determineValueType( cls ),
+ Operator.determineOperator( operator,
+ false ) );
+ }
+ }
+
+}
\ No newline at end of file
Added: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTesterTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTesterTest.java (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/test/ReteTesterTest.java 2009-11-15 07:11:38 UTC (rev 30150)
@@ -0,0 +1,500 @@
+package org.drools.reteoo.test;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.drools.FactHandle;
+import org.drools.RuleBaseFactory;
+import org.drools.WorkingMemory;
+import org.drools.base.ClassObjectType;
+import org.drools.common.DefaultFactHandle;
+import org.drools.common.InternalFactHandle;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.common.PropagationContextImpl;
+import org.drools.reteoo.BetaMemory;
+import org.drools.reteoo.BetaNode;
+import org.drools.reteoo.JoinNode;
+import org.drools.reteoo.LeftInputAdapterNode;
+import org.drools.reteoo.LeftTuple;
+import org.drools.reteoo.MockLeftTupleSink;
+import org.drools.reteoo.MockObjectSource;
+import org.drools.reteoo.MockTupleSource;
+import org.drools.reteoo.ObjectTypeNode;
+import org.drools.reteoo.ReteooRuleBase;
+import org.drools.reteoo.ReteooWorkingMemory;
+import org.drools.reteoo.test.ReteTester.DslStep;
+import org.drools.rule.Declaration;
+import org.drools.spi.PropagationContext;
+
+import junit.framework.TestCase;
+
+public class ReteTesterTest extends TestCase {
+ public void testIndentPos() {
+ ReteTester tester = new ReteTester();
+ assertEquals( 5,
+ tester.indentPos( " asdfasdf" ) );
+ }
+
+ public void testReaderAsString() {
+ String str = " line1\n";
+ str += " line2\n";
+
+ List<String> lines = ReteTester.chunkReader( new StringReader( str ) );
+ assertEquals( 2,
+ lines.size() );
+
+ assertEquals( " line1",
+ lines.get( 0 ) );
+ assertEquals( " line2",
+ lines.get( 1 ) );
+ }
+
+ public void testReaderAsStringRemoveLineQuotes() {
+ String str = " line1\n";
+ str += "X// some comments\n";
+ str += " line2\n";
+ str += " line3 //some other comments\n";
+
+ List<String> lines = ReteTester.chunkReader( new StringReader( str ) );
+ assertEquals( 4,
+ lines.size() );
+
+ assertEquals( " line1",
+ lines.get( 0 ) );
+ assertEquals( "X ",
+ lines.get( 1 ) );
+ assertEquals( " line2",
+ lines.get( 2 ) );
+ assertEquals( " line3 ",
+ lines.get( 3 ) );
+ }
+
+ public void testReaderAsStringRemoveBlockQuotes1() {
+ String str = " line1\n";
+ str += " /* some comments*/\n";
+ str += " line2\n";
+ str += " line3 //some other comments\n";
+
+ List<String> lines = ReteTester.chunkReader( new StringReader( str ) );
+ assertEquals( 4,
+ lines.size() );
+
+ assertEquals( " line1",
+ lines.get( 0 ) );
+ assertEquals( " ",
+ lines.get( 1 ) );
+ assertEquals( " line2",
+ lines.get( 2 ) );
+ assertEquals( " line3 ",
+ lines.get( 3 ) );
+ }
+
+ public void testReaderAsStringRemoveBlockQuotes2() {
+ String str = " line1\n";
+ str += " /* some comments\n";
+ str += " line2 // nested line comment\n";
+ str += " lin*/e3\n";
+ str += " line4 //some other comments\n";
+
+ List<String> lines = ReteTester.chunkReader( new StringReader( str ) );
+ assertEquals( 5,
+ lines.size() );
+
+ assertEquals( " line1",
+ lines.get( 0 ) );
+ assertEquals( " ",
+ lines.get( 1 ) );
+ assertEquals( " ",
+ lines.get( 2 ) );
+ assertEquals( " e3",
+ lines.get( 3 ) );
+ assertEquals( " line4 ",
+ lines.get( 4 ) );
+ }
+
+ public void testDslCommandBuilder() {
+ InputStream stream = getClass().getResourceAsStream( "JoinNode.data" );
+ assertNotNull( stream );
+ DslStep[] step = (DslStep[]) ReteTester.buildDslCommands( new InputStreamReader( stream ) ).toArray( new DslStep[0] );
+ // assertEquals( 10, cmds.length );
+
+ // assertEquals( 1, step[0].getLine() );
+ // assertEquals( "LeftInputAdapter", step[0].getName() );
+ // assertEquals( "node0", step[0].getCommands().get( 0 ) );
+ //
+ // assertEquals( 3, step[1].getLine() );
+ // assertEquals( "JoinNode", step[1].getName() );
+ // assertEquals( "node0, node1, ==", step[1].getCommands().get( 0 ) );
+ //
+ // assertEquals( 5, step[2].getLine() );
+ // assertEquals( "JoinNode", step[2].getName() );
+ // assertEquals( "node1, node2, ==", step[2].getCommands().get( 0 ) );
+ //
+ // assertEquals( 7, step[3].getLine() );
+ // assertEquals( "Facts", step[3].getName() );
+ // assertEquals( "0, 0, 0, 0", step[3].getCommands().get( 0 ) );
+ //
+ // assertEquals( 9, step[4].getLine() );
+ // assertEquals( "node1", step[4].getName() );
+ // assertEquals( "assertObject, h0", step[4].getCommands().get( 0 ) );
+ // assertEquals( "assertLeftTuple, h1, h2", step[4].getCommands().get( 1 ) );
+ // assertEquals( "assertObject, h3, h4", step[4].getCommands().get( 2 ) );
+ // assertEquals( "leftMemory, 2,[ [h1], [h2] ]", step[4].getCommands().get( 3 ) );
+ // assertEquals( "rightMemory, 3, [ [h0], [h3], [h4] ]", step[4].getCommands().get( 4 ) );
+ //
+ // assertEquals( 15, step[5].getLine() );
+ // assertEquals( "node2", step[5].getName() );
+ // assertEquals( "leftMemory, 6, [ [h0, h1], [h0, h2],[h3, h1], [h3, h2],[h4, h1], [h4, h2] ]", step[5].getCommands().get( 0 ) );
+ // assertEquals( "rightMemory, 0, []", step[5].getCommands().get( 1 ) );
+ //
+ // assertEquals( 20, step[6].getLine() );
+ // assertEquals( "node1", step[6].getName() );
+ // assertEquals( "retractRightTuple, h0", step[6].getCommands().get( 0 ) );
+ // assertEquals( "leftMemory, 2, [ [h1], [h2] ]", step[6].getCommands().get( 1 ) );
+ // assertEquals( "rightMemory, 2, [ [h3], [h4] ]", step[6].getCommands().get( 2 ) );
+ //
+ // assertEquals( 24, step[7].getLine() );
+ // assertEquals( "node2", step[7].getName() );
+ // assertEquals( "leftMemory, 4, [ [h3, h1], [h3, h2], [h4, h1], [h4, h2] ]", step[7].getCommands().get( 0 ) );
+ //
+ // assertEquals( 26, step[8].getLine() );
+ // assertEquals( "node1", step[8].getName() );
+ // assertEquals( "retractLeftTuple, h2", step[8].getCommands().get( 0 ) );
+ // assertEquals( "leftMemory, 1, [ [h1] ]", step[8].getCommands().get( 1 ) );
+ // assertEquals( "rightMemory, 2, [ [h3], [h4] ]", step[8].getCommands().get( 2 ) );
+ //
+ // assertEquals( 30, step[9].getLine() );
+ // assertEquals( "node2", step[9].getName() );
+ // assertEquals( "leftMemory, 4, [ [h3, h1], [h4, h1] ]", step[9].getCommands().get( 0 ) );
+ }
+
+ public void testObjectTypeNodeStep() {
+ String str = "ObjectTypeNode\n";
+ str += " otn1, java.lang.Integer";
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+ ObjectTypeNode otn1 = (ObjectTypeNode) map.get( "otn1" );
+ assertNotNull( otn1 );
+
+ assertEquals( new ClassObjectType( Integer.class ),
+ otn1.getObjectType() );
+ }
+
+ public void testLeftInputAdapterNodeStep() {
+ String str = "ObjectTypeNode\n";
+ str += " otn1, java.lang.Integer\n";
+ str += "LeftInputAdapterNode\n";
+ str += " lian0, otn1";
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+ ObjectTypeNode otn1 = (ObjectTypeNode) map.get( "otn1" );
+
+ LeftInputAdapterNode lian0 = (LeftInputAdapterNode) map.get( "lian0" );
+ assertNotNull( lian0 );
+
+ assertSame( lian0,
+ otn1.getSinkPropagator().getSinks()[0] );
+ }
+
+ public void testBindingStep() {
+ String str = "Binding\n";
+ str += " p1, 0, java.lang.Integer, intValue\n";
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+ //print(steps);
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+ Declaration p1 = (Declaration) map.get( "p1" );
+ assertNotNull( p1 );
+ }
+
+ public void testJoinNodeStep() {
+ String str = "ObjectTypeNode\n";
+ str += " otn1, java.lang.Integer\n";
+ str += "LeftInputAdapterNode\n";
+ str += " lian0, otn1\n";
+ str += "ObjectTypeNode\n";
+ str += " otn2, java.lang.Integer\n";
+ str += "Binding\n";
+ str += " p1, 0, java.lang.Integer, intValue\n";
+ str += "JoinNode\n";
+ str += " join1, lian0, otn2\n";
+ str += " intValue, ==, p1\n";
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+
+ JoinNode join1 = (JoinNode) map.get( "join1" );
+ assertNotNull( join1 );
+
+ PropagationContext context = new PropagationContextImpl( 0,
+ PropagationContext.ASSERTION,
+ null,
+ null,
+ null );
+ ReteooWorkingMemory workingMemory = new ReteooWorkingMemory( 1,
+ (ReteooRuleBase) RuleBaseFactory.newRuleBase() );
+
+ BetaMemory memory = (BetaMemory) workingMemory.getNodeMemory( join1 );
+
+ final DefaultFactHandle f0 = new DefaultFactHandle( 0,
+ 0 );
+ final LeftTuple tuple0 = new LeftTuple( f0,
+ join1,
+ true );
+
+ // assert tuple, should add one to left memory
+ join1.assertLeftTuple( tuple0,
+ context,
+ workingMemory );
+ // check memories, left memory is populated, right memory is emptys
+ assertEquals( 1,
+ memory.getLeftTupleMemory().size() );
+ assertEquals( 0,
+ memory.getRightTupleMemory().size() );
+
+ // assert tuple, should add left memory should be 2
+ final DefaultFactHandle f1 = new DefaultFactHandle( 1,
+ 0);
+ final LeftTuple tuple1 = new LeftTuple( f1,
+ join1,
+ true );
+ join1.assertLeftTuple( tuple1,
+ context,
+ workingMemory );
+ assertEquals( 2,
+ memory.getLeftTupleMemory().size() );
+
+ LeftTuple leftTuple = memory.getLeftTupleMemory().getFirst( null );
+ assertEquals( tuple0,
+ leftTuple );
+ assertEquals( tuple1,
+ leftTuple.getNext() );
+ }
+
+ public void testFactsStep() {
+ String str = "Facts\n";
+ str += " 1, 2, 'hello'\n";
+ str += " 'good bye', new java.util.ArrayList()\n";
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+
+ WorkingMemory wm = (WorkingMemory) map.get( "WorkingMemory" );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) map.get( "Handles" );
+
+ assertNotNull( wm );
+ assertNotNull( handles );
+
+ assertEquals( 5, handles.size() );
+
+ assertEquals( 1, handles.get( 0 ).getObject() );
+ assertEquals( 2, handles.get( 1 ).getObject() );
+ assertEquals( "hello", handles.get( 2 ).getObject() );
+ assertEquals( "good bye", handles.get( 3 ).getObject() );
+ assertEquals( new ArrayList<FactHandle>(), handles.get( 4 ).getObject() );
+ }
+
+ public void testBetaNodeAssertOperations() {
+ String str = "ObjectTypeNode\n";
+ str += " otn1, java.lang.Integer\n";
+ str += "LeftInputAdapterNode\n";
+ str += " lian0, otn1\n";
+ str += "ObjectTypeNode\n";
+ str += " otn2, java.lang.Integer\n";
+ str += "Binding\n";
+ str += " p1, 0, java.lang.Integer, intValue\n";
+ str += "JoinNode\n";
+ str += " join1, lian0, otn2\n";
+ str += " intValue, !=, p1\n";
+ str += "Facts\n";
+ str += " 0, 1, 2, 3\n";
+ str += "assert\n";
+ str += " otn2 [h0, h2]\n";
+ str += " otn1 [h1, h3]\n";
+
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+
+ InternalWorkingMemory wm = (InternalWorkingMemory) map.get( "WorkingMemory" );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) map.get( "Handles" );
+
+ JoinNode join1 = (JoinNode) map.get( "join1" );
+
+ BetaMemory memory = (BetaMemory) wm.getNodeMemory( join1 );
+ assertEquals( 2,
+ memory.getRightTupleMemory().size() );
+
+ assertEquals( 2,
+ memory.getLeftTupleMemory().size() );
+ }
+
+ public void testBetaNodeRetractOperations() {
+ String str = "ObjectTypeNode\n";
+ str += " otn1, java.lang.Integer\n";
+ str += "LeftInputAdapterNode\n";
+ str += " lian0, otn1\n";
+ str += "ObjectTypeNode\n";
+ str += " otn2, java.lang.Integer\n";
+ str += "Binding\n";
+ str += " p1, 0, java.lang.Integer, intValue\n";
+ str += "JoinNode\n";
+ str += " join1, lian0, otn2\n";
+ str += " intValue, !=, p1\n";
+ str += "Facts\n";
+ str += " 0, 1, 2, 3\n";
+ str += "assert\n";
+ str += " otn1 [h1, h3]\n";
+ str += " otn2 [h0, h2]\n";
+ str += "retract\n";
+ str += " otn1 [h1]\n";
+ str += " otn2 [h2]\n";
+
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+
+ InternalWorkingMemory wm = (InternalWorkingMemory) map.get( "WorkingMemory" );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) map.get( "Handles" );
+
+ JoinNode join1 = (JoinNode) map.get( "join1" );
+
+ BetaMemory memory = (BetaMemory) wm.getNodeMemory( join1 );
+ assertEquals( 1,
+ memory.getRightTupleMemory().size() );
+
+ assertEquals( 1,
+ memory.getLeftTupleMemory().size() );
+ }
+
+ public void testBetaNodeSimpleMemoryChecks() {
+ String str = "ObjectTypeNode\n";
+ str += " otn1, java.lang.Integer\n";
+ str += "LeftInputAdapterNode\n";
+ str += " lian0, otn1\n";
+ str += "ObjectTypeNode\n";
+ str += " otn2, java.lang.Integer\n";
+ str += "Binding\n";
+ str += " p1, 0, java.lang.Integer, intValue\n";
+ str += "JoinNode\n";
+ str += " join1, lian0, otn2\n";
+ str += " intValue, !=, p1\n";
+ str += "Facts\n";
+ str += " 0, 1, 2, 3\n";
+ str += "assert\n";
+ str += " otn1 [h1, h3]\n";
+ str += " otn2 [h0, h2]\n";
+ str += "join1\n";
+ str += " leftMemory [[h1], [h3]]\n";
+ str += " rightMemory [h0, h2]\n";
+ str += "retract\n";
+ str += " otn1 [h1]\n";
+ str += " otn2 [h2]\n";;
+ str += "join1\n";
+ str += " leftMemory [ [h3] ]\n";
+ str += " rightMemory [h0]\n";
+
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+
+ InternalWorkingMemory wm = (InternalWorkingMemory) map.get( "WorkingMemory" );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) map.get( "Handles" );
+
+ JoinNode join1 = (JoinNode) map.get( "join1" );
+
+ BetaMemory memory = (BetaMemory) wm.getNodeMemory( join1 );
+ assertEquals( 1,
+ memory.getRightTupleMemory().size() );
+
+ assertEquals( 1,
+ memory.getLeftTupleMemory().size() );
+ }
+
+ public void testBetaNodeChainedMemoryChecks() {
+ String str = "ObjectTypeNode\n";
+ str += " otn1, java.lang.Integer\n";
+ str += "LeftInputAdapterNode\n";
+ str += " lian0, otn1\n";
+ str += "ObjectTypeNode\n";
+ str += " otn2, java.lang.Integer\n";
+ str += "ObjectTypeNode\n";
+ str += " otn3, java.lang.Integer\n";
+ str += "Binding\n";
+ str += " p1, 0, java.lang.Integer, intValue\n";
+ str += "JoinNode\n";
+ str += " join1, lian0, otn2\n";
+ str += " intValue, !=, p1\n";
+ str += "JoinNode\n";
+ str += " join2, join1, otn3\n";
+ str += " intValue, !=, p1\n";
+ str += "Facts\n";
+ str += " 0, 1, 2, 3, 4\n";
+ str += "assert\n";
+ str += " otn1 [h1, h3]\n";
+ str += " otn2 [h0, h2]\n";
+ str += " otn3 [h4]\n";
+ str += "join1\n";
+ str += " leftMemory [[h1], [h3]]\n";
+ str += " rightMemory [h0, h2]\n";
+ str += "join2\n";
+ str += " leftMemory [[h1, h0], [h3, h0],\n";
+ str += " [h1, h2], [h3, h2]]\n";
+ str += " rightMemory [h4]\n";
+ str += "retract\n";
+ str += " otn1 [h1]\n";
+ str += " otn2 [h2]\n";;
+ str += "join1\n";
+ str += " leftMemory [ [h3] ]\n";
+ str += " rightMemory [h0]\n";
+ str += "join2\n";
+ str += " leftMemory [[h3, h0]]\n";
+ str += " rightMemory [h4]\n";
+
+
+ List<DslStep> steps = ReteTester.buildDslCommands( new StringReader( str ) );
+
+ ReteTester tester = new ReteTester();
+ Map<String, Object> map = tester.run( steps );
+
+ InternalWorkingMemory wm = (InternalWorkingMemory) map.get( "WorkingMemory" );
+ List<InternalFactHandle> handles = (List<InternalFactHandle>) map.get( "Handles" );
+
+ JoinNode join1 = (JoinNode) map.get( "join1" );
+
+ BetaMemory memory = (BetaMemory) wm.getNodeMemory( join1 );
+ assertEquals( 1,
+ memory.getRightTupleMemory().size() );
+
+ assertEquals( 1,
+ memory.getLeftTupleMemory().size() );
+ }
+
+ private void print(DslStep[] steps) {
+ for ( DslStep command : steps ) {
+ System.out.println( command );
+ }
+ }
+}
Added: labs/jbossrules/trunk/drools-core/src/test/resources/org/drools/reteoo/test/JoinNode.data
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/resources/org/drools/reteoo/test/JoinNode.data (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/test/resources/org/drools/reteoo/test/JoinNode.data 2009-11-15 07:11:38 UTC (rev 30150)
@@ -0,0 +1,38 @@
+ObjectTypeNode
+ otn1, java.lang.Integer
+LeftInputAdapterNode
+ lian0, otn1
+ObjectTypeNode
+ otn2, java.lang.Integer
+ObjectTypeNode
+ otn3, java.lang.Integer
+Binding
+ p1, 0, java.lang.Integer, intValue
+JoinNode
+ join1, lian0, otn2
+ intValue, !=, p1
+JoinNode
+ join2, join1, otn3
+ intValue, !=, p1
+Facts
+ 0, 1, 2, 3, 4
+assert
+ otn1 [h1, h3]
+ otn2 [h0, h2]
+ otn3 [h4]
+join1
+ leftMemory [[h1], [h3]]
+ rightMemory [h0, h2]
+join2
+ leftMemory [[h1, h0], [h3, h0],
+ [h1, h2], [h3, h2]]
+ rightMemory [h4]
+retract
+ otn1 [h1]
+ otn2 [h2];
+join1
+ leftMemory [ [h3] ]
+ rightMemory [h0]
+join2
+ leftMemory [[h3, h0]]
+ rightMemory [h4]
\ No newline at end of file
More information about the jboss-svn-commits
mailing list