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 org.drools.Agenda;
020: import org.drools.Cheese;
021: import org.drools.DroolsTestCase;
022: import org.drools.FactException;
023: import org.drools.FactHandle;
024: import org.drools.RuleBase;
025: import org.drools.RuleBaseConfiguration;
026: import org.drools.RuleBaseFactory;
027: import org.drools.WorkingMemory;
028: import org.drools.RuleBaseConfiguration.LogicalOverride;
029: import org.drools.base.ClassObjectType;
030: import org.drools.base.ShadowProxy;
031: import org.drools.common.DefaultFactHandle;
032: import org.drools.common.InternalAgenda;
033: import org.drools.common.InternalRuleBase;
034: import org.drools.common.InternalWorkingMemory;
035: import org.drools.common.PropagationContextImpl;
036: import org.drools.reteoo.ReteooBuilder.IdGenerator;
037: import org.drools.rule.Rule;
038: import org.drools.spi.Consequence;
039: import org.drools.spi.KnowledgeHelper;
040: import org.drools.spi.PropagationContext;
041:
042: public class LogicalAssertionTest extends DroolsTestCase {
043:
044: public void testSingleLogicalRelationship() throws Exception {
045: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
046: .newRuleBase();
047: IdGenerator idGenerator = ruleBase.getReteooBuilder()
048: .getIdGenerator();
049:
050: final Rete rete = ruleBase.getRete();
051: // create a RuleBase with a single ObjectTypeNode we attach a
052: // MockObjectSink so we can detect assertions and retractions
053: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
054: idGenerator.getNextId(), new ClassObjectType(
055: String.class), rete, 3);
056: objectTypeNode.attach();
057: final MockObjectSink sink = new MockObjectSink();
058: objectTypeNode.addObjectSink(sink);
059:
060: final Rule rule1 = new Rule("test-rule1");
061: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
062: .getNextId(), new MockTupleSource(idGenerator
063: .getNextId()), rule1, rule1.getLhs());
064: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
065: .newStatefulSession();
066:
067: final InternalAgenda agenda = (InternalAgenda) workingMemory
068: .getAgenda();
069:
070: final Consequence consequence = new Consequence() {
071: /**
072: *
073: */
074: private static final long serialVersionUID = 400L;
075:
076: public void evaluate(KnowledgeHelper knowledgeHelper,
077: WorkingMemory workingMemory) {
078: // do nothing
079: }
080: };
081:
082: rule1.setConsequence(consequence);
083:
084: final DefaultFactHandle handle1 = (DefaultFactHandle) workingMemory
085: .insert("o1");
086: final ReteTuple tuple1 = new ReteTuple(handle1);
087:
088: final PropagationContext context1 = new PropagationContextImpl(
089: 0, PropagationContext.ASSERTION, null, null);
090:
091: // Test single activation for a single logical assertions
092: node.assertTuple(tuple1, context1, workingMemory);
093:
094: final String logicalString = new String("logical");
095: FactHandle logicalHandle = workingMemory.insert(logicalString,
096: false, true, rule1, tuple1.getActivation());
097: // Retract the tuple and test the logically asserted fact was also retracted
098: node.retractTuple(tuple1, context1, workingMemory);
099:
100: workingMemory.executeQueuedActions();
101:
102: assertLength(1, sink.getRetracted());
103:
104: Object[] values = (Object[]) sink.getRetracted().get(0);
105:
106: assertSame(logicalHandle, values[0]);
107:
108: // Test single activation for a single logical assertions. This also
109: // tests that logical assertions live on after the related Activation
110: // has fired.
111: node.assertTuple(tuple1, context1, workingMemory);
112: logicalHandle = workingMemory.insert(logicalString, false,
113: true, rule1, tuple1.getActivation());
114:
115: agenda.fireNextItem(null);
116:
117: node.retractTuple(tuple1, context1, workingMemory);
118:
119: workingMemory.executeQueuedActions();
120:
121: assertLength(2, sink.getRetracted());
122:
123: values = (Object[]) sink.getRetracted().get(1);
124:
125: assertSame(logicalHandle, values[0]);
126: }
127:
128: public void testEqualsMap() throws Exception {
129: // create a RuleBase with a single ObjectTypeNode we attach a
130: // MockObjectSink so w can detect assertions and retractions
131: final Rule rule1 = new Rule("test-rule1");
132:
133: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
134: .newRuleBase();
135: IdGenerator idGenerator = ruleBase.getReteooBuilder()
136: .getIdGenerator();
137:
138: final Rete rete = ruleBase.getRete();
139: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
140: idGenerator.getNextId(), new ClassObjectType(
141: String.class), rete, 3);
142: objectTypeNode.attach();
143: final MockObjectSink sink = new MockObjectSink();
144: objectTypeNode.addObjectSink(sink);
145:
146: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
147: .getNextId(), new MockTupleSource(idGenerator
148: .getNextId()), rule1, rule1.getLhs());
149:
150: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
151: .newStatefulSession();
152:
153: final Agenda agenda = workingMemory.getAgenda();
154:
155: final Consequence consequence = new Consequence() {
156: /**
157: *
158: */
159: private static final long serialVersionUID = 400L;
160:
161: public void evaluate(KnowledgeHelper knowledgeHelper,
162: WorkingMemory workingMemory) {
163: // do nothing
164: }
165: };
166: rule1.setConsequence(consequence);
167:
168: final DefaultFactHandle handle1 = new DefaultFactHandle(1,
169: "cheese");
170: final ReteTuple tuple1 = new ReteTuple(handle1);
171:
172: final PropagationContext context1 = new PropagationContextImpl(
173: 0, PropagationContext.ASSERTION, null, null);
174:
175: // Test single activation for a single logical assertions
176: node.assertTuple(tuple1, context1, workingMemory);
177:
178: final String logicalString1 = new String("logical");
179: FactHandle logicalHandle1 = workingMemory.insert(
180: logicalString1, false, true, rule1, tuple1
181: .getActivation());
182:
183: final String logicalString2 = new String("logical");
184: FactHandle logicalHandle2 = workingMemory.insert(
185: logicalString2, false, true, rule1, tuple1
186: .getActivation());
187:
188: assertSame(logicalHandle1, logicalHandle2);
189:
190: // little sanity check using normal assert
191: logicalHandle1 = workingMemory.insert(logicalString1);
192: logicalHandle2 = workingMemory.insert(logicalString2);
193:
194: // If assert behavior in working memory is IDENTITY,
195: // returned handles must not be the same
196: if (RuleBaseConfiguration.AssertBehaviour.IDENTITY == ((ReteooRuleBase) ruleBase)
197: .getConfiguration().getAssertBehaviour()) {
198:
199: assertNotSame(logicalHandle1, logicalHandle2);
200: } else {
201: // in case behavior is EQUALS, handles should be the same
202: assertSame(logicalHandle1, logicalHandle2);
203: }
204: }
205:
206: /**
207: * This tests that Stated asserts always take precedent
208: *
209: * @throws Exception
210: */
211: public void testStatedOverrideDiscard() throws Exception {
212: // create a RuleBase with a single ObjectTypeNode we attach a
213: // MockObjectSink so we can detect assertions and retractions
214: final Rule rule1 = new Rule("test-rule1");
215: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
216: .newRuleBase();
217: IdGenerator idGenerator = ruleBase.getReteooBuilder()
218: .getIdGenerator();
219:
220: final Rete rete = ruleBase.getRete();
221: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
222: idGenerator.getNextId(), new ClassObjectType(
223: String.class), rete, 3);
224: objectTypeNode.attach();
225: final MockObjectSink sink = new MockObjectSink();
226: objectTypeNode.addObjectSink(sink);
227: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
228: .getNextId(), new MockTupleSource(idGenerator
229: .getNextId()), rule1, rule1.getLhs());
230:
231: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
232: .newStatefulSession();
233:
234: final Agenda agenda = workingMemory.getAgenda();
235:
236: final Consequence consequence = new Consequence() {
237: /**
238: *
239: */
240: private static final long serialVersionUID = 400L;
241:
242: public void evaluate(KnowledgeHelper knowledgeHelper,
243: WorkingMemory workingMemory) {
244: // do nothing
245: }
246: };
247: rule1.setConsequence(consequence);
248:
249: final DefaultFactHandle handle1 = new DefaultFactHandle(1,
250: "cheese");
251: final ReteTuple tuple1 = new ReteTuple(handle1);
252:
253: final PropagationContext context1 = new PropagationContextImpl(
254: 0, PropagationContext.ASSERTION, null, null);
255:
256: // Test that a STATED assertion overrides a logical assertion
257: node.assertTuple(tuple1, context1, workingMemory);
258:
259: String logicalString1 = new String("logical");
260: FactHandle logicalHandle1 = workingMemory.insert(
261: logicalString1, false, true, rule1, tuple1
262: .getActivation());
263:
264: // This assertion is stated and should override any previous justified
265: // "equals" objects.
266: String logicalString2 = new String("logical");
267: FactHandle logicalHandle2 = workingMemory
268: .insert(logicalString2);
269:
270: node.retractTuple(tuple1, context1, workingMemory);
271:
272: assertLength(0, sink.getRetracted());
273:
274: // we override and discard the original logical object
275: assertSame(logicalHandle2, logicalHandle1);
276:
277: // so while new STATED assertion is equal
278: assertEquals(logicalString1, workingMemory
279: .getObject(logicalHandle2));
280: // they are not identity same
281: assertNotSame(logicalString1, workingMemory
282: .getObject(logicalHandle2));
283:
284: // Test that a logical assertion cannot override a STATED assertion
285: node.assertTuple(tuple1, context1, workingMemory);
286:
287: logicalString2 = new String("logical");
288: logicalHandle2 = workingMemory.insert(logicalString2);
289:
290: // This logical assertion will be ignored as there is already
291: // an equals STATED assertion.
292: logicalString1 = new String("logical");
293: logicalHandle1 = workingMemory.insert(logicalString1, false,
294: true, rule1, tuple1.getActivation());
295:
296: assertNull(logicalHandle1);
297:
298: // Already identify same so return previously assigned handle
299: logicalHandle1 = workingMemory.insert(logicalString2, false,
300: false, rule1, tuple1.getActivation());
301: // return the matched handle
302:
303: assertSame(logicalHandle2, logicalHandle1);
304:
305: node.retractTuple(tuple1, context1, workingMemory);
306:
307: assertLength(0, sink.getRetracted());
308:
309: // Should keep the same handle when overriding
310: assertSame(logicalHandle1, logicalHandle2);
311:
312: // so while new STATED assertion is equal
313: assertEquals(logicalString1, workingMemory
314: .getObject(logicalHandle2));
315:
316: // they are not identity same
317: assertNotSame(logicalString1, workingMemory
318: .getObject(logicalHandle2));
319:
320: }
321:
322: /**
323: * This tests that Stated asserts always take precedent
324: *
325: * @throws Exception
326: */
327: public void testStatedOverridePreserve() throws Exception {
328: // create a RuleBase with a single ObjectTypeNode we attach a
329: // MockObjectSink so we can detect assertions and retractions
330: final Rule rule1 = new Rule("test-rule1");
331: RuleBaseConfiguration conf = new RuleBaseConfiguration();
332: conf.setLogicalOverride(LogicalOverride.PRESERVE);
333: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
334: .newRuleBase(conf);
335: IdGenerator idGenerator = ruleBase.getReteooBuilder()
336: .getIdGenerator();
337:
338: final Rete rete = ruleBase.getRete();
339: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
340: idGenerator.getNextId(), new ClassObjectType(
341: String.class), rete, 3);
342: objectTypeNode.attach();
343: final MockObjectSink sink = new MockObjectSink();
344: objectTypeNode.addObjectSink(sink);
345: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
346: .getNextId(), new MockTupleSource(idGenerator
347: .getNextId()), rule1, rule1.getLhs());
348: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
349: .newStatefulSession();
350:
351: final Agenda agenda = workingMemory.getAgenda();
352:
353: final Consequence consequence = new Consequence() {
354: /**
355: *
356: */
357: private static final long serialVersionUID = 400L;
358:
359: public void evaluate(KnowledgeHelper knowledgeHelper,
360: WorkingMemory workingMemory) {
361: // do nothing
362: }
363: };
364: rule1.setConsequence(consequence);
365:
366: final DefaultFactHandle handle1 = new DefaultFactHandle(1,
367: "cheese");
368: final ReteTuple tuple1 = new ReteTuple(handle1);
369:
370: final PropagationContext context1 = new PropagationContextImpl(
371: 0, PropagationContext.ASSERTION, null, null);
372:
373: // Test that a STATED assertion overrides a logical assertion
374: node.assertTuple(tuple1, context1, workingMemory);
375:
376: final String logicalString1 = new String("logical");
377: final FactHandle logicalHandle1 = workingMemory.insert(
378: logicalString1, false, true, rule1, tuple1
379: .getActivation());
380:
381: // This assertion is stated and should override any previous justified
382: // "equals" objects.
383: String logicalString2 = new String("logical");
384: FactHandle logicalHandle2 = workingMemory
385: .insert(logicalString2);
386:
387: node.retractTuple(tuple1, context1, workingMemory);
388:
389: assertLength(0, sink.getRetracted());
390:
391: assertNotSame(logicalHandle2, logicalHandle1);
392:
393: // so while new STATED assertion is equal
394: assertEquals(workingMemory.getObject(logicalHandle1),
395: workingMemory.getObject(logicalHandle2));
396:
397: // they are not identity same
398: assertNotSame(workingMemory.getObject(logicalHandle1),
399: workingMemory.getObject(logicalHandle2));
400:
401: // Test that a logical assertion cannot override a STATED assertion
402: node.assertTuple(tuple1, context1, workingMemory);
403:
404: logicalString2 = new String("logical");
405: logicalHandle2 = workingMemory.insert(logicalString2);
406: }
407:
408: public void testRetract() throws Exception {
409: // create a RuleBase with a single ObjectTypeNode we attach a
410: // MockObjectSink so we can detect assertions and retractions
411: final Rule rule1 = new Rule("test-rule1");
412: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
413: .newRuleBase();
414: IdGenerator idGenerator = ruleBase.getReteooBuilder()
415: .getIdGenerator();
416:
417: final Rete rete = ruleBase.getRete();
418: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
419: idGenerator.getNextId(), new ClassObjectType(
420: String.class), rete, 3);
421: objectTypeNode.attach();
422: final MockObjectSink sink = new MockObjectSink();
423: objectTypeNode.addObjectSink(sink);
424: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
425: .getNextId(), new MockTupleSource(idGenerator
426: .getNextId()), rule1, rule1.getLhs());
427:
428: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
429: .newStatefulSession();
430:
431: final Consequence consequence = new Consequence() {
432: /**
433: *
434: */
435: private static final long serialVersionUID = 400L;
436:
437: public void evaluate(KnowledgeHelper knowledgeHelper,
438: WorkingMemory workingMemory) {
439: // do nothing
440: }
441: };
442:
443: // create the first activation which will justify the fact "logical"
444: rule1.setConsequence(consequence);
445:
446: final DefaultFactHandle handle1 = new DefaultFactHandle(1,
447: "cheese");
448: final ReteTuple tuple1 = new ReteTuple(handle1);
449:
450: final PropagationContext context = new PropagationContextImpl(
451: 0, PropagationContext.ASSERTION, null, null);
452:
453: node.assertTuple(tuple1, context, workingMemory);
454:
455: // Assert the logical "logical" fact
456: final String logicalString1 = new String("logical");
457: final FactHandle logicalHandle1 = workingMemory.insert(
458: logicalString1, false, true, rule1, tuple1
459: .getActivation());
460:
461: // create the second activation to justify the "logical" fact
462: final Rule rule2 = new Rule("test-rule2");
463: final RuleTerminalNode node2 = new RuleTerminalNode(idGenerator
464: .getNextId(), new MockTupleSource(3), rule2, rule2
465: .getLhs());
466: rule2.setConsequence(consequence);
467:
468: final DefaultFactHandle handle2 = new DefaultFactHandle(2,
469: "cheese");
470: final ReteTuple tuple2 = new ReteTuple(handle2);
471:
472: node.assertTuple(tuple2, context, workingMemory);
473:
474: node2.assertTuple(tuple2, context, workingMemory);
475:
476: // Assert the logical "logical" fact
477: final String logicalString2 = new String("logical");
478: final FactHandle logicalHandle2 = workingMemory.insert(
479: logicalString2, false, true, rule2, tuple2
480: .getActivation());
481:
482: // "logical" should only appear once
483: assertLength(1, workingMemory.getTruthMaintenanceSystem()
484: .getJustifiedMap().values());
485:
486: // retract the logical object
487: workingMemory.retract(logicalHandle2);
488:
489: // The logical object should never appear
490: assertLength(0, workingMemory.getTruthMaintenanceSystem()
491: .getJustifiedMap().values());
492:
493: }
494:
495: public void testMultipleLogicalRelationships() throws FactException {
496: final Rule rule1 = new Rule("test-rule1");
497: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
498: .newRuleBase();
499: IdGenerator idGenerator = ruleBase.getReteooBuilder()
500: .getIdGenerator();
501:
502: final Rete rete = ruleBase.getRete();
503:
504: // Create a RuleBase with a single ObjectTypeNode we attach a
505: // MockObjectSink so we can detect assertions and retractions
506: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
507: idGenerator.getNextId(), new ClassObjectType(
508: String.class), rete, 3);
509: objectTypeNode.attach();
510: final MockObjectSink sink = new MockObjectSink();
511: objectTypeNode.addObjectSink(sink);
512: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
513: .getNextId(), new MockTupleSource(idGenerator
514: .getNextId()), rule1, rule1.getLhs());
515: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
516: .newStatefulSession();
517:
518: final Agenda agenda = workingMemory.getAgenda();
519:
520: final Consequence consequence = new Consequence() {
521: /**
522: *
523: */
524: private static final long serialVersionUID = 400L;
525:
526: public void evaluate(KnowledgeHelper knowledgeHelper,
527: WorkingMemory workingMemory) {
528: // do nothing
529: }
530: };
531:
532: // Create first justifier
533: rule1.setConsequence(consequence);
534:
535: final DefaultFactHandle handle1 = new DefaultFactHandle(1,
536: "cheese");
537: final ReteTuple tuple1 = new ReteTuple(handle1);
538:
539: final PropagationContext context1 = new PropagationContextImpl(
540: 0, PropagationContext.ASSERTION, null, null);
541: // get the activation onto the agenda
542: node.assertTuple(tuple1, context1, workingMemory);
543:
544: // Create the second justifer
545: final Rule rule2 = new Rule("test-rule2");
546: final RuleTerminalNode node2 = new RuleTerminalNode(idGenerator
547: .getNextId(), new MockTupleSource(idGenerator
548: .getNextId()), rule2, rule2.getLhs());
549: rule2.setConsequence(consequence);
550:
551: final DefaultFactHandle handle2 = new DefaultFactHandle(2,
552: "cheese");
553: final ReteTuple tuple2 = new ReteTuple(handle2);
554:
555: final PropagationContext context2 = new PropagationContextImpl(
556: 0, PropagationContext.ASSERTION, null, null);
557:
558: // get the activations onto the agenda
559: node2.assertTuple(tuple2, context2, workingMemory);
560:
561: // Create the first justifieable relationship
562: final String logicalString1 = new String("logical");
563: final FactHandle logicalHandle1 = workingMemory.insert(
564: logicalString1, false, true, rule1, tuple1
565: .getActivation());
566:
567: // Create the second justifieable relationship
568: final String logicalString2 = new String("logical");
569: final FactHandle logicalHandle2 = workingMemory.insert(
570: logicalString2, false, true, rule2, tuple2
571: .getActivation());
572:
573: // "logical" should only appear once
574: assertLength(1, workingMemory.getTruthMaintenanceSystem()
575: .getJustifiedMap().values());
576:
577: // Now lets cancel the first activation
578: node2.retractTuple(tuple2, context2, workingMemory);
579:
580: workingMemory.executeQueuedActions();
581:
582: // because this logical fact has two relationships it shouldn't retract yet
583: assertLength(0, sink.getRetracted());
584:
585: // check "logical" is still in the system
586: assertLength(1, workingMemory.getTruthMaintenanceSystem()
587: .getJustifiedMap().values());
588:
589: // now remove that final justification
590: node.retractTuple(tuple1, context1, workingMemory);
591:
592: workingMemory.executeQueuedActions();
593:
594: // Should cause the logical fact to be retracted
595: assertLength(1, sink.getRetracted());
596:
597: // "logical" fact should no longer be in the system
598: assertLength(0, workingMemory.getTruthMaintenanceSystem()
599: .getJustifiedMap().values());
600: }
601:
602: /**
603: * This tests that when multiple not identical, but equals facts, are asserted
604: * into WM, only when all are removed, a logical assert will succeed
605: *
606: * @throws Exception
607: */
608: public void testMultipleAssert() throws Exception {
609: // create a RuleBase with a single ObjectTypeNode we attach a
610: // MockObjectSink so we can detect assertions and retractions
611: final Rule rule1 = new Rule("test-rule1");
612: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
613: .newRuleBase();
614: IdGenerator idGenerator = ruleBase.getReteooBuilder()
615: .getIdGenerator();
616:
617: final Rete rete = ruleBase.getRete();
618: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
619: idGenerator.getNextId(), new ClassObjectType(
620: String.class), rete, 3);
621: objectTypeNode.attach();
622: final MockObjectSink sink = new MockObjectSink();
623: objectTypeNode.addObjectSink(sink);
624: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
625: .getNextId(), new MockTupleSource(idGenerator
626: .getNextId()), rule1, rule1.getLhs());
627:
628: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
629: .newStatefulSession();
630:
631: final Agenda agenda = workingMemory.getAgenda();
632:
633: final Consequence consequence = new Consequence() {
634: /**
635: *
636: */
637: private static final long serialVersionUID = 400L;
638:
639: public void evaluate(KnowledgeHelper knowledgeHelper,
640: WorkingMemory workingMemory) {
641: // do nothing
642: }
643: };
644: rule1.setConsequence(consequence);
645:
646: final DefaultFactHandle handle1 = new DefaultFactHandle(1,
647: "cheese");
648: final ReteTuple tuple1 = new ReteTuple(handle1);
649:
650: final PropagationContext context1 = new PropagationContextImpl(
651: 0, PropagationContext.ASSERTION, null, null);
652:
653: // Assert multiple stated objects
654: node.assertTuple(tuple1, context1, workingMemory);
655:
656: final String statedString1 = new String("logical");
657: final FactHandle statedHandle1 = workingMemory
658: .insert(statedString1);
659:
660: final String statedString2 = new String("logical");
661: final FactHandle statedHandle2 = workingMemory
662: .insert(statedString2);
663:
664: // This assertion is logical should fail as there is previous stated objects
665: final String logicalString3 = new String("logical");
666: FactHandle logicalHandle3 = workingMemory.insert(
667: logicalString3, false, true, rule1, tuple1
668: .getActivation());
669:
670: // Checks that previous LogicalAssert failed
671: assertNull(logicalHandle3);
672:
673: // If assert behavior in working memory is IDENTITY,
674: // we need to retract object 2 times before being able to
675: // succesfully logically assert a new fact
676: if (RuleBaseConfiguration.AssertBehaviour.IDENTITY == ((ReteooRuleBase) ruleBase)
677: .getConfiguration().getAssertBehaviour()) {
678:
679: workingMemory.retract(statedHandle2);
680:
681: logicalHandle3 = workingMemory.insert(logicalString3,
682: false, true, rule1, tuple1.getActivation());
683:
684: // Checks that previous LogicalAssert failed
685: assertNull(logicalHandle3);
686: }
687:
688: workingMemory.retract(statedHandle1);
689:
690: logicalHandle3 = workingMemory.insert(logicalString3, false,
691: true, rule1, tuple1.getActivation());
692:
693: // Checks that previous LogicalAssert succeeded as there are no more
694: // stated strings in the working memory
695: assertNotNull(logicalHandle3);
696:
697: }
698:
699: /**
700: * This test checks that truth maintenance is correctly maintained for modified objects
701: */
702: public void testMutableObject() {
703: // create a RuleBase with a single ObjectTypeNode we attach a
704: // MockObjectSink so we can detect assertions and retractions
705: final Rule rule1 = new Rule("test-rule1");
706: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
707: .newRuleBase();
708: IdGenerator idGenerator = ruleBase.getReteooBuilder()
709: .getIdGenerator();
710:
711: final Rete rete = ruleBase.getRete();
712: final ObjectTypeNode objectTypeNode = new ObjectTypeNode(
713: idGenerator.getNextId(), new ClassObjectType(
714: String.class), rete, 3);
715: objectTypeNode.attach();
716: final MockObjectSink sink = new MockObjectSink();
717: objectTypeNode.addObjectSink(sink);
718: final RuleTerminalNode node = new RuleTerminalNode(idGenerator
719: .getNextId(), new MockTupleSource(idGenerator
720: .getNextId()), rule1, rule1.getLhs());
721: final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) ruleBase
722: .newStatefulSession();
723:
724: final Agenda agenda = workingMemory.getAgenda();
725:
726: final Consequence consequence = new Consequence() {
727: /**
728: *
729: */
730: private static final long serialVersionUID = 400L;
731:
732: public void evaluate(KnowledgeHelper knowledgeHelper,
733: WorkingMemory workingMemory) {
734: // do nothing
735: }
736: };
737: rule1.setConsequence(consequence);
738:
739: final DefaultFactHandle handle1 = new DefaultFactHandle(1,
740: "cheese");
741: final ReteTuple tuple1 = new ReteTuple(handle1);
742:
743: final PropagationContext context1 = new PropagationContextImpl(
744: 0, PropagationContext.ASSERTION, null, null);
745:
746: // Test that a STATED assertion overrides a logical assertion
747: node.assertTuple(tuple1, context1, workingMemory);
748:
749: final Cheese cheese = new Cheese("brie", 10);
750: final FactHandle cheeseHandle = workingMemory.insert(cheese,
751: false, true, rule1, tuple1.getActivation());
752:
753: cheese.setType("cheddar");
754: cheese.setPrice(20);
755:
756: assertEquals(1, workingMemory.getTruthMaintenanceSystem()
757: .getJustifiedMap().size());
758: assertEquals(1, workingMemory.getTruthMaintenanceSystem()
759: .getAssertMap().size());
760:
761: workingMemory.retract(cheeseHandle);
762:
763: assertEquals(0, workingMemory.getTruthMaintenanceSystem()
764: .getJustifiedMap().size());
765: assertEquals(0, workingMemory.getTruthMaintenanceSystem()
766: .getAssertMap().size());
767: }
768:
769: private Object unwrapShadow(Object object) {
770: if (object instanceof ShadowProxy) {
771: return ((ShadowProxy) object).getShadowedObject();
772: } else {
773: return object;
774: }
775: }
776: }
|