1 package org.drools.reteoo.impl;
2
3 /*
4 $Id: JoinMemoryImpl.java,v 1.4 2002/08/27 23:31:08 bob Exp $
5
6 Copyright 2002 (C) The Werken Company. All Rights Reserved.
7
8 Redistribution and use of this software and associated documentation
9 ("Software"), with or without modification, are permitted provided
10 that the following conditions are met:
11
12 1. Redistributions of source code must retain copyright
13 statements and notices. Redistributions must also contain a
14 copy of this document.
15
16 2. Redistributions in binary form must reproduce the
17 above copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
20
21 3. The name "drools" must not be used to endorse or promote
22 products derived from this Software without prior written
23 permission of The Werken Company. For written permission,
24 please contact bob@werken.com.
25
26 4. Products derived from this Software may not be called "drools"
27 nor may "drools" appear in their names without prior written
28 permission of The Werken Company. "drools" is a registered
29 trademark of The Werken Company.
30
31 5. Due credit should be given to The Werken Company.
32 (http://drools.werken.com/).
33
34 THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS
35 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
36 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
37 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
38 THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
39 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
43 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
45 OF THE POSSIBILITY OF SUCH DAMAGE.
46
47 */
48
49 import org.drools.WorkingMemory;
50 import org.drools.FactException;
51 import org.drools.reteoo.JoinMemory;
52 import org.drools.rule.Declaration;
53
54 import java.util.Set;
55 import java.util.HashSet;
56 import java.util.Iterator;
57 import java.util.Collections;
58
59 /*** Memory for left and right inputs of a <code>JoinNode</code>.
60 *
61 * @see JoinMemory
62 * @see JoinNodeImpl
63 * @see ReteTuple
64 *
65 * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
66 */
67 public class JoinMemoryImpl implements JoinMemory
68 {
69 // ------------------------------------------------------------
70 // Instance members
71 // ------------------------------------------------------------
72
73 /*** Left-side tuples. */
74 private TupleSet leftTuples;
75
76 /*** Right-side tuples. */
77 private TupleSet rightTuples;
78
79 /*** Join column declarations. */
80 private Set joinDeclarations;
81
82 // ------------------------------------------------------------
83 // Constructors
84 // ------------------------------------------------------------
85
86 /*** Construct.
87 *
88 * @param node The <code>JoinNode</code> this memory
89 * is for.
90 */
91 public JoinMemoryImpl(JoinNodeImpl node)
92 {
93 this.leftTuples = new TupleSet();
94 this.rightTuples = new TupleSet();
95
96 this.joinDeclarations = node.getCommonDeclarations();
97 }
98
99 // ------------------------------------------------------------
100 // Instance methods
101 // ------------------------------------------------------------
102
103 /*** Retract an object from this memory.
104 *
105 * @param object The object to retract.
106 */
107 protected void retractObject(Object object)
108 {
109 try
110 {
111 ReteTuple eachTuple = null;
112
113 Iterator tupleIter = leftTuples.iterator();
114
115 while ( tupleIter.hasNext() )
116 {
117 eachTuple = (ReteTuple) tupleIter.next();
118
119 if ( eachTuple.dependsOn( object ) )
120 {
121 tupleIter.remove();
122 }
123 }
124
125 tupleIter = rightTuples.iterator();
126
127 while ( tupleIter.hasNext() )
128 {
129 eachTuple = (ReteTuple) tupleIter.next();
130
131 if ( eachTuple.dependsOn( object ) )
132 {
133 tupleIter.remove();
134 }
135 }
136 }
137 catch (Exception e)
138 {
139 e.printStackTrace();
140 }
141 }
142
143 /*** Retract tuples from this memory.
144 *
145 * @param keys The keys for the tuples to be removed.
146 */
147 protected void retractTuples(Set keys)
148 {
149 Iterator keyIter = keys.iterator();
150 TupleKey eachKey = null;
151
152 while ( keyIter.hasNext() )
153 {
154 eachKey = (TupleKey) keyIter.next();
155
156 retractTuples( eachKey );
157 }
158 }
159
160 /*** Retract tuples from this memory.
161 *
162 * @param key The key for the tuples to be removed.
163 */
164 protected void retractTuples(TupleKey key)
165 {
166 retractTuples( key,
167 getLeftTuples().iterator() );
168
169 retractTuples( key,
170 getRightTuples().iterator() );
171 }
172
173 /*** Retract tuples from this memory.
174 *
175 * @param key The key for the tuples to be removed.
176 * @param tupleIter Iterator of tuples to be removed.
177 */
178 private void retractTuples(TupleKey key,
179 Iterator tupleIter)
180 {
181 ReteTuple eachTuple = null;
182
183 while ( tupleIter.hasNext() )
184 {
185 eachTuple = (ReteTuple) tupleIter.next();
186
187 if ( eachTuple.getKey().containsAll( key ) )
188 {
189 tupleIter.remove();
190 }
191 }
192 }
193
194 /*** Modify tuples on the left-side.
195 *
196 * @param trigger Triggering object.
197 * @param newTuples Modification replacement tuples.
198 * @param joinNode This memory's join node.
199 * @param workingMemory The working memory session.
200 *
201 * @throws FactException if an error occurs during modification.
202 */
203 protected void modifyLeftTuples(Object trigger,
204 TupleSet newTuples,
205 JoinNodeImpl joinNode,
206 WorkingMemory workingMemory) throws FactException
207 {
208 modifyTuples( trigger,
209 newTuples,
210 getLeftTuples(),
211 getRightTuples(),
212 joinNode,
213 workingMemory );
214 }
215
216 /*** Modify tuples on the right-side.
217 *
218 * @param trigger Triggering object.
219 * @param newTuples Modification replacement tuples.
220 * @param joinNode This memory's join node.
221 * @param workingMemory The working memory session.
222 *
223 * @throws FactException if an error occurs during modification.
224 */
225 protected void modifyRightTuples(Object trigger,
226 TupleSet newTuples,
227 JoinNodeImpl joinNode,
228 WorkingMemory workingMemory) throws FactException
229 {
230 modifyTuples( trigger,
231 newTuples,
232 getRightTuples(),
233 getLeftTuples(),
234 joinNode,
235 workingMemory );
236 }
237
238 /*** Modify tuples
239 *
240 * @param trigger Triggering object.
241 * @param newTuples Modification replacement tuples.
242 * @param thisSideTuples The tuples on the side that's receiving
243 * the modifications.
244 * @param thatSideTuples The tuples on the side that's <b>not</b>
245 * receiving the modifications.
246 * @param joinNode This memory's join node.
247 * @param workingMemory The working memory session.
248 *
249 * @throws FactException if an error occurs during modification.
250 */
251 protected void modifyTuples(Object trigger,
252 TupleSet newTuples,
253 TupleSet thisSideTuples,
254 TupleSet thatSideTuples,
255 JoinNodeImpl joinNode,
256 WorkingMemory workingMemory) throws FactException
257 {
258 Set retractedKeys = new HashSet();
259
260 Set origModified = new HashSet();
261 Set newModified = new HashSet();
262
263 ReteTuple origTuple = null;
264 ReteTuple newTuple = null;
265
266 Iterator tupleIter = thisSideTuples.iterator();
267
268 while ( tupleIter.hasNext() )
269 {
270 origTuple = (ReteTuple) tupleIter.next();
271
272 if ( origTuple.dependsOn( trigger ) )
273 {
274 newTuple = newTuples.getTuple( origTuple.getKey() );
275
276 if ( newTuple == null )
277 {
278 retractedKeys.add( origTuple.getKey() );
279 }
280 else
281 {
282 newModified.add( newTuple );
283 origModified.add( origTuple );
284 }
285 }
286 }
287
288 newModified.addAll( newTuples.getTuples() );
289
290 ReteTuple eachTuple = null;
291
292 TupleSet origJoined = new TupleSet();
293
294 tupleIter = origModified.iterator();
295
296 while ( tupleIter.hasNext() )
297 {
298 eachTuple = (ReteTuple) tupleIter.next();
299
300 origJoined.addAllTuples( attemptJoin( eachTuple,
301 thatSideTuples.iterator() ) );
302 }
303
304 TupleSet newJoined = new TupleSet();
305
306 tupleIter = newModified.iterator();
307
308 while ( tupleIter.hasNext() )
309 {
310 eachTuple = (ReteTuple) tupleIter.next();
311
312 newJoined.addAllTuples( attemptJoin( eachTuple,
313 thatSideTuples.iterator() ) );
314 }
315
316 tupleIter = origJoined.iterator();
317
318 while ( tupleIter.hasNext() )
319 {
320 eachTuple = (ReteTuple) tupleIter.next();
321
322 if ( ! newJoined.containsTuple( eachTuple.getKey() ) )
323 {
324 retractedKeys.add( eachTuple.getKey() );
325 }
326 }
327
328 thisSideTuples.addAllTuples( newTuples );
329
330 propagateRetractTuples( trigger,
331 retractedKeys,
332 joinNode,
333 workingMemory );
334
335 joinNode.propagateModifyTuples( trigger,
336 newJoined,
337 workingMemory );
338 }
339
340 /*** Propagate retractions.
341 *
342 * @param trigger The retracted trigger object.
343 * @param retractedKeys Keys to the retracted tuples.
344 * @param joinNode This memory's join node.
345 * @param workingMemory The working memory session.
346 *
347 * @throws FactException if an error occurs during modification.
348 */
349 private void propagateRetractTuples(Object trigger,
350 Set retractedKeys,
351 JoinNodeImpl joinNode,
352 WorkingMemory workingMemory) throws FactException
353 {
354 Iterator keyIter = retractedKeys.iterator();
355 TupleKey eachKey = null;
356
357 while ( keyIter.hasNext() )
358 {
359 eachKey = (TupleKey) keyIter.next();
360
361 joinNode.propagateRetractTuples( eachKey,
362 workingMemory );
363 }
364
365 }
366
367 /*** Add a <code>ReteTuple</code> received from the <code>JoinNode's</code>
368 * left input to the left side of this memory, and attempt
369 * to join to existing <code>Tuples</code> in the right
370 * side.
371 *
372 * @see JoinNodeImpl
373 * @see ReteTuple
374 *
375 * @param tuple The <code>Tuple</code> to add to the left
376 * side memory.
377 *
378 * @return A <code>List</code> of <code>Tuples</code> successfully
379 * created by joining the incoming <code>tuple</code>
380 * against existing <code>Tuples</code> on the right
381 * side memory.
382 */
383 protected Set addLeftTuple(ReteTuple tuple)
384 {
385 this.leftTuples.addTuple( tuple );
386
387
388 Set joined = attemptJoin( tuple,
389 getRightTupleIterator() );
390
391 return joined;
392 }
393
394 /*** Retrieve the <code>List</code> of <code>Tuples</code>
395 * held in the left side memory.
396 *
397 * @return The <code>List</code> of <code>Tuples</code>
398 * help in the left side memory.
399 */
400 protected TupleSet getLeftTuples()
401 {
402 return this.leftTuples;
403 }
404
405 /*** Retrieve an <code>Iterator</code> over the <code>Tuples</code>
406 * held in the left side memory.
407 *
408 * @return An <code>Iterator</code> over the <code>Tuples</code>
409 * help in the left side memory.
410 */
411 protected Iterator getLeftTupleIterator()
412 {
413 return this.leftTuples.iterator();
414 }
415
416 /*** Add a <code>ReteTuple</code> received from the <code>JoinNode's</code>
417 * right input to the right side of this memory, and attempt
418 * to join to existing <code>Tuples</code> in the left
419 * side.
420 *
421 * @see JoinNodeImpl
422 * @see ReteTuple
423 *
424 * @param tuple The <code>Tuple</code> to add to the right
425 * side memory.
426 *
427 * @return A <code>List</code> of <code>Tuples</code> successfully
428 * created by joining the incoming <code>tuple</code>
429 * against existing <code>Tuples</code> on the left
430 * side memory.
431 */
432 protected Set addRightTuple(ReteTuple tuple)
433 {
434 this.rightTuples.addTuple( tuple );
435
436 return attemptJoin( tuple,
437 getLeftTupleIterator() );
438 }
439
440 /*** Retrieve the <code>List</code> of <code>Tuples</code>
441 * held in the right side memory.
442 *
443 * @return The <code>List</code> of <code>Tuples</code>
444 * help in the right side memory.
445 */
446 protected TupleSet getRightTuples()
447 {
448 return this.rightTuples;
449 }
450
451 /*** Retrieve an <code>Iterator</code> over the <code>Tuples</code>
452 * held in the right side memory.
453 *
454 * @return An <code>Iterator</code> over the <code>Tuples</code>
455 * help in the right side memory.
456 */
457 protected Iterator getRightTupleIterator()
458 {
459 return this.rightTuples.iterator();
460 }
461
462 /*** Retrieve an <code>Iterator</code> over the common
463 * <code>Declarations</code> used to join <code>Tuples</code>
464 * from the left and right side memories.
465 *
466 * @return An <code>Iterator</code> of common join
467 * <code>Declarations</code>.
468 */
469 protected Iterator getJoinDeclarationIterator()
470 {
471 return this.joinDeclarations.iterator();
472 }
473
474 /*** Attempt to join the <code>tuple</code> against the
475 * tuples available through the <code>tupleIterator</code>.
476 *
477 * @param tuple The <code>Tuple</code> to attempt joining.
478 * @param tupleIter The <code>Iterator</code> over
479 * <code>Tuples</code> to attempt joining to the
480 * <code>tuple</code> parameter.
481 *
482 * @return A possibly empty <code>List</code> of joined
483 * <code>Tuples</code>.
484 */
485 protected Set attemptJoin(ReteTuple tuple,
486 Iterator tupleIter)
487 {
488 Set joinedTuples = Collections.EMPTY_SET;
489
490 ReteTuple eachTuple = null;
491 ReteTuple joinedTuple = null;
492
493 while ( tupleIter.hasNext() )
494 {
495 eachTuple = (ReteTuple) tupleIter.next();
496
497 joinedTuple = attemptJoin( tuple,
498 eachTuple );
499
500 if ( joinedTuple != null )
501 {
502 if ( joinedTuples == Collections.EMPTY_SET )
503 {
504 joinedTuples = new HashSet();
505 }
506
507 joinedTuples.add( joinedTuple );
508 }
509 }
510
511 return joinedTuples;
512 }
513
514 /*** Attempt to join two <code>Tuples</code>.
515 *
516 * @param left The left-side <code>Tuple</code>.
517 * @param right The right-side <code>Tuple</code>.
518 *
519 * @return A newly joined <code>Tuple</code> if a join
520 * is possible, else <code>null</code>.
521 */
522 protected ReteTuple attemptJoin(ReteTuple left,
523 ReteTuple right)
524 {
525
526 Iterator declIter = getJoinDeclarationIterator();
527 Declaration eachDecl = null;
528
529 Object leftValue = null;
530 Object rightValue = null;
531
532 while ( declIter.hasNext() )
533 {
534
535 eachDecl = (Declaration) declIter.next();
536
537 leftValue = left.get( eachDecl );
538 rightValue = right.get( eachDecl );
539
540 if ( leftValue == null
541 &&
542 rightValue == null )
543 {
544 continue;
545 }
546
547 if ( leftValue == null
548 ||
549 rightValue == null )
550 {
551 return null;
552 }
553
554 if ( leftValue.equals( rightValue ) )
555 {
556 continue;
557 }
558 else
559 {
560 return null;
561 }
562 }
563
564 ReteTuple joinedTuple = new JoinTuple( left,
565 right );
566
567 return joinedTuple;
568
569 }
570
571 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
572 // java.lang.Object
573 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
574
575 /*** Produce debug string.
576 *
577 * @return The debug string.
578 */
579 public String toString()
580 {
581 return "[JoinMemory \n\tleft=" + this.leftTuples + "\n\tright=" + this.rightTuples + "]";
582 }
583
584 }
This page was automatically generated by Maven