001: package org.drools.reteoo;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.util.ArrayList;
020: import java.util.List;
021:
022: import org.drools.DroolsTestCase;
023: import org.drools.RuleBase;
024: import org.drools.RuleBaseFactory;
025: import org.drools.WorkingMemory;
026: import org.drools.base.SalienceInteger;
027: import org.drools.common.DefaultFactHandle;
028: import org.drools.common.InternalAgenda;
029: import org.drools.common.PropagationContextImpl;
030: import org.drools.common.RuleFlowGroupImpl;
031: import org.drools.rule.Rule;
032: import org.drools.ruleflow.common.instance.ProcessInstance;
033: import org.drools.ruleflow.core.Connection;
034: import org.drools.ruleflow.core.Constraint;
035: import org.drools.ruleflow.core.EndNode;
036: import org.drools.ruleflow.core.Join;
037: import org.drools.ruleflow.core.RuleFlowProcess;
038: import org.drools.ruleflow.core.RuleSetNode;
039: import org.drools.ruleflow.core.Split;
040: import org.drools.ruleflow.core.StartNode;
041: import org.drools.ruleflow.core.impl.ConnectionImpl;
042: import org.drools.ruleflow.core.impl.EndNodeImpl;
043: import org.drools.ruleflow.core.impl.JoinImpl;
044: import org.drools.ruleflow.core.impl.RuleFlowProcessImpl;
045: import org.drools.ruleflow.core.impl.RuleSetNodeImpl;
046: import org.drools.ruleflow.core.impl.SplitImpl;
047: import org.drools.ruleflow.core.impl.StartNodeImpl;
048: import org.drools.ruleflow.instance.RuleFlowProcessInstance;
049: import org.drools.ruleflow.instance.impl.RuleFlowProcessInstanceImpl;
050: import org.drools.spi.Consequence;
051: import org.drools.spi.KnowledgeHelper;
052: import org.drools.spi.PropagationContext;
053:
054: /**
055: * @author mproctor
056: */
057:
058: public class RuleFlowGroupTest extends DroolsTestCase {
059:
060: public void testRuleFlowGroup() {
061: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
062:
063: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
064: .newStatefulSession();
065:
066: final InternalAgenda agenda = (InternalAgenda) workingMemory
067: .getAgenda();
068:
069: final List list = new ArrayList();
070:
071: // create the consequence
072: final Consequence consequence = new Consequence() {
073: /**
074: *
075: */
076: private static final long serialVersionUID = 400L;
077:
078: public void evaluate(KnowledgeHelper knowledgeHelper,
079: WorkingMemory workingMemory) {
080: list.add(knowledgeHelper.getRule());
081: }
082: };
083:
084: // create a rule for each rule flow groups
085: final Rule rule0 = new Rule("test-rule0");
086: rule0.setRuleFlowGroup("rule-flow-group-0");
087: rule0.setConsequence(consequence);
088:
089: final RuleTerminalNode node0 = new RuleTerminalNode(3,
090: new MockTupleSource(2), rule0, rule0.getLhs());
091:
092: final Rule rule1 = new Rule("test-rule1");
093: rule1.setRuleFlowGroup("rule-flow-group-1");
094: rule1.setConsequence(consequence);
095:
096: final RuleTerminalNode node1 = new RuleTerminalNode(4,
097: new MockTupleSource(2), rule1, rule1.getLhs());
098:
099: final Rule rule2 = new Rule("test-rule2");
100: rule2.setRuleFlowGroup("rule-flow-group-2");
101: rule2.setConsequence(consequence);
102: rule2.setSalience(new SalienceInteger(10));
103:
104: final RuleTerminalNode node2 = new RuleTerminalNode(5,
105: new MockTupleSource(2), rule2, rule2.getLhs());
106:
107: final Rule rule3 = new Rule("test-rule3");
108: rule3.setRuleFlowGroup("rule-flow-group-3");
109: rule3.setConsequence(consequence);
110:
111: final RuleTerminalNode node3 = new RuleTerminalNode(6,
112: new MockTupleSource(2), rule3, rule3.getLhs());
113:
114: final PropagationContext context0 = new PropagationContextImpl(
115: 0, PropagationContext.ASSERTION, rule0, null);
116:
117: // nodes
118: final StartNode start = new StartNodeImpl();
119: final RuleSetNode ruleSet0 = new RuleSetNodeImpl();
120: ruleSet0.setRuleFlowGroup("rule-flow-group-0");
121: final RuleSetNode ruleSet1 = new RuleSetNodeImpl();
122: ruleSet1.setRuleFlowGroup("rule-flow-group-1");
123: final RuleSetNode ruleSet2 = new RuleSetNodeImpl();
124: ruleSet2.setRuleFlowGroup("rule-flow-group-2");
125: final RuleSetNode ruleSet3 = new RuleSetNodeImpl();
126: ruleSet3.setRuleFlowGroup("rule-flow-group-3");
127: final Split split = new SplitImpl();
128: split.setType(Split.TYPE_AND);
129: final Join join = new JoinImpl();
130: join.setType(Join.TYPE_AND);
131: final EndNode end = new EndNodeImpl();
132: // connections
133: new ConnectionImpl(start, ruleSet0, Connection.TYPE_NORMAL);
134: new ConnectionImpl(ruleSet0, split, Connection.TYPE_NORMAL);
135: new ConnectionImpl(split, ruleSet1, Connection.TYPE_NORMAL);
136: new ConnectionImpl(split, ruleSet2, Connection.TYPE_NORMAL);
137: new ConnectionImpl(ruleSet1, join, Connection.TYPE_NORMAL);
138: new ConnectionImpl(ruleSet2, join, Connection.TYPE_NORMAL);
139: new ConnectionImpl(join, ruleSet3, Connection.TYPE_NORMAL);
140: new ConnectionImpl(ruleSet3, end, Connection.TYPE_NORMAL);
141:
142: // process
143: final RuleFlowProcess process = new RuleFlowProcessImpl();
144: process.addNode(start);
145: process.addNode(ruleSet0);
146: process.addNode(ruleSet1);
147: process.addNode(ruleSet2);
148: process.addNode(ruleSet3);
149: process.addNode(split);
150: process.addNode(join);
151: process.addNode(end);
152:
153: // proces instance
154: final RuleFlowProcessInstance processInstance = new RuleFlowProcessInstanceImpl();
155: processInstance.setWorkingMemory(workingMemory);
156: processInstance.setProcess(process);
157: assertEquals(ProcessInstance.STATE_PENDING, processInstance
158: .getState());
159:
160: final RuleFlowGroupImpl ruleFlowGroup0 = (RuleFlowGroupImpl) agenda
161: .getRuleFlowGroup("rule-flow-group-0");
162: final RuleFlowGroupImpl ruleFlowGroup1 = (RuleFlowGroupImpl) agenda
163: .getRuleFlowGroup("rule-flow-group-1");
164: final RuleFlowGroupImpl ruleFlowGroup2 = (RuleFlowGroupImpl) agenda
165: .getRuleFlowGroup("rule-flow-group-2");
166: final RuleFlowGroupImpl ruleFlowGroup3 = (RuleFlowGroupImpl) agenda
167: .getRuleFlowGroup("rule-flow-group-3");
168:
169: final ReteTuple tuple0 = new ReteTuple(new DefaultFactHandle(1,
170: "cheese"));
171: node0.assertTuple(tuple0, context0, workingMemory);
172:
173: final ReteTuple tuple1 = new ReteTuple(new DefaultFactHandle(1,
174: "cheese"));
175: node0.assertTuple(tuple1, context0, workingMemory);
176:
177: final ReteTuple tuple2 = new ReteTuple(new DefaultFactHandle(1,
178: "cheese"));
179: node1.assertTuple(tuple2, context0, workingMemory);
180:
181: final ReteTuple tuple3 = new ReteTuple(new DefaultFactHandle(1,
182: "cheese"));
183: node2.assertTuple(tuple3, context0, workingMemory);
184:
185: final ReteTuple tuple4 = new ReteTuple(new DefaultFactHandle(1,
186: "cheese"));
187: node3.assertTuple(tuple4, context0, workingMemory);
188:
189: // RuleFlowGroups should be populated, but the agenda shouldn't
190: assertEquals(2, ruleFlowGroup0.size());
191: assertEquals(1, ruleFlowGroup1.size());
192: assertEquals(1, ruleFlowGroup2.size());
193: assertEquals(1, ruleFlowGroup3.size());
194: assertEquals(0, agenda.agendaSize());
195:
196: // Activate process instance, the activations stay in the group,
197: // but should now also be in the Agenda
198: processInstance.start();
199: assertEquals(ProcessInstance.STATE_ACTIVE, processInstance
200: .getState());
201: assertEquals(2, ruleFlowGroup0.size());
202: assertEquals(2, agenda.agendaSize());
203:
204: // As we fire each rule they are removed from both the Agenda and the RuleFlowGroup
205: agenda.fireNextItem(null);
206: assertEquals(1, ruleFlowGroup0.size());
207: assertEquals(1, agenda.agendaSize());
208:
209: // on firing the last activation the child rule flow groups should
210: // activate and thus repopulate the agenda
211: agenda.fireNextItem(null);
212: workingMemory.executeQueuedActions();
213: assertEquals(0, ruleFlowGroup0.size());
214: assertEquals(1, ruleFlowGroup1.size());
215: assertEquals(1, ruleFlowGroup2.size());
216: assertEquals(2, agenda.agendaSize());
217:
218: // we set the salience higher on rule2, so it sould fire first and empty ruleFlowGroup2
219: agenda.fireNextItem(null);
220: assertEquals(1, ruleFlowGroup1.size());
221: assertEquals(0, ruleFlowGroup2.size());
222: assertEquals(1, agenda.agendaSize());
223:
224: // executing rule1, which should activate AND-join and thus group 3
225: agenda.fireNextItem(null);
226: workingMemory.executeQueuedActions();
227: assertEquals(0, ruleFlowGroup0.size());
228: assertEquals(0, ruleFlowGroup1.size());
229: assertEquals(0, ruleFlowGroup2.size());
230: assertEquals(1, ruleFlowGroup3.size());
231: assertEquals(1, agenda.agendaSize());
232:
233: // executing rule3, and finishing execution
234: agenda.fireNextItem(null);
235: workingMemory.executeQueuedActions();
236: assertEquals(0, ruleFlowGroup0.size());
237: assertEquals(0, ruleFlowGroup1.size());
238: assertEquals(0, ruleFlowGroup2.size());
239: assertEquals(0, ruleFlowGroup3.size());
240: assertEquals(0, agenda.agendaSize());
241: assertEquals(ProcessInstance.STATE_COMPLETED, processInstance
242: .getState());
243: }
244:
245: /** XOR split and join */
246: public void testRuleFlowGroup2() {
247: final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
248:
249: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
250: .newStatefulSession();
251:
252: final InternalAgenda agenda = (InternalAgenda) workingMemory
253: .getAgenda();
254:
255: final List list = new ArrayList();
256:
257: // create the consequence
258: final Consequence consequence = new Consequence() {
259: /**
260: *
261: */
262: private static final long serialVersionUID = 400L;
263:
264: public void evaluate(KnowledgeHelper knowledgeHelper,
265: WorkingMemory workingMemory) {
266: list.add(knowledgeHelper.getRule());
267: }
268: };
269:
270: // create a rule for each rule flow groups
271: final Rule rule0 = new Rule("test-rule0");
272: rule0.setRuleFlowGroup("rule-flow-group-0");
273: rule0.setConsequence(consequence);
274:
275: final RuleTerminalNode node0 = new RuleTerminalNode(3,
276: new MockTupleSource(2), rule0, rule0.getLhs());
277:
278: final Rule rule1 = new Rule("test-rule1");
279: rule1.setRuleFlowGroup("rule-flow-group-1");
280: rule1.setConsequence(consequence);
281:
282: final RuleTerminalNode node1 = new RuleTerminalNode(4,
283: new MockTupleSource(2), rule1, rule1.getLhs());
284:
285: final Rule rule2 = new Rule("test-rule2");
286: rule2.setRuleFlowGroup("rule-flow-group-2");
287: rule2.setConsequence(consequence);
288: rule2.setSalience(new SalienceInteger(10));
289:
290: final RuleTerminalNode node2 = new RuleTerminalNode(5,
291: new MockTupleSource(2), rule2, rule2.getLhs());
292:
293: final Rule rule3 = new Rule("test-rule3");
294: rule3.setRuleFlowGroup("rule-flow-group-3");
295: rule3.setConsequence(consequence);
296:
297: final RuleTerminalNode node3 = new RuleTerminalNode(6,
298: new MockTupleSource(2), rule3, rule3.getLhs());
299:
300: final PropagationContext context0 = new PropagationContextImpl(
301: 0, PropagationContext.ASSERTION, rule0, null);
302:
303: // nodes
304: final StartNode start = new StartNodeImpl();
305: final RuleSetNode ruleSet0 = new RuleSetNodeImpl();
306: ruleSet0.setRuleFlowGroup("rule-flow-group-0");
307: final RuleSetNode ruleSet1 = new RuleSetNodeImpl();
308: ruleSet1.setRuleFlowGroup("rule-flow-group-1");
309: final RuleSetNode ruleSet2 = new RuleSetNodeImpl();
310: ruleSet2.setRuleFlowGroup("rule-flow-group-2");
311: final RuleSetNode ruleSet3 = new RuleSetNodeImpl();
312: ruleSet3.setRuleFlowGroup("rule-flow-group-3");
313: final Split split = new SplitImpl();
314: split.setType(Split.TYPE_XOR);
315: final Join join = new JoinImpl();
316: join.setType(Join.TYPE_XOR);
317: final EndNode end = new EndNodeImpl();
318: // connections
319: new ConnectionImpl(start, ruleSet0, Connection.TYPE_NORMAL);
320: new ConnectionImpl(ruleSet0, split, Connection.TYPE_NORMAL);
321: Connection out1 = new ConnectionImpl(split, ruleSet1,
322: Connection.TYPE_NORMAL);
323: Connection out2 = new ConnectionImpl(split, ruleSet2,
324: Connection.TYPE_NORMAL);
325: new ConnectionImpl(ruleSet1, join, Connection.TYPE_NORMAL);
326: new ConnectionImpl(ruleSet2, join, Connection.TYPE_NORMAL);
327: new ConnectionImpl(join, ruleSet3, Connection.TYPE_NORMAL);
328: new ConnectionImpl(ruleSet3, end, Connection.TYPE_NORMAL);
329: Constraint constraint1 = new org.drools.ruleflow.core.impl.ConstraintImpl();
330: constraint1.setPriority(1);
331: split.setConstraint(out1, constraint1);
332: Constraint constraint2 = new org.drools.ruleflow.core.impl.ConstraintImpl();
333: constraint2.setPriority(2);
334: split.setConstraint(out2, constraint2);
335:
336: // process
337: final RuleFlowProcess process = new RuleFlowProcessImpl();
338: process.setId("1");
339: process.addNode(start);
340: process.addNode(ruleSet0);
341: process.addNode(ruleSet1);
342: process.addNode(ruleSet2);
343: process.addNode(ruleSet3);
344: process.addNode(split);
345: process.addNode(join);
346: process.addNode(end);
347:
348: // rules for split
349: final Rule splitRule1 = new Rule("RuleFlow-1-" + split.getId()
350: + "-" + ruleSet1.getId());
351: splitRule1.setRuleFlowGroup("DROOLS_SYSTEM");
352: splitRule1.setConsequence(consequence);
353:
354: final RuleTerminalNode splitNode1 = new RuleTerminalNode(7,
355: new MockTupleSource(2), splitRule1, splitRule1.getLhs());
356:
357: final Rule splitRule2 = new Rule("RuleFlow-1-" + split.getId()
358: + "-" + ruleSet2.getId());
359: splitRule2.setRuleFlowGroup("DROOLS_SYSTEM");
360: splitRule2.setConsequence(consequence);
361:
362: final RuleTerminalNode splitNode2 = new RuleTerminalNode(8,
363: new MockTupleSource(2), splitRule2, splitRule2.getLhs());
364:
365: // proces instance
366: final RuleFlowProcessInstance processInstance = new RuleFlowProcessInstanceImpl();
367: processInstance.setWorkingMemory(workingMemory);
368: processInstance.setProcess(process);
369: assertEquals(ProcessInstance.STATE_PENDING, processInstance
370: .getState());
371:
372: final RuleFlowGroupImpl ruleFlowGroup0 = (RuleFlowGroupImpl) agenda
373: .getRuleFlowGroup("rule-flow-group-0");
374: final RuleFlowGroupImpl ruleFlowGroup1 = (RuleFlowGroupImpl) agenda
375: .getRuleFlowGroup("rule-flow-group-1");
376: final RuleFlowGroupImpl ruleFlowGroup2 = (RuleFlowGroupImpl) agenda
377: .getRuleFlowGroup("rule-flow-group-2");
378: final RuleFlowGroupImpl ruleFlowGroup3 = (RuleFlowGroupImpl) agenda
379: .getRuleFlowGroup("rule-flow-group-3");
380:
381: final ReteTuple tuple0 = new ReteTuple(new DefaultFactHandle(1,
382: "cheese"));
383: node0.assertTuple(tuple0, context0, workingMemory);
384:
385: final ReteTuple tuple1 = new ReteTuple(new DefaultFactHandle(1,
386: "cheese"));
387: node0.assertTuple(tuple1, context0, workingMemory);
388:
389: final ReteTuple tuple2 = new ReteTuple(new DefaultFactHandle(1,
390: "cheese"));
391: node1.assertTuple(tuple2, context0, workingMemory);
392:
393: final ReteTuple tuple3 = new ReteTuple(new DefaultFactHandle(1,
394: "cheese"));
395: node2.assertTuple(tuple3, context0, workingMemory);
396:
397: final ReteTuple tuple4 = new ReteTuple(new DefaultFactHandle(1,
398: "cheese"));
399: node3.assertTuple(tuple4, context0, workingMemory);
400:
401: final ReteTuple splitTuple1 = new ReteTuple(
402: new DefaultFactHandle(1, "cheese"));
403: splitNode1.assertTuple(splitTuple1, context0, workingMemory);
404:
405: final ReteTuple splitTuple2 = new ReteTuple(
406: new DefaultFactHandle(1, "cheese"));
407: splitNode2.assertTuple(splitTuple2, context0, workingMemory);
408:
409: final RuleFlowGroupImpl systemRuleFlowGroup = (RuleFlowGroupImpl) agenda
410: .getRuleFlowGroup("DROOLS_SYSTEM");
411:
412: // RuleFlowGroups should be populated, but the agenda shouldn't
413: assertEquals(2, ruleFlowGroup0.size());
414: assertEquals(1, ruleFlowGroup1.size());
415: assertEquals(1, ruleFlowGroup2.size());
416: assertEquals(1, ruleFlowGroup3.size());
417: assertEquals(2, systemRuleFlowGroup.size());
418: assertEquals(0, agenda.agendaSize());
419:
420: // Activate process instance, the activations stay in the group,
421: // but should now also be in the Agenda
422: processInstance.start();
423: assertEquals(ProcessInstance.STATE_ACTIVE, processInstance
424: .getState());
425: assertEquals(2, ruleFlowGroup0.size());
426: assertEquals(2, agenda.agendaSize());
427:
428: // As we fire each rule they are removed from both the Agenda and the RuleFlowGroup
429: agenda.fireNextItem(null);
430: assertEquals(1, ruleFlowGroup0.size());
431: assertEquals(1, agenda.agendaSize());
432:
433: // XOR split should activate group1
434: agenda.fireNextItem(null);
435: workingMemory.executeQueuedActions();
436: assertEquals(0, ruleFlowGroup0.size());
437: assertEquals(1, ruleFlowGroup1.size());
438: assertEquals(1, ruleFlowGroup2.size());
439: assertEquals(1, agenda.agendaSize());
440:
441: // executing group1, XOR join should activate group3
442: agenda.fireNextItem(null);
443: workingMemory.executeQueuedActions();
444: assertEquals(0, ruleFlowGroup1.size());
445: assertEquals(1, ruleFlowGroup2.size());
446: assertEquals(1, ruleFlowGroup3.size());
447: assertEquals(1, agenda.agendaSize());
448:
449: // executing rule3, and finishing execution
450: agenda.fireNextItem(null);
451: workingMemory.executeQueuedActions();
452: assertEquals(0, ruleFlowGroup0.size());
453: assertEquals(0, ruleFlowGroup1.size());
454: assertEquals(1, ruleFlowGroup2.size());
455: assertEquals(0, ruleFlowGroup3.size());
456: assertEquals(0, agenda.agendaSize());
457: assertEquals(ProcessInstance.STATE_COMPLETED, processInstance
458: .getState());
459: }
460: }
|