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.lang.reflect.Field;
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.drools.DroolsTestCase;
024: import org.drools.RuleBaseConfiguration;
025: import org.drools.RuleBaseFactory;
026: import org.drools.common.DefaultBetaConstraints;
027: import org.drools.common.DefaultFactHandle;
028: import org.drools.common.InternalFactHandle;
029: import org.drools.common.PropagationContextImpl;
030: import org.drools.rule.Rule;
031: import org.drools.spi.BetaNodeFieldConstraint;
032: import org.drools.spi.MockConstraint;
033: import org.drools.spi.PropagationContext;
034: import org.drools.util.FactEntry;
035: import org.drools.util.Iterator;
036:
037: public class JoinNodeTest extends DroolsTestCase {
038: Rule rule;
039: PropagationContext context;
040: ReteooWorkingMemory workingMemory;
041: MockObjectSource objectSource;
042: MockTupleSource tupleSource;
043: MockTupleSink sink;
044: BetaNode node;
045: BetaMemory memory;
046: MockConstraint constraint = new MockConstraint();
047:
048: /**
049: * Setup the BetaNode used in each of the tests
050: */
051: public void setUp() {
052: this .rule = new Rule("test-rule");
053: this .context = new PropagationContextImpl(0,
054: PropagationContext.ASSERTION, null, null);
055: this .workingMemory = new ReteooWorkingMemory(1,
056: (ReteooRuleBase) RuleBaseFactory.newRuleBase());
057:
058: this .tupleSource = new MockTupleSource(4);
059: this .objectSource = new MockObjectSource(4);
060: this .sink = new MockTupleSink();
061:
062: final RuleBaseConfiguration configuration = new RuleBaseConfiguration();
063:
064: this .node = new JoinNode(
065: 15,
066: this .tupleSource,
067: this .objectSource,
068: new DefaultBetaConstraints(
069: new BetaNodeFieldConstraint[] { this .constraint },
070: configuration));
071:
072: this .node.addTupleSink(this .sink);
073:
074: this .memory = (BetaMemory) this .workingMemory
075: .getNodeMemory(this .node);
076:
077: // check memories are empty
078: assertEquals(0, this .memory.getTupleMemory().size());
079: assertEquals(0, this .memory.getFactHandleMemory().size());
080:
081: }
082:
083: public void testAttach() throws Exception {
084: final Field objectFfield = ObjectSource.class
085: .getDeclaredField("sink");
086: objectFfield.setAccessible(true);
087: ObjectSinkPropagator objectSink = (ObjectSinkPropagator) objectFfield
088: .get(this .objectSource);
089:
090: final Field tupleField = TupleSource.class
091: .getDeclaredField("sink");
092: tupleField.setAccessible(true);
093: TupleSinkPropagator tupleSink = (TupleSinkPropagator) tupleField
094: .get(this .tupleSource);
095:
096: assertEquals(15, this .node.getId());
097:
098: assertNotNull(objectSink);
099: assertNotNull(tupleSink);
100:
101: this .node.attach();
102:
103: objectSink = (ObjectSinkPropagator) objectFfield
104: .get(this .objectSource);
105: tupleSink = (TupleSinkPropagator) tupleField
106: .get(this .tupleSource);
107:
108: assertEquals(1, objectSink.getSinks().length);
109:
110: assertEquals(1, tupleSink.getSinks().length);
111:
112: assertSame(this .node, objectSink.getSinks()[0]);
113:
114: assertSame(this .node, tupleSink.getSinks()[0]);
115: }
116:
117: public void testMemory() {
118: final ReteooWorkingMemory workingMemory = new ReteooWorkingMemory(
119: 1, (ReteooRuleBase) RuleBaseFactory.newRuleBase());
120:
121: final MockObjectSource objectSource = new MockObjectSource(1);
122: final MockTupleSource tupleSource = new MockTupleSource(1);
123:
124: final JoinNode joinNode = new JoinNode(2, tupleSource,
125: objectSource);
126:
127: final BetaMemory memory = (BetaMemory) workingMemory
128: .getNodeMemory(joinNode);
129:
130: assertNotNull(memory);
131: }
132:
133: /**
134: * Test just tuple assertions
135: *
136: * @throws AssertionException
137: */
138: public void testAssertTuple() throws Exception {
139: final DefaultFactHandle f0 = new DefaultFactHandle(0, "cheese");
140: final ReteTuple tuple0 = new ReteTuple(f0);
141:
142: // assert tuple, should add one to left memory
143: this .node.assertTuple(tuple0, this .context, this .workingMemory);
144: // check memories, left memory is populated, right memory is emptys
145: assertEquals(1, this .memory.getTupleMemory().size());
146: assertEquals(0, this .memory.getFactHandleMemory().size());
147:
148: // assert tuple, should add left memory should be 2
149: final DefaultFactHandle f1 = new DefaultFactHandle(1, "cheese");
150: final ReteTuple tuple1 = new ReteTuple(f1);
151: this .node.assertTuple(tuple1, this .context, this .workingMemory);
152: assertEquals(2, this .memory.getTupleMemory().size());
153:
154: final Iterator it = this .memory.getTupleMemory().iterator();
155: assertEquals(tuple0, it.next());
156: assertEquals(tuple1, it.next());
157: }
158:
159: /**
160: * Test just tuple assertions
161: *
162: * @throws AssertionException
163: */
164: public void testAssertTupleSequentialMode() throws Exception {
165: RuleBaseConfiguration conf = new RuleBaseConfiguration();
166: conf.setSequential(true);
167:
168: this .workingMemory = new ReteooWorkingMemory(1,
169: (ReteooRuleBase) RuleBaseFactory.newRuleBase(conf));
170:
171: // override setup, so its working in sequential mode
172: this .node = new JoinNode(
173: 15,
174: this .tupleSource,
175: this .objectSource,
176: new DefaultBetaConstraints(
177: new BetaNodeFieldConstraint[] { this .constraint },
178: conf));
179:
180: this .node.addTupleSink(this .sink);
181:
182: this .memory = (BetaMemory) this .workingMemory
183: .getNodeMemory(this .node);
184:
185: final DefaultFactHandle f0 = new DefaultFactHandle(0, "cheese");
186: final ReteTuple tuple0 = new ReteTuple(f0);
187:
188: this .node.assertObject(f0, this .context, this .workingMemory);
189:
190: // assert tuple
191: this .node.assertTuple(tuple0, this .context, this .workingMemory);
192:
193: assertEquals(1, this .sink.getAsserted().size());
194:
195: assertNull(this .memory.getTupleMemory());
196:
197: assertEquals(1, this .memory.getFactHandleMemory().size());
198:
199: assertEquals(new ReteTuple(tuple0, f0), ((Object[]) this .sink
200: .getAsserted().get(0))[0]);
201: }
202:
203: /**
204: * Test just object assertions
205: *
206: * @throws Exception
207: */
208: public void testAssertObject() throws Exception {
209: final DefaultFactHandle f0 = (DefaultFactHandle) this .workingMemory
210: .insert("test0");
211:
212: // assert object, should add one to right memory
213: this .node.assertObject(f0, this .context, this .workingMemory);
214: assertEquals(0, this .memory.getTupleMemory().size());
215: assertEquals(1, this .memory.getFactHandleMemory().size());
216:
217: // check new objects/handles still assert
218: final DefaultFactHandle f1 = (DefaultFactHandle) this .workingMemory
219: .insert("test1");
220: this .node.assertObject(f1, this .context, this .workingMemory);
221: assertEquals(2, this .memory.getFactHandleMemory().size());
222:
223: final Iterator it = this .memory.getFactHandleMemory().iterator(
224: new ReteTuple(f0));
225:
226: final InternalFactHandle rf0 = ((FactEntry) it.next())
227: .getFactHandle();
228: final InternalFactHandle rf1 = ((FactEntry) it.next())
229: .getFactHandle();
230:
231: assertEquals(f0, rf0);
232: assertEquals(f1, rf1);
233: }
234:
235: /**
236: * Test assertion with both Objects and Tuples
237: *
238: * @throws Exception
239: */
240: public void testAssertPropagations() throws Exception {
241: // assert first right object
242: final DefaultFactHandle f0 = (DefaultFactHandle) this .workingMemory
243: .insert("test0");
244: this .node.assertObject(f0, this .context, this .workingMemory);
245:
246: // assert tuple, should add left memory should be 2
247: final DefaultFactHandle f1 = new DefaultFactHandle(1, "cheese");
248: final ReteTuple tuple1 = new ReteTuple(f1);
249: this .node.assertTuple(tuple1, this .context, this .workingMemory);
250:
251: assertEquals(1, this .sink.getAsserted().size());
252:
253: assertEquals(new ReteTuple(tuple1, f0), ((Object[]) this .sink
254: .getAsserted().get(0))[0]);
255:
256: final DefaultFactHandle f2 = new DefaultFactHandle(2, "cheese");
257: final ReteTuple tuple2 = new ReteTuple(f2);
258: this .node.assertTuple(tuple2, this .context, this .workingMemory);
259:
260: assertEquals(2, this .sink.getAsserted().size());
261: assertEquals(new ReteTuple(tuple2, f0), ((Object[]) this .sink
262: .getAsserted().get(1))[0]);
263:
264: final DefaultFactHandle f3 = (DefaultFactHandle) this .workingMemory
265: .insert("test2");
266: this .node.assertObject(f3, this .context, this .workingMemory);
267:
268: assertEquals(4, this .sink.getAsserted().size());
269:
270: final List tuples = new ArrayList();
271: tuples.add(((Object[]) this .sink.getAsserted().get(2))[0]);
272: tuples.add(((Object[]) this .sink.getAsserted().get(3))[0]);
273:
274: assertTrue(tuples.contains(new ReteTuple(tuple1, f3)));
275: assertTrue(tuples.contains(new ReteTuple(tuple2, f3)));
276: }
277:
278: /**
279: * Test Tuple retraction
280: *
281: * @throws Exception
282: * @throws RetractionException
283: */
284: public void testRetractTuple() throws Exception {
285: // setup 2 tuples 3 fact handles
286: final DefaultFactHandle f0 = (DefaultFactHandle) this .workingMemory
287: .insert("test0");
288: this .node.assertObject(f0, this .context, this .workingMemory);
289:
290: final DefaultFactHandle f1 = (DefaultFactHandle) this .workingMemory
291: .insert("test1");
292: final ReteTuple tuple1 = new ReteTuple(f1);
293: this .node.assertTuple(tuple1, this .context, this .workingMemory);
294:
295: final DefaultFactHandle f2 = (DefaultFactHandle) this .workingMemory
296: .insert("test2");
297: final ReteTuple tuple2 = new ReteTuple(f2);
298: this .node.assertTuple(tuple2, this .context, this .workingMemory);
299:
300: final DefaultFactHandle f3 = (DefaultFactHandle) this .workingMemory
301: .insert("test3");
302: this .node.assertObject(f3, this .context, this .workingMemory);
303:
304: final DefaultFactHandle f4 = (DefaultFactHandle) this .workingMemory
305: .insert("test4");
306: this .node.assertObject(f4, this .context, this .workingMemory);
307:
308: assertLength(6, this .sink.getAsserted());
309:
310: // Double check the item is in memory
311: final BetaMemory memory = (BetaMemory) this .workingMemory
312: .getNodeMemory(this .node);
313: assertTrue(memory.getFactHandleMemory().contains(f0));
314:
315: // Retract an object, check propagations and memory
316: this .node.retractObject(f0, this .context, this .workingMemory);
317: assertLength(2, this .sink.getRetracted());
318:
319: List tuples = new ArrayList();
320: tuples.add(((Object[]) this .sink.getRetracted().get(0))[0]);
321: tuples.add(((Object[]) this .sink.getRetracted().get(1))[0]);
322:
323: assertTrue(tuples.contains(new ReteTuple(tuple1, f0)));
324: assertTrue(tuples.contains(new ReteTuple(tuple1, f0)));
325:
326: // Now check the item is no longer in memory
327: assertFalse(memory.getFactHandleMemory().contains(f0));
328:
329: this .node
330: .retractTuple(tuple2, this .context, this .workingMemory);
331: assertEquals(4, this .sink.getRetracted().size());
332:
333: tuples = new ArrayList();
334: tuples.add(((Object[]) this .sink.getRetracted().get(2))[0]);
335: tuples.add(((Object[]) this .sink.getRetracted().get(3))[0]);
336:
337: assertTrue(tuples.contains(new ReteTuple(tuple2, f3)));
338: assertTrue(tuples.contains(new ReteTuple(tuple2, f4)));
339: }
340:
341: public void testConstraintPropagations() throws Exception {
342: this .constraint.isAllowed = false;
343: // assert first right object
344: final DefaultFactHandle f0 = (DefaultFactHandle) this .workingMemory
345: .insert("test0");
346: this .node.assertObject(f0, this .context, this .workingMemory);
347:
348: // assert tuple, should add left memory should be 2
349: final DefaultFactHandle f1 = new DefaultFactHandle(1, "cheese");
350: final ReteTuple tuple1 = new ReteTuple(f1);
351: this .node.assertTuple(tuple1, this .context, this .workingMemory);
352:
353: // Should be no assertions
354: assertLength(0, this .sink.getAsserted());
355:
356: this .node.retractObject(f0, this .context, this .workingMemory);
357: assertLength(0, this .sink.getRetracted());
358: }
359:
360: public void testUpdateSink() {
361: final ReteooWorkingMemory workingMemory = new ReteooWorkingMemory(
362: 1, (ReteooRuleBase) RuleBaseFactory.newRuleBase());
363:
364: final JoinNode joinNode = new JoinNode(1, this .tupleSource,
365: this .objectSource);
366:
367: // Add the first tuple sink and assert a tuple and object
368: // The sink has no memory
369: final MockTupleSink sink1 = new MockTupleSink(2);
370: joinNode.addTupleSink(sink1);
371:
372: final DefaultFactHandle f0 = new DefaultFactHandle(0, "string0");
373:
374: final ReteTuple tuple1 = new ReteTuple(f0);
375:
376: joinNode.assertTuple(tuple1, this .context, workingMemory);
377:
378: final String string1 = "string1";
379: final DefaultFactHandle string1Handle = new DefaultFactHandle(
380: 1, string1);
381:
382: joinNode.assertObject(string1Handle, this .context,
383: workingMemory);
384:
385: assertLength(1, sink1.getAsserted());
386:
387: // Add the new sink, this should be updated from the re-processed
388: // joinnode memory
389: final MockTupleSink sink2 = new MockTupleSink(3);
390: assertLength(0, sink2.getAsserted());
391:
392: joinNode.updateSink(sink2, this .context, workingMemory);
393:
394: assertLength(1, sink2.getAsserted());
395: }
396:
397: }
|