0001: package org.drools.reteoo;
0002:
0003: /*
0004: * Copyright 2005 JBoss Inc
0005: *
0006: * Licensed under the Apache License, Version 2.0 (the "License");
0007: * you may not use this file except in compliance with the License.
0008: * You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing, software
0013: * distributed under the License is distributed on an "AS IS" BASIS,
0014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015: * See the License for the specific language governing permissions and
0016: * limitations under the License.
0017: */
0018:
0019: import java.util.ArrayList;
0020: import java.util.HashMap;
0021: import java.util.List;
0022: import java.util.Map;
0023:
0024: import org.drools.Agenda;
0025: import org.drools.DroolsTestCase;
0026: import org.drools.RuleBase;
0027: import org.drools.RuleBaseConfiguration;
0028: import org.drools.RuleBaseFactory;
0029: import org.drools.WorkingMemory;
0030: import org.drools.base.SalienceInteger;
0031: import org.drools.common.ArrayAgendaGroup;
0032: import org.drools.common.BinaryHeapQueueAgendaGroup;
0033: import org.drools.common.DefaultFactHandle;
0034: import org.drools.common.InternalAgenda;
0035: import org.drools.common.InternalAgendaGroup;
0036: import org.drools.common.InternalRuleBase;
0037: import org.drools.common.InternalWorkingMemory;
0038: import org.drools.common.PropagationContextImpl;
0039: import org.drools.common.RuleFlowGroupImpl;
0040: import org.drools.conflict.DepthConflictResolver;
0041: import org.drools.reteoo.ReteooBuilder.IdGenerator;
0042: import org.drools.rule.Rule;
0043: import org.drools.spi.Activation;
0044: import org.drools.spi.ActivationGroup;
0045: import org.drools.spi.AgendaFilter;
0046: import org.drools.spi.AgendaGroup;
0047: import org.drools.spi.Consequence;
0048: import org.drools.spi.ConsequenceException;
0049: import org.drools.spi.KnowledgeHelper;
0050: import org.drools.spi.PropagationContext;
0051: import org.drools.spi.RuleFlowGroup;
0052:
0053: /**
0054: * @author mproctor
0055: */
0056:
0057: public class AgendaTest extends DroolsTestCase {
0058: public void testClearAgenda() {
0059: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
0060:
0061: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0062: .newStatefulSession();
0063:
0064: final Agenda agenda = workingMemory.getAgenda();
0065:
0066: final Rule rule1 = new Rule("test-rule1");
0067: final Rule rule2 = new Rule("test-rule2");
0068:
0069: final RuleTerminalNode node1 = new RuleTerminalNode(3,
0070: new MockTupleSource(2), rule1, rule1.getLhs());
0071:
0072: final RuleTerminalNode node2 = new RuleTerminalNode(5,
0073: new MockTupleSource(4), rule2, rule2.getLhs());
0074:
0075: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
0076: "cheese"));
0077:
0078: final PropagationContext context1 = new PropagationContextImpl(
0079: 0, PropagationContext.ASSERTION, rule1, null);
0080:
0081: // Add consequence. Notice here the context here for the add to ageyunda
0082: // is itself
0083: rule1.setConsequence(new org.drools.spi.Consequence() {
0084: /**
0085: *
0086: */
0087: private static final long serialVersionUID = 400L;
0088:
0089: public void evaluate(final KnowledgeHelper knowledgeHelper,
0090: final WorkingMemory workingMemory) {
0091: // do nothing
0092: }
0093: });
0094:
0095: // Add consequence. Notice here the context here for the add to ageyunda
0096: // is itself
0097: rule2.setConsequence(new org.drools.spi.Consequence() {
0098: /**
0099: *
0100: */
0101: private static final long serialVersionUID = 400L;
0102:
0103: public void evaluate(final KnowledgeHelper knowledgeHelper,
0104: final WorkingMemory workingMemory) {
0105: // do nothing
0106: }
0107: });
0108:
0109: assertEquals(0, agenda.getFocus().size());
0110:
0111: rule1.setNoLoop(false);
0112: rule2.setDuration(5000);
0113:
0114: node1.assertTuple(tuple, context1, workingMemory);
0115:
0116: node2.assertTuple(tuple, context1, workingMemory);
0117:
0118: // make sure we have an activation in the current focus
0119: assertEquals(1, agenda.getFocus().size());
0120:
0121: assertEquals(1, agenda.getScheduledActivations().length);
0122:
0123: agenda.clearAgenda();
0124:
0125: assertEquals(0, agenda.getFocus().size());
0126:
0127: assertEquals(0, agenda.getScheduledActivations().length);
0128: }
0129:
0130: public void testFilters() throws Exception {
0131: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
0132:
0133: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0134: .newStatefulSession();
0135: final InternalAgenda agenda = (InternalAgenda) workingMemory
0136: .getAgenda();
0137:
0138: final Rule rule = new Rule("test-rule");
0139: final RuleTerminalNode node = new RuleTerminalNode(3,
0140: new MockTupleSource(2), rule, rule.getLhs());
0141:
0142: final Map results = new HashMap();
0143: // add consequence
0144: rule.setConsequence(new org.drools.spi.Consequence() {
0145: /**
0146: *
0147: */
0148: private static final long serialVersionUID = 400L;
0149:
0150: public void evaluate(final KnowledgeHelper knowledgeHelper,
0151: final WorkingMemory workingMemory) {
0152: results.put("fired", new Boolean(true));
0153: }
0154: });
0155:
0156: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
0157: "cheese"));
0158: final PropagationContext context = new PropagationContextImpl(
0159: 0, PropagationContext.ASSERTION, rule, null);
0160:
0161: // test agenda is empty
0162: assertEquals(0, agenda.getFocus().size());
0163:
0164: // True filter, activations should always add
0165: final AgendaFilter filterTrue = new AgendaFilter() {
0166: public boolean accept(Activation item) {
0167: return true;
0168: }
0169: };
0170:
0171: rule.setNoLoop(false);
0172: node.assertTuple(tuple, context, workingMemory);
0173:
0174: // check there is an item to fire
0175: assertEquals(1, agenda.getFocus().size());
0176: agenda.fireNextItem(filterTrue);
0177:
0178: // check focus is empty
0179: assertEquals(0, agenda.getFocus().size());
0180:
0181: // make sure it also fired
0182: assertEquals(new Boolean(true), results.get("fired"));
0183:
0184: // clear the agenda and the result map
0185: agenda.clearAgenda();
0186: results.clear();
0187:
0188: // False filter, activations should always be denied
0189: final AgendaFilter filterFalse = new AgendaFilter() {
0190: public boolean accept(Activation item) {
0191: return false;
0192: }
0193: };
0194:
0195: rule.setNoLoop(false);
0196: node.assertTuple(tuple, context, workingMemory);
0197:
0198: // check we have an item to fire
0199: assertEquals(1, agenda.getFocus().size());
0200: agenda.fireNextItem(filterFalse);
0201:
0202: // make sure the focus is empty
0203: assertEquals(0, agenda.getFocus().size());
0204:
0205: // check the consequence never fired
0206: assertNull(results.get("fired"));
0207: }
0208:
0209: public void testFocusStack() throws ConsequenceException {
0210: final InternalRuleBase ruleBase = (InternalRuleBase) RuleBaseFactory
0211: .newRuleBase();
0212:
0213: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0214: .newStatefulSession();
0215:
0216: // create the consequence
0217: final Consequence consequence = new Consequence() {
0218: private static final long serialVersionUID = 400L;
0219:
0220: public void evaluate(KnowledgeHelper knowledgeHelper,
0221: WorkingMemory workingMemory) {
0222: // do nothing
0223: }
0224: };
0225:
0226: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
0227: "cheese"));
0228:
0229: // create a rule for each agendaGroup
0230: final Rule rule0 = new Rule("test-rule0");
0231: final RuleTerminalNode node0 = new RuleTerminalNode(3,
0232: new MockTupleSource(2), rule0, rule0.getLhs());
0233: rule0.setConsequence(consequence);
0234: final PropagationContext context0 = new PropagationContextImpl(
0235: 0, PropagationContext.ASSERTION, rule0, null);
0236:
0237: final Rule rule1 = new Rule("test-rule1", "agendaGroup1");
0238: final RuleTerminalNode node1 = new RuleTerminalNode(5,
0239: new MockTupleSource(4), rule1, rule1.getLhs());
0240: rule1.setConsequence(consequence);
0241: final PropagationContext context1 = new PropagationContextImpl(
0242: 0, PropagationContext.ASSERTION, rule1, null);
0243:
0244: final Rule rule2 = new Rule("test-rule2", "agendaGroup2");
0245: final RuleTerminalNode node2 = new RuleTerminalNode(7,
0246: new MockTupleSource(6), rule2, rule2.getLhs());
0247: rule2.setConsequence(consequence);
0248: final PropagationContext context2 = new PropagationContextImpl(
0249: 0, PropagationContext.ASSERTION, rule2, null);
0250:
0251: final Rule rule3 = new Rule("test-rule3", "agendaGroup3");
0252: final RuleTerminalNode node3 = new RuleTerminalNode(9,
0253: new MockTupleSource(8), rule3, rule3.getLhs());
0254: rule3.setConsequence(consequence);
0255: final PropagationContext context3 = new PropagationContextImpl(
0256: 0, PropagationContext.ASSERTION, rule3, null);
0257:
0258: final InternalAgenda agenda = (InternalAgenda) workingMemory
0259: .getAgenda();
0260:
0261: // create the AgendaGroups
0262: final AgendaGroup agendaGroup1 = new BinaryHeapQueueAgendaGroup(
0263: "agendaGroup1", ruleBase);
0264: agenda.addAgendaGroup(agendaGroup1);
0265:
0266: final AgendaGroup agendaGroup2 = new BinaryHeapQueueAgendaGroup(
0267: "agendaGroup2", ruleBase);
0268: agenda.addAgendaGroup(agendaGroup2);
0269:
0270: final AgendaGroup agendaGroup3 = new BinaryHeapQueueAgendaGroup(
0271: "agendaGroup3", ruleBase);
0272: agenda.addAgendaGroup(agendaGroup3);
0273:
0274: // focus at this point is MAIN
0275: assertEquals(0, agenda.focusStackSize());
0276:
0277: node0.assertTuple(tuple, context0, workingMemory);
0278:
0279: // check focus is main
0280: final AgendaGroup main = agenda
0281: .getAgendaGroup(AgendaGroup.MAIN);
0282: assertEquals(agenda.getFocus(), main);
0283: // check main got the tuple
0284: assertEquals(1, agenda.getFocus().size());
0285: node2.assertTuple(tuple, context2, workingMemory);
0286:
0287: // main is still focus and this tuple went to agendaGroup 2
0288: assertEquals(1, agenda.getFocus().size());
0289:
0290: // check agendaGroup2 still got the tuple
0291: assertEquals(1, agendaGroup2.size());
0292:
0293: // make sure total agenda size reflects this
0294: assertEquals(2, agenda.agendaSize());
0295:
0296: // put another one on agendaGroup 2
0297: node2.assertTuple(tuple, context2, workingMemory);
0298:
0299: // main is still focus so shouldn't have increased
0300: assertEquals(1, agenda.getFocus().size());
0301:
0302: // check agendaGroup2 still got the tuple
0303: assertEquals(2, agendaGroup2.size());
0304:
0305: // make sure total agenda size reflects this
0306: assertEquals(3, agenda.agendaSize());
0307:
0308: // set the focus to agendaGroup1, note agendaGroup1 has no activations
0309: agenda.setFocus("agendaGroup1");
0310: // add agendaGroup2 onto the focus stack
0311: agenda.setFocus("agendaGroup2");
0312: // finally add agendaGroup3 to the top of the focus stack
0313: agenda.setFocus("agendaGroup3");
0314:
0315: // agendaGroup3, the current focus, has no activations
0316: assertEquals(0, agenda.getFocus().size());
0317:
0318: // add to agendaGroup 3
0319: node3.assertTuple(tuple, context3, workingMemory);
0320:
0321: assertEquals(1, agenda.getFocus().size());
0322:
0323: node3.assertTuple(tuple, context3, workingMemory);
0324:
0325: // agendaGroup3 now has 2 activations
0326: assertEquals(2, agenda.getFocus().size());
0327: // check totalAgendaSize still works
0328: assertEquals(5, agenda.agendaSize());
0329:
0330: // ok now lets check that stacks work with fireNextItem
0331: agenda.fireNextItem(null);
0332:
0333: // agendaGroup3 should still be the current agendaGroup
0334: assertEquals(agenda.getFocus(), agendaGroup3);
0335: // agendaGroup3 has gone from 2 to one activations
0336: assertEquals(1, agenda.getFocus().size());
0337: // check totalAgendaSize has reduced too
0338: assertEquals(4, agenda.agendaSize());
0339:
0340: // now repeat the process
0341: agenda.fireNextItem(null);
0342:
0343: // focus is still agendaGroup3, but now its empty
0344: assertEquals(agenda.getFocus(), agendaGroup3);
0345: assertEquals(0, agenda.getFocus().size());
0346: assertEquals(3, agenda.agendaSize());
0347:
0348: // repeat fire again
0349: agenda.fireNextItem(null);
0350:
0351: // agendaGroup3 is empty so it should be popped from the stack making````````````````````
0352: // agendaGroup2
0353: // the current agendaGroup
0354: assertEquals(agendaGroup2, agenda.getFocus());
0355: // agendaGroup2 had 2 activations, now it only has 1
0356: assertEquals(1, agenda.getFocus().size());
0357: assertEquals(2, agenda.agendaSize());
0358:
0359: // repeat fire again
0360: agenda.fireNextItem(null);
0361:
0362: assertEquals(agenda.getFocus(), agendaGroup2);
0363: assertEquals(0, agenda.getFocus().size());
0364: assertEquals(1, agenda.agendaSize());
0365:
0366: // this last fire is more interesting as it demonstrates that
0367: // agendaGroup1 on
0368: // the stack before agendaGroup2 gets skipped as it has no activations
0369: agenda.fireNextItem(null);
0370:
0371: assertEquals(agenda.getFocus(), main);
0372: assertEquals(0, agenda.getFocus().size());
0373: assertEquals(0, agenda.agendaSize());
0374:
0375: }
0376:
0377: //
0378: public void testAutoFocus() throws ConsequenceException {
0379: final InternalRuleBase ruleBase = (InternalRuleBase) RuleBaseFactory
0380: .newRuleBase();
0381:
0382: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0383: .newStatefulSession();
0384: final InternalAgenda agenda = (InternalAgenda) workingMemory
0385: .getAgenda();
0386:
0387: // create the agendaGroup
0388: final AgendaGroup agendaGroup = new BinaryHeapQueueAgendaGroup(
0389: "agendaGroup", ruleBase);
0390: agenda.addAgendaGroup(agendaGroup);
0391:
0392: // create the consequence
0393: final Consequence consequence = new Consequence() {
0394: /**
0395: *
0396: */
0397: private static final long serialVersionUID = 400L;
0398:
0399: public void evaluate(KnowledgeHelper knowledgeHelper,
0400: WorkingMemory workingMemory) {
0401: // do nothing
0402: }
0403: };
0404:
0405: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
0406: "cheese"));
0407:
0408: // create a rule for the agendaGroup
0409: final Rule rule = new Rule("test-rule", "agendaGroup");
0410: final RuleTerminalNode node = new RuleTerminalNode(2,
0411: new MockTupleSource(2), rule, rule.getLhs());
0412: rule.setConsequence(consequence);
0413: final PropagationContext context = new PropagationContextImpl(
0414: 0, PropagationContext.ASSERTION, rule, null);
0415:
0416: // first test that autoFocus=false works. Here the rule should not fire
0417: // as its agendaGroup does not have focus.
0418: rule.setAutoFocus(false);
0419:
0420: node.assertTuple(tuple, context, workingMemory);
0421:
0422: // check activation as added to the agendaGroup
0423: assertEquals(1, agendaGroup.size());
0424:
0425: // fire next item, agendaGroup should not fire as its not on the focus stack
0426: // and thus should retain its sinle activation
0427: agenda.fireNextItem(null);
0428: assertEquals(1, agendaGroup.size());
0429:
0430: // Clear the agenda we we can test again
0431: agenda.clearAgenda();
0432: assertEquals(0, agendaGroup.size());
0433:
0434: // Now test that autoFocus=true works. Here the rule should fire as its
0435: // agendaGroup gets the focus when the activation is created.
0436: rule.setAutoFocus(true);
0437:
0438: node.assertTuple(tuple, context, workingMemory);
0439:
0440: assertEquals(1, agendaGroup.size());
0441: agenda.fireNextItem(null);
0442: assertEquals(0, agendaGroup.size());
0443: }
0444:
0445: public void testAgendaGroupLockOnActive() {
0446: final InternalRuleBase ruleBase = (InternalRuleBase) RuleBaseFactory
0447: .newRuleBase();
0448:
0449: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0450: .newStatefulSession();
0451: final InternalAgenda agenda = (InternalAgenda) workingMemory
0452: .getAgenda();
0453:
0454: // create the agendaGroup
0455: final InternalAgendaGroup agendaGroup = new BinaryHeapQueueAgendaGroup(
0456: "agendaGroup", ruleBase);
0457: agenda.addAgendaGroup(agendaGroup);
0458:
0459: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
0460: "cheese"));
0461:
0462: // create a rule for the agendaGroup
0463: final Rule rule = new Rule("test-rule", "agendaGroup");
0464: final RuleTerminalNode node = new RuleTerminalNode(2,
0465: new MockTupleSource(2), rule, rule.getLhs());
0466:
0467: final PropagationContext context = new PropagationContextImpl(
0468: 0, PropagationContext.ASSERTION, rule, null);
0469:
0470: // When both the rule is lock-on-active and the agenda group is active, activations should be ignored
0471: rule.setLockOnActive(true);
0472: agendaGroup.setActive(true);
0473: node.assertTuple(tuple, context, workingMemory);
0474: // activation should be ignored
0475: assertEquals(0, agendaGroup.size());
0476:
0477: // lock-on-active is now false so activation should propagate
0478: rule.setLockOnActive(false);
0479: node.assertTuple(tuple, context, workingMemory);
0480: assertEquals(1, agendaGroup.size());
0481:
0482: // even if lock-on-active is true, unless the agenda group is active the activation will still propagate
0483: rule.setLockOnActive(true);
0484: agendaGroup.setActive(false);
0485: node.assertTuple(tuple, context, workingMemory);
0486: assertEquals(2, agendaGroup.size());
0487: }
0488:
0489: public void testActivationGroup() {
0490: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
0491:
0492: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0493: .newStatefulSession();
0494:
0495: final InternalAgenda agenda = (InternalAgenda) workingMemory
0496: .getAgenda();
0497:
0498: final List list = new ArrayList();
0499:
0500: // create the consequence
0501: final Consequence consequence = new Consequence() {
0502: /**
0503: *
0504: */
0505: private static final long serialVersionUID = 400L;
0506:
0507: public void evaluate(KnowledgeHelper knowledgeHelper,
0508: WorkingMemory workingMemory) {
0509: list.add(knowledgeHelper.getRule());
0510: }
0511: };
0512:
0513: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
0514: "cheese"));
0515:
0516: // create a rule for each agendaGroup
0517: final Rule rule0 = new Rule("test-rule0");
0518: rule0.setActivationGroup("activation-group-0");
0519: final RuleTerminalNode node0 = new RuleTerminalNode(3,
0520: new MockTupleSource(2), rule0, rule0.getLhs());
0521: rule0.setConsequence(consequence);
0522: final PropagationContext context0 = new PropagationContextImpl(
0523: 0, PropagationContext.ASSERTION, rule0, null);
0524:
0525: final Rule rule1 = new Rule("test-rule1");
0526: rule1.setActivationGroup("activation-group-0");
0527: final RuleTerminalNode node1 = new RuleTerminalNode(5,
0528: new MockTupleSource(4), rule1, rule1.getLhs());
0529: rule1.setConsequence(consequence);
0530: final PropagationContext context1 = new PropagationContextImpl(
0531: 0, PropagationContext.ASSERTION, rule1, null);
0532:
0533: final Rule rule2 = new Rule("test-rule2");
0534: final RuleTerminalNode node2 = new RuleTerminalNode(7,
0535: new MockTupleSource(6), rule2, rule2.getLhs());
0536: rule2.setConsequence(consequence);
0537: final PropagationContext context2 = new PropagationContextImpl(
0538: 0, PropagationContext.ASSERTION, rule2, null);
0539:
0540: final Rule rule3 = new Rule("test-rule3", "agendaGroup3");
0541: rule3.setActivationGroup("activation-group-3");
0542: final RuleTerminalNode node3 = new RuleTerminalNode(9,
0543: new MockTupleSource(8), rule3, rule3.getLhs());
0544: rule3.setConsequence(consequence);
0545: final PropagationContext context3 = new PropagationContextImpl(
0546: 0, PropagationContext.ASSERTION, rule3, null);
0547:
0548: // Assert the tuple and check it was added to activation-group-0
0549: node0.assertTuple(tuple, context0, workingMemory);
0550: final ActivationGroup activationGroup0 = agenda
0551: .getActivationGroup("activation-group-0");
0552: assertEquals(1, activationGroup0.size());
0553:
0554: // Removing a tuple should remove the activation from the activation-group-0 again
0555: node0.retractTuple(tuple, context0, workingMemory);
0556: assertEquals(0, activationGroup0.size());
0557:
0558: // Assert the tuple again and check it was added to activation-group-0
0559: node0.assertTuple(tuple, context0, workingMemory);
0560: assertEquals(1, activationGroup0.size());
0561:
0562: // Assert another tuple and check it was added to activation-group-0
0563: node1.assertTuple(tuple, context1, workingMemory);
0564: assertEquals(2, activationGroup0.size());
0565:
0566: // There should now be two potential activations to fire
0567: assertEquals(2, agenda.focusStackSize());
0568:
0569: // The first tuple should fire, adding itself to the List and clearing and cancelling the other Activations in the activation-group-0
0570: agenda.fireNextItem(null);
0571:
0572: // Make sure the activation-group-0 is clear
0573: assertEquals(0, activationGroup0.size());
0574:
0575: // Make sure the Agenda is empty
0576: assertEquals(0, agenda.focusStackSize());
0577:
0578: // List should only have a single item, "rule0"
0579: assertEquals(1, list.size());
0580: assertSame(rule0, list.get(0));
0581:
0582: list.clear();
0583:
0584: //-------------------
0585: // Now try a more complex scenario involving two Xor Groups and one rule not in a Group
0586: node0.assertTuple(tuple, context0, workingMemory);
0587: node1.assertTuple(tuple, context1, workingMemory);
0588: node2.assertTuple(tuple, context2, workingMemory);
0589: node3.assertTuple(tuple, context3, workingMemory);
0590:
0591: // activation-group-0 should be populated again
0592: assertEquals(2, activationGroup0.size());
0593:
0594: // make sure the activation-group-3 is cleared when we can clear the Agenda Group for the activation that is in both
0595: final ActivationGroup activationGroup3 = agenda
0596: .getActivationGroup("activation-group-3");
0597:
0598: assertEquals(4, agenda.agendaSize());
0599: assertEquals(1, activationGroup3.size());
0600:
0601: agenda.clearAgendaGroup("agendaGroup3");
0602: assertEquals(3, agenda.agendaSize());
0603: assertEquals(0, activationGroup3.size());
0604:
0605: // Activation for activation-group-0 should be next - the activation in no activation/agenda group should remain on the agenda
0606: agenda.fireNextItem(null);
0607: assertEquals(1, agenda.agendaSize());
0608: assertEquals(0, activationGroup0.size());
0609:
0610: // Fire the last activation and make sure the Agenda Empties
0611: agenda.fireNextItem(null);
0612: assertEquals(0, agenda.agendaSize());
0613:
0614: assertEquals(2, list.size());
0615: assertEquals(rule0, list.get(0));
0616: assertEquals(rule2, list.get(1));
0617:
0618: }
0619:
0620: /**
0621: * Basic RuleFlowGroup test where there are three rules, each in their own
0622: * RuleFlowGroup. First only rule-flow-group-0 is activated and rule0 is
0623: * executed. When the two remaining groups are activated, the rule with the
0624: * highest priority is executed first.
0625: */
0626: public void testRuleFlowGroup() {
0627: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
0628:
0629: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0630: .newStatefulSession();
0631:
0632: final InternalAgenda agenda = (InternalAgenda) workingMemory
0633: .getAgenda();
0634:
0635: final List list = new ArrayList();
0636:
0637: // create the consequence
0638: final Consequence consequence = new Consequence() {
0639: /**
0640: *
0641: */
0642: private static final long serialVersionUID = 400L;
0643:
0644: public void evaluate(KnowledgeHelper knowledgeHelper,
0645: WorkingMemory workingMemory) {
0646: list.add(knowledgeHelper.getRule());
0647: }
0648: };
0649:
0650: // create a rule for each rule flow groups
0651: final Rule rule0 = new Rule("test-rule0");
0652: rule0.setRuleFlowGroup("rule-flow-group-0");
0653: rule0.setConsequence(consequence);
0654:
0655: final RuleTerminalNode node0 = new RuleTerminalNode(3,
0656: new MockTupleSource(2), rule0, rule0.getLhs());
0657:
0658: final Rule rule1 = new Rule("test-rule1");
0659: rule1.setRuleFlowGroup("rule-flow-group-1");
0660: rule1.setConsequence(consequence);
0661:
0662: final RuleTerminalNode node1 = new RuleTerminalNode(4,
0663: new MockTupleSource(2), rule1, rule1.getLhs());
0664:
0665: final Rule rule2 = new Rule("test-rule2");
0666: rule2.setRuleFlowGroup("rule-flow-group-2");
0667: rule2.setConsequence(consequence);
0668: rule2.setSalience(new SalienceInteger(10));
0669:
0670: final RuleTerminalNode node2 = new RuleTerminalNode(5,
0671: new MockTupleSource(2), rule2, rule2.getLhs());
0672:
0673: final PropagationContext context0 = new PropagationContextImpl(
0674: 0, PropagationContext.ASSERTION, rule0, null);
0675:
0676: final RuleFlowGroup ruleFlowGroup0 = agenda
0677: .getRuleFlowGroup("rule-flow-group-0");
0678: final RuleFlowGroup ruleFlowGroup1 = agenda
0679: .getRuleFlowGroup("rule-flow-group-1");
0680: final RuleFlowGroup ruleFlowGroup2 = agenda
0681: .getRuleFlowGroup("rule-flow-group-2");
0682:
0683: final ReteTuple tuple0 = new ReteTuple(new DefaultFactHandle(1,
0684: "cheese"));
0685: node0.assertTuple(tuple0, context0, workingMemory);
0686:
0687: final ReteTuple tuple1 = new ReteTuple(new DefaultFactHandle(1,
0688: "cheese"));
0689: node0.assertTuple(tuple1, context0, workingMemory);
0690:
0691: final ReteTuple tuple2 = new ReteTuple(new DefaultFactHandle(1,
0692: "cheese"));
0693: node1.assertTuple(tuple2, context0, workingMemory);
0694:
0695: final ReteTuple tuple3 = new ReteTuple(new DefaultFactHandle(1,
0696: "cheese"));
0697: node2.assertTuple(tuple3, context0, workingMemory);
0698:
0699: // RuleFlowGroups should be populated, but the agenda shouldn't be
0700: assertEquals(2, ruleFlowGroup0.size());
0701: assertEquals(1, ruleFlowGroup1.size());
0702: assertEquals(1, ruleFlowGroup2.size());
0703: assertEquals(0, agenda.agendaSize());
0704:
0705: // Activate the RuleFlowGroup, the nodes stay in the group, but should now also be in the Agenda
0706: agenda.activateRuleFlowGroup("rule-flow-group-0");
0707: assertEquals(2, ruleFlowGroup0.size());
0708: assertEquals(2, agenda.agendaSize());
0709:
0710: // As we fire each rule they are removed from both the Agenda and the RuleFlowGroup
0711: agenda.fireNextItem(null);
0712: assertEquals(1, ruleFlowGroup0.size());
0713: assertEquals(1, agenda.agendaSize());
0714:
0715: // After firing all activations of RuleFlowGroup 0, the agenda is empty
0716: agenda.fireNextItem(null);
0717: assertEquals(0, ruleFlowGroup0.size());
0718: assertEquals(0, agenda.agendaSize());
0719:
0720: // Now we activate two RuleFlowGroups together
0721: // All their activations should be added to the agenda.
0722: agenda.activateRuleFlowGroup("rule-flow-group-1");
0723: agenda.activateRuleFlowGroup("rule-flow-group-2");
0724: assertEquals(1, ruleFlowGroup1.size());
0725: assertEquals(1, ruleFlowGroup2.size());
0726: assertEquals(2, agenda.agendaSize());
0727:
0728: // we set the salience higher on rule2, so it sould fire first and empty ruleFlowGroup2
0729: agenda.fireNextItem(null);
0730: assertEquals(1, ruleFlowGroup1.size());
0731: assertEquals(0, ruleFlowGroup2.size());
0732: assertEquals(1, agenda.agendaSize());
0733:
0734: // this is the last activation, so everything should be empty after this
0735: agenda.fireNextItem(null);
0736: assertEquals(0, ruleFlowGroup0.size());
0737: assertEquals(0, ruleFlowGroup1.size());
0738: assertEquals(0, ruleFlowGroup2.size());
0739: assertEquals(0, agenda.agendaSize());
0740: }
0741:
0742: /**
0743: * RuleFlowGroup test that makes sure that, if new activations are created
0744: * for an active RuleFlowGroup, those activations get added to the agenda
0745: * directly as well.
0746: */
0747: public void testRuleFlowGroup1() {
0748: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
0749:
0750: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0751: .newStatefulSession();
0752:
0753: final InternalAgenda agenda = (InternalAgenda) workingMemory
0754: .getAgenda();
0755:
0756: // create rule1
0757: final Consequence consequence1 = new Consequence() {
0758: private static final long serialVersionUID = 400L;
0759:
0760: public void evaluate(KnowledgeHelper knowledgeHelper,
0761: WorkingMemory workingMemory) {
0762: // do nothing
0763: }
0764: };
0765:
0766: final Rule rule1 = new Rule("test-rule1");
0767: rule1.setRuleFlowGroup("rule-flow-group-0");
0768: rule1.setConsequence(consequence1);
0769:
0770: final RuleTerminalNode node1 = new RuleTerminalNode(4,
0771: new MockTupleSource(2), rule1, rule1.getLhs());
0772:
0773: // create context
0774: final PropagationContext context0 = new PropagationContextImpl(
0775: 0, PropagationContext.ASSERTION, rule1, null);
0776:
0777: // create rule0
0778: final Consequence consequence0 = new Consequence() {
0779: private static final long serialVersionUID = 400L;
0780:
0781: public void evaluate(KnowledgeHelper knowledgeHelper,
0782: WorkingMemory w) {
0783: // activate rule1
0784: final ReteTuple tuple1 = new ReteTuple(
0785: new DefaultFactHandle(1, "cheese"));
0786: node1.assertTuple(tuple1, context0, workingMemory);
0787: }
0788: };
0789:
0790: final Rule rule0 = new Rule("test-rule0");
0791: rule0.setRuleFlowGroup("rule-flow-group-0");
0792: rule0.setConsequence(consequence0);
0793:
0794: final RuleTerminalNode node0 = new RuleTerminalNode(3,
0795: new MockTupleSource(2), rule0, rule0.getLhs());
0796:
0797: final RuleFlowGroup ruleFlowGroup0 = agenda
0798: .getRuleFlowGroup("rule-flow-group-0");
0799:
0800: // Create one activation for rule0 only
0801: final ReteTuple tuple0 = new ReteTuple(new DefaultFactHandle(1,
0802: "cheese"));
0803: node0.assertTuple(tuple0, context0, workingMemory);
0804:
0805: // RuleFlowGroup should be populated, but the agenda shouldn't be
0806: assertEquals(1, ruleFlowGroup0.size());
0807: assertEquals(0, agenda.agendaSize());
0808:
0809: // Activate the RuleFlowGroup, the activation stays in the group, but should now also be in the Agenda
0810: agenda.activateRuleFlowGroup("rule-flow-group-0");
0811: assertEquals(1, ruleFlowGroup0.size());
0812: assertEquals(1, agenda.agendaSize());
0813:
0814: // As we fire the rule, an new activation is created for rule1, and it should be added to group AND the agenda.
0815: agenda.fireNextItem(null);
0816: assertEquals(1, ruleFlowGroup0.size());
0817: assertEquals(1, agenda.agendaSize());
0818:
0819: // After firing all activations of RuleFlowGroup 0, the agenda is empty
0820: agenda.fireNextItem(null);
0821: assertEquals(0, ruleFlowGroup0.size());
0822: assertEquals(0, agenda.agendaSize());
0823: }
0824:
0825: /**
0826: * RuleFlowGroup test that makes sure that, if an activation in an active
0827: * RuleFlowGroup gets deactivated, the activation is no longer executed.
0828: */
0829: public void testRuleFlowGroup2() {
0830: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
0831:
0832: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0833: .newStatefulSession();
0834:
0835: final InternalAgenda agenda = (InternalAgenda) workingMemory
0836: .getAgenda();
0837:
0838: // create rule1
0839: final Consequence consequence1 = new Consequence() {
0840: private static final long serialVersionUID = 400L;
0841:
0842: public void evaluate(KnowledgeHelper knowledgeHelper,
0843: WorkingMemory workingMemory) {
0844: // do nothing
0845: }
0846: };
0847:
0848: final Rule rule1 = new Rule("test-rule1");
0849: rule1.setRuleFlowGroup("rule-flow-group-0");
0850: rule1.setConsequence(consequence1);
0851:
0852: final RuleTerminalNode node1 = new RuleTerminalNode(4,
0853: new MockTupleSource(2), rule1, rule1.getLhs());
0854:
0855: // create context
0856: final PropagationContext context0 = new PropagationContextImpl(
0857: 0, PropagationContext.ASSERTION, rule1, null);
0858:
0859: final ReteTuple tuple1 = new ReteTuple(new DefaultFactHandle(1,
0860: "cheese"));
0861:
0862: // create rule0
0863: final Consequence consequence0 = new Consequence() {
0864: private static final long serialVersionUID = 400L;
0865:
0866: public void evaluate(KnowledgeHelper knowledgeHelper,
0867: WorkingMemory w) {
0868: // deactivate rule1
0869: node1.retractTuple(tuple1, context0, workingMemory);
0870: }
0871: };
0872:
0873: final Rule rule0 = new Rule("test-rule0");
0874: rule0.setRuleFlowGroup("rule-flow-group-0");
0875: rule0.setConsequence(consequence0);
0876: rule0.setSalience(new SalienceInteger(10));
0877:
0878: final RuleTerminalNode node0 = new RuleTerminalNode(3,
0879: new MockTupleSource(2), rule0, rule0.getLhs());
0880:
0881: final RuleFlowGroup ruleFlowGroup0 = agenda
0882: .getRuleFlowGroup("rule-flow-group-0");
0883:
0884: // Create an activation for both rules
0885: final ReteTuple tuple0 = new ReteTuple(new DefaultFactHandle(1,
0886: "cheese"));
0887: node0.assertTuple(tuple0, context0, workingMemory);
0888:
0889: node1.assertTuple(tuple1, context0, workingMemory);
0890:
0891: // RuleFlowGroup should be populated, but the agenda shouldn't be
0892: assertEquals(2, ruleFlowGroup0.size());
0893: assertEquals(0, agenda.agendaSize());
0894:
0895: // Activate the RuleFlowGroup, the activations stay in the group, but should now also be in the Agenda
0896: agenda.activateRuleFlowGroup("rule-flow-group-0");
0897: assertEquals(2, ruleFlowGroup0.size());
0898: assertEquals(2, agenda.agendaSize());
0899:
0900: // As we fire the rule, rule0 should execute first, as it has higher salience.
0901: // Rule0 should deactivate rule1 as well, so the everything should be empty
0902: agenda.fireNextItem(null);
0903: assertEquals(0, ruleFlowGroup0.size());
0904: assertEquals(0, agenda.agendaSize());
0905:
0906: }
0907:
0908: /**
0909: * RuleFlowGroup test that makes sure that, when deactivating a RuleFlowGroup,
0910: * all activations for that group are no longer on the agenda. When
0911: * reactivating the RuleFlowGroup however, they get added to the agenda again.
0912: */
0913: public void testRuleFlowGroup3() {
0914: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
0915:
0916: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
0917: .newStatefulSession();
0918:
0919: final InternalAgenda agenda = (InternalAgenda) workingMemory
0920: .getAgenda();
0921:
0922: // create rule0
0923: final Consequence consequence0 = new Consequence() {
0924: private static final long serialVersionUID = 400L;
0925:
0926: public void evaluate(KnowledgeHelper knowledgeHelper,
0927: WorkingMemory w) {
0928: // do nothing
0929: }
0930: };
0931:
0932: final Rule rule0 = new Rule("test-rule0");
0933: rule0.setRuleFlowGroup("rule-flow-group-0");
0934: rule0.setConsequence(consequence0);
0935:
0936: final RuleTerminalNode node0 = new RuleTerminalNode(1,
0937: new MockTupleSource(2), rule0, rule0.getLhs());
0938:
0939: final RuleFlowGroup ruleFlowGroup0 = agenda
0940: .getRuleFlowGroup("rule-flow-group-0");
0941:
0942: // create context
0943: final PropagationContext context0 = new PropagationContextImpl(
0944: 0, PropagationContext.ASSERTION, rule0, null);
0945:
0946: // Create two activation for this rule
0947: final ReteTuple tuple0 = new ReteTuple(new DefaultFactHandle(1,
0948: "cheese"));
0949: node0.assertTuple(tuple0, context0, workingMemory);
0950: final ReteTuple tuple1 = new ReteTuple(new DefaultFactHandle(1,
0951: "cheese"));
0952: node0.assertTuple(tuple1, context0, workingMemory);
0953:
0954: // RuleFlowGroup should be populated, but the agenda shouldn't be
0955: assertEquals(2, ruleFlowGroup0.size());
0956: assertEquals(0, agenda.agendaSize());
0957:
0958: // Activate the RuleFlowGroup, the activations stay in the group, but
0959: // should now also be in the Agenda
0960: agenda.activateRuleFlowGroup("rule-flow-group-0");
0961: assertEquals(2, ruleFlowGroup0.size());
0962: assertEquals(2, agenda.agendaSize());
0963:
0964: // Reactivate an already active RuleFlowGroup should not have any effect
0965: agenda.activateRuleFlowGroup("rule-flow-group-0");
0966: assertEquals(2, ruleFlowGroup0.size());
0967: assertEquals(2, agenda.agendaSize());
0968:
0969: // Deactivate the RuleFlowGroup, the activations should be removed from
0970: // the agenda but still in the RuleFlowGroup
0971: agenda.deactivateRuleFlowGroup("rule-flow-group-0");
0972: assertEquals(2, ruleFlowGroup0.size());
0973: assertEquals(0, agenda.agendaSize());
0974:
0975: // Reactivate the RuleFlowGroup, the activations stay in the group, but
0976: // should now also be in the Agenda again
0977: agenda.activateRuleFlowGroup("rule-flow-group-0");
0978: assertEquals(2, ruleFlowGroup0.size());
0979: assertEquals(2, agenda.agendaSize());
0980:
0981: }
0982:
0983: /**
0984: * Test auto-deactivation of RuleFlowGroup.
0985: */
0986: public void testRuleFlowGroup4() {
0987: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
0988: .newRuleBase();
0989: IdGenerator idGenerator = ruleBase.getReteooBuilder()
0990: .getIdGenerator();
0991: final InternalWorkingMemory workingMemory = (InternalWorkingMemory) ruleBase
0992: .newStatefulSession();
0993: ;
0994:
0995: final InternalAgenda agenda = (InternalAgenda) workingMemory
0996: .getAgenda();
0997:
0998: // create rule0
0999: final Consequence consequence0 = new Consequence() {
1000: private static final long serialVersionUID = 400L;
1001:
1002: public void evaluate(KnowledgeHelper knowledgeHelper,
1003: WorkingMemory w) {
1004: // do nothing
1005: }
1006: };
1007:
1008: final Rule rule0 = new Rule("test-rule0");
1009: rule0.setRuleFlowGroup("rule-flow-group-0");
1010: rule0.setConsequence(consequence0);
1011:
1012: final RuleTerminalNode node0 = new RuleTerminalNode(idGenerator
1013: .getNextId(), new MockTupleSource(idGenerator
1014: .getNextId()), rule0, rule0.getLhs());
1015:
1016: final RuleFlowGroup ruleFlowGroup0 = agenda
1017: .getRuleFlowGroup("rule-flow-group-0");
1018: assertTrue(ruleFlowGroup0.isAutoDeactivate());
1019: ruleFlowGroup0.setAutoDeactivate(false);
1020: assertFalse(ruleFlowGroup0.isAutoDeactivate());
1021:
1022: // create context
1023: final PropagationContext context0 = new PropagationContextImpl(
1024: 0, PropagationContext.ASSERTION, rule0, null);
1025:
1026: // Create an activation for this rule
1027: final ReteTuple tuple0 = new ReteTuple(new DefaultFactHandle(1,
1028: "cheese"));
1029: node0.assertTuple(tuple0, context0, workingMemory);
1030:
1031: // RuleFlowGroup should be populated, but the agenda shouldn't be
1032: assertEquals(1, ruleFlowGroup0.size());
1033: assertEquals(0, agenda.agendaSize());
1034:
1035: // Activate the RuleFlowGroup, the activations stay in the group, but
1036: // should now also be in the Agenda
1037: agenda.activateRuleFlowGroup("rule-flow-group-0");
1038: assertEquals(1, ruleFlowGroup0.size());
1039: assertEquals(1, agenda.agendaSize());
1040:
1041: // Execute activation
1042: agenda.fireNextItem(null);
1043: assertEquals(0, ruleFlowGroup0.size());
1044: assertEquals(0, agenda.agendaSize());
1045: assertTrue(ruleFlowGroup0.isActive());
1046:
1047: // Set auto-deactivation status to true
1048: ruleFlowGroup0.setAutoDeactivate(true);
1049: assertTrue(ruleFlowGroup0.isAutoDeactivate());
1050: assertFalse(ruleFlowGroup0.isActive());
1051:
1052: // Add another activation and activate RuleFlowGroup again
1053: final ReteTuple tuple1 = new ReteTuple(new DefaultFactHandle(1,
1054: "cheese"));
1055: node0.assertTuple(tuple1, context0, workingMemory);
1056: agenda.activateRuleFlowGroup("rule-flow-group-0");
1057: assertEquals(1, ruleFlowGroup0.size());
1058: assertEquals(1, agenda.agendaSize());
1059: assertTrue(ruleFlowGroup0.isActive());
1060:
1061: // Execute the activation, the RuleFlowGroup should automatically deactivate
1062: agenda.fireNextItem(null);
1063: assertEquals(0, ruleFlowGroup0.size());
1064: assertEquals(0, agenda.agendaSize());
1065: workingMemory.executeQueuedActions();
1066: assertFalse(ruleFlowGroup0.isActive());
1067:
1068: // A new activation should now be added to the RuleFlowGroup but not to the agenda
1069: final ReteTuple tuple2 = new ReteTuple(new DefaultFactHandle(1,
1070: "cheese"));
1071: node0.assertTuple(tuple2, context0, workingMemory);
1072: assertEquals(1, ruleFlowGroup0.size());
1073: assertEquals(0, agenda.agendaSize());
1074: }
1075:
1076: /**
1077: * Test auto-deactivation of empty ruleflow group.
1078: */
1079: public void testRuleFlowGroup5() {
1080: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
1081:
1082: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
1083: .newStatefulSession();
1084:
1085: final InternalAgenda agenda = (InternalAgenda) workingMemory
1086: .getAgenda();
1087:
1088: // create rule0
1089: final Consequence consequence0 = new Consequence() {
1090: private static final long serialVersionUID = 400L;
1091:
1092: public void evaluate(KnowledgeHelper knowledgeHelper,
1093: WorkingMemory w) {
1094: // do nothing
1095: }
1096: };
1097:
1098: final Rule rule0 = new Rule("test-rule0");
1099: rule0.setRuleFlowGroup("rule-flow-group-0");
1100: rule0.setConsequence(consequence0);
1101:
1102: final RuleFlowGroup ruleFlowGroup0 = agenda
1103: .getRuleFlowGroup("rule-flow-group-0");
1104: assertTrue(ruleFlowGroup0.isAutoDeactivate());
1105:
1106: // RuleFlowGroup should be empty, as well as the agenda
1107: assertEquals(0, ruleFlowGroup0.size());
1108: assertEquals(0, agenda.agendaSize());
1109:
1110: // Activate the RuleFlowGroup, the activations stay in the group, but
1111: // should now also be in the Agenda
1112: agenda.activateRuleFlowGroup("rule-flow-group-0");
1113: assertEquals(0, ruleFlowGroup0.size());
1114: assertEquals(0, agenda.agendaSize());
1115: workingMemory.executeQueuedActions();
1116:
1117: assertFalse(ruleFlowGroup0.isActive());
1118: }
1119:
1120: public void testRuleFlowGroupLockOnActive() {
1121: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
1122:
1123: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
1124: .newStatefulSession();
1125: final InternalAgenda agenda = (InternalAgenda) workingMemory
1126: .getAgenda();
1127:
1128: // create the agendaGroup
1129: //final AgendaGroupImpl agendaGroup = new AgendaGroupImpl( "agendaGroup" );
1130: //agenda.addAgendaGroup( agendaGroup );
1131:
1132: final RuleFlowGroupImpl ruleFlowGroup = (RuleFlowGroupImpl) agenda
1133: .getRuleFlowGroup("rule-flow-group-0");
1134:
1135: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
1136: "cheese"));
1137:
1138: // create a rule for the agendaGroup
1139: final Rule rule = new Rule("test-rule");
1140: rule.setRuleFlowGroup("rule-flow-group-0");
1141: final RuleTerminalNode node = new RuleTerminalNode(2,
1142: new MockTupleSource(2), rule, rule.getLhs());
1143:
1144: final PropagationContext context = new PropagationContextImpl(
1145: 0, PropagationContext.ASSERTION, rule, null);
1146:
1147: // When both the rule is lock-on-active and the agenda group is active, activations should be ignored
1148: rule.setLockOnActive(true);
1149: ruleFlowGroup.setAutoDeactivate(false);
1150: ruleFlowGroup.setActive(true);
1151: node.assertTuple(tuple, context, workingMemory);
1152: // activation should be ignored
1153: assertEquals(0, ruleFlowGroup.size());
1154:
1155: // lock-on-active is now false so activation should propagate
1156: rule.setLockOnActive(false);
1157: node.assertTuple(tuple, context, workingMemory);
1158: assertEquals(1, ruleFlowGroup.size());
1159:
1160: // even if lock-on-active is true, unless the agenda group is active the activation will still propagate
1161: rule.setLockOnActive(true);
1162: ruleFlowGroup.setActive(false);
1163: node.assertTuple(tuple, context, workingMemory);
1164: assertEquals(2, ruleFlowGroup.size());
1165: }
1166:
1167: public void testSequentialAgenda() {
1168: RuleBaseConfiguration conf = new RuleBaseConfiguration();
1169: conf.setSequential(true);
1170: InternalRuleBase ruleBase = (InternalRuleBase) RuleBaseFactory
1171: .newRuleBase(conf);
1172:
1173: // create the consequence
1174: final Consequence consequence = new Consequence() {
1175: /**
1176: *
1177: */
1178: private static final long serialVersionUID = 400L;
1179:
1180: public void evaluate(KnowledgeHelper knowledgeHelper,
1181: WorkingMemory workingMemory) {
1182: // do nothing
1183: }
1184: };
1185:
1186: final ReteTuple tuple = new ReteTuple(new DefaultFactHandle(1,
1187: "cheese"));
1188:
1189: // create a rule for each agendaGroup
1190: final Rule rule0 = new Rule("test-rule0");
1191: final RuleTerminalNode node0 = new RuleTerminalNode(3,
1192: new MockTupleSource(2), rule0, rule0.getLhs());
1193: node0.setSequence(72);
1194: rule0.setConsequence(consequence);
1195: final PropagationContext context0 = new PropagationContextImpl(
1196: 0, PropagationContext.ASSERTION, rule0, null);
1197:
1198: final Rule rule1 = new Rule("test-rule1", "agendaGroup1");
1199: final RuleTerminalNode node1 = new RuleTerminalNode(5,
1200: new MockTupleSource(4), rule1, rule1.getLhs());
1201: node1.setSequence(10);
1202: rule1.setConsequence(consequence);
1203: final PropagationContext context1 = new PropagationContextImpl(
1204: 0, PropagationContext.ASSERTION, rule1, null);
1205:
1206: final Rule rule2 = new Rule("test-rule2", "agendaGroup1");
1207: final RuleTerminalNode node2 = new RuleTerminalNode(7,
1208: new MockTupleSource(6), rule2, rule2.getLhs());
1209: node2.setSequence(7);
1210: rule2.setConsequence(consequence);
1211: final PropagationContext context2 = new PropagationContextImpl(
1212: 0, PropagationContext.ASSERTION, rule2, null);
1213:
1214: final Rule rule3 = new Rule("test-rule3", "agendaGroup2");
1215: final RuleTerminalNode node3 = new RuleTerminalNode(9,
1216: new MockTupleSource(8), rule3, rule3.getLhs());
1217: node3.setSequence(0);
1218: rule3.setConsequence(consequence);
1219: final PropagationContext context3 = new PropagationContextImpl(
1220: 0, PropagationContext.ASSERTION, rule3, null);
1221:
1222: ruleBase.getAgendaGroupRuleTotals().put("MAIN",
1223: new Integer(100));
1224: ruleBase.getAgendaGroupRuleTotals().put("agendaGroup1",
1225: new Integer(10));
1226: ruleBase.getAgendaGroupRuleTotals().put("agendaGroup2",
1227: new Integer(1));
1228:
1229: InternalWorkingMemory workingMemory = new ReteooWorkingMemory(
1230: 0, ruleBase);
1231:
1232: final InternalAgenda agenda = (InternalAgenda) workingMemory
1233: .getAgenda();
1234:
1235: final AgendaGroup agendaGroup1 = new ArrayAgendaGroup(
1236: "agendaGroup1", ruleBase);
1237: agenda.addAgendaGroup(agendaGroup1);
1238:
1239: final AgendaGroup agendaGroup2 = new ArrayAgendaGroup(
1240: "agendaGroup2", ruleBase);
1241: agenda.addAgendaGroup(agendaGroup2);
1242:
1243: // focus at this point is MAIN
1244: assertEquals(0, agenda.focusStackSize());
1245:
1246: node0.assertTuple(tuple, context0, workingMemory);
1247:
1248: // check focus is main
1249: final AgendaGroup main = agenda
1250: .getAgendaGroup(AgendaGroup.MAIN);
1251: assertEquals(agenda.getFocus(), main);
1252: // check main got the tuple
1253: assertEquals(1, agenda.getFocus().size());
1254: node2.assertTuple(tuple, context2, workingMemory);
1255:
1256: // main is still focus and this tuple went to agendaGroup1
1257: assertEquals(1, agenda.getFocus().size());
1258:
1259: // check agendaGroup1 still got the tuple
1260: assertEquals(1, agendaGroup1.size());
1261:
1262: // make sure total agenda size reflects this
1263: assertEquals(2, agenda.agendaSize());
1264:
1265: // put another one on agendaGroup 1
1266: node2.assertTuple(tuple, context2, workingMemory);
1267:
1268: // main is still focus so shouldn't have increased
1269: assertEquals(1, agenda.getFocus().size());
1270:
1271: // check agendaGroup2 still got the tuple
1272: assertEquals(2, agendaGroup1.size());
1273:
1274: // make sure total agenda size reflects this
1275: assertEquals(3, agenda.agendaSize());
1276:
1277: // set the focus to agendaGroup1, note agendaGroup1 has no activations
1278: agenda.setFocus("agendaGroup1");
1279: // add agendaGroup2 onto the focus stack
1280: agenda.setFocus("agendaGroup2");
1281:
1282: // agendaGroup2, the current focus, has no activations
1283: assertEquals(0, agenda.getFocus().size());
1284:
1285: // add to agendaGroup2
1286: node3.assertTuple(tuple, context3, workingMemory);
1287:
1288: assertEquals(1, agenda.getFocus().size());
1289:
1290: node3.assertTuple(tuple, context3, workingMemory);
1291:
1292: // agendaGroup2 now has 2 activations
1293: assertEquals(2, agenda.getFocus().size());
1294:
1295: // check totalAgendaSize still works
1296: assertEquals(5, agenda.agendaSize());
1297:
1298: // ok now lets check that stacks work with fireNextItem
1299: agenda.fireNextItem(null);
1300:
1301: // agendaGroup2 should still be the current agendaGroup
1302: assertEquals(agendaGroup2, agenda.getFocus());
1303: // agendaGroup2 has gone from 2 to one activations
1304: assertEquals(1, agenda.getFocus().size());
1305: // check totalAgendaSize has reduced too
1306: assertEquals(4, agenda.agendaSize());
1307:
1308: // now repeat the process
1309: agenda.fireNextItem(null);
1310:
1311: // focus is still agendaGroup2, but now its empty
1312: assertEquals(agendaGroup2, agenda.getFocus());
1313: assertEquals(0, agenda.getFocus().size());
1314: assertEquals(3, agenda.agendaSize());
1315:
1316: // repeat fire again
1317: agenda.fireNextItem(null);
1318:
1319: // agendaGroup2 is empty so it should be popped from the stack making agendaGroup1 the current agendaGroup
1320: assertEquals(agendaGroup1, agenda.getFocus());
1321: // agendaGroup1 had 2 activations, now it only has 1
1322: assertEquals(1, agenda.getFocus().size());
1323: assertEquals(2, agenda.agendaSize());
1324:
1325: // repeat fire again
1326: agenda.fireNextItem(null);
1327:
1328: assertEquals(agendaGroup1, agenda.getFocus());
1329: assertEquals(0, agenda.getFocus().size());
1330: assertEquals(1, agenda.agendaSize());
1331:
1332: // this last fire is more interesting as it demonstrates that
1333: // agendaGroup1 on
1334: // the stack before agendaGroup2 gets skipped as it has no activations
1335: agenda.fireNextItem(null);
1336:
1337: assertEquals(agenda.getFocus(), main);
1338: assertEquals(0, agenda.getFocus().size());
1339: assertEquals(0, agenda.agendaSize());
1340:
1341: }
1342:
1343: }
|