001 package com.hammurapi.eventbus;
002
003 import java.lang.reflect.Array;
004 import java.util.ArrayList;
005 import java.util.Collection;
006 import java.util.Collections;
007 import java.util.Comparator;
008 import java.util.Iterator;
009 import java.util.LinkedList;
010 import java.util.List;
011 import java.util.Map;
012 import java.util.Set;
013 import java.util.concurrent.Callable;
014 import java.util.concurrent.ExecutorService;
015 import java.util.concurrent.Future;
016 import java.util.concurrent.atomic.AtomicReference;
017 import java.util.logging.Logger;
018
019 import com.hammurapi.extract.And;
020 import com.hammurapi.extract.CommutativeAnd;
021 import com.hammurapi.extract.ComparisonResult;
022 import com.hammurapi.extract.Extractor;
023 import com.hammurapi.extract.False;
024 import com.hammurapi.extract.Predicate;
025 import com.hammurapi.extract.True;
026
027 /**
028 *
029 * @author Pavel Vlasov.
030 *
031 * @param <E>
032 * @param <P>
033 * @param <C>
034 */
035 public abstract class PredicatedInferenceNode<E, P extends Comparable<P>, C, K, H extends EventBus.Handle<E,P,C>, S extends EventStore<E,P,C,H,S>> implements InferenceNode<E, P, C, K, H, S> {
036 private static final Logger logger = Logger.getLogger(PredicatedInferenceNode.class.getName());
037
038 protected abstract List<PredicatedInferenceNode<E, P, C, K, H, S>> getFalseChildren();
039
040 protected abstract List<PredicatedInferenceNode<E, P, C, K, H, S>> getTrueChildren();
041
042 protected abstract List<EventHandlerWrapper<E, P, C, K, H, S>> getFalseHandlers();
043
044 protected abstract List<EventHandlerWrapper<E, P, C, K, H, S>> getTrueHandlers();
045
046 protected PredicateChainingMatcher<E, P, C, K, H, S> getMatcher() {
047 return matcher;
048 }
049
050 protected abstract Callable<Collection<EventHandlerWrapper<E, P, C, K, H, S>>> createCollectorTask(
051 Map<C, Map<Extractor<E, ? super Boolean, C>, ? super Boolean>> cache,
052 ExecutorService executor,
053 AtomicReference<Collection<Future<Collection<EventHandlerWrapper<E, P, C, K, H, S>>>>> collector,
054 E event);
055
056 private Predicate<E, C> predicate;
057
058 private C context;
059
060 private K id;
061
062 private boolean isRoot;
063
064 private LinkedList<PredicatedInferenceNode<E, P, C, K, H, S>> nodePath;
065
066 protected PredicateChainingMatcher<E, P, C, K, H, S> matcher;
067
068 public void setRoot(boolean isRoot) {
069 this.isRoot = isRoot;
070 }
071
072 public boolean isRoot() {
073 return isRoot;
074 }
075
076 public PredicatedInferenceNode(
077 PredicatedInferenceNode<E,P,C,K,H,S> parent,
078 PredicateChainingMatcher<E,P,C,K,H,S> matcher,
079 Predicate<E, C> predicate,
080 C context,
081 K id) {
082 this.predicate = predicate;
083 this.context = context;
084 this.id = id;
085 if (parent==null) {
086 this.nodePath = new LinkedList<PredicatedInferenceNode<E,P,C,K,H,S>>();
087 } else {
088 this.nodePath = new LinkedList<PredicatedInferenceNode<E,P,C,K,H,S>>(parent.getNodePath());
089 }
090 this.nodePath.add(this);
091 this.matcher = matcher;
092 }
093
094 LinkedList<PredicatedInferenceNode<E, P, C, K, H, S>> getNodePath() {
095 return nodePath;
096 }
097
098 public K getId() {
099 return id;
100 }
101
102 public Predicate<E,C> getPredicate() {
103 return predicate;
104 }
105
106 public C getContext() {
107 return context;
108 }
109
110 /**
111 * Returns true if the handler was incorporated into the node.
112 * @param handler
113 * @param nodePath If not null, only nodes from the path are considered.
114 * @return
115 */
116 boolean addHandler(EventHandlerWrapper<E, P, C, K, H, S> handler, LinkedList<PredicatedInferenceNode<E,P,C,K,H,S>> nodePath) {
117 if (nodePath!=null) {
118 if (nodePath.getFirst()!=this) {
119 return false;
120 }
121
122 if (nodePath.size()==1) {
123 nodePath = null;
124 } else {
125 nodePath = new LinkedList<PredicatedInferenceNode<E,P,C,K,H,S>>(nodePath);
126 nodePath.removeFirst();
127 }
128 }
129
130 if (handler.getCardinality()!=1) {
131 throw new IllegalArgumentException("Only handlers with cardinality 1 can be added to predicated inference node: "+handler);
132 }
133
134 if (handler.getPredicate()!=null && !(handler.getPredicate() instanceof True) && !(handler.getPredicate() instanceof False) && !Collections.singleton(0).equals(handler.getPredicate().parameterIndices())) {
135 throw new IllegalArgumentException("Only predicates with parameter indices [0] can be added to predicated inference node: "+predicate);
136 }
137
138 // Less expensive predicates cannot be chained after more expensive.
139 if (!isRoot && this.predicate.getCost()>handler.getPredicate().getCost()) {
140 return false;
141 }
142
143 CR cr = compare(handler);
144
145 if (cr==null) {
146 return false; // Predicates are incompatible.
147 }
148
149 EventHandlerWrapperFilter<E,P,C,K,H,S> subHandler = new EventHandlerWrapperFilter<E,P,C,K,H,S>(handler, cr.subPredicate);
150 switch (cr.target) {
151 case THIS_TRUE:
152 getTrueHandlers().add(handler);
153 return true;
154 case THIS_FALSE:
155 getFalseHandlers().add(handler);
156 return true;
157 case SUB_TRUE:
158 for (PredicatedInferenceNode<E, P, C, K, H, S> trueChild: getTrueChildren()) {
159 if (trueChild.addHandler(subHandler, nodePath)) {
160 return true;
161 }
162 }
163
164 if (nodePath!=null) {
165 return false;
166 }
167
168 if (cr.subPredicate instanceof And && ((And<E,C>) cr.subPredicate).getParts().size()>1) {
169 PredicatedInferenceNode<E, P, C, K, H, S> newTrueChild = getMatcher().createPredicatedInferenceNode(this, ((And<E,C>) cr.subPredicate).getParts().get(0), handler.getContext());
170 getTrueChildren().add(newTrueChild);
171 if (!newTrueChild.addHandler(subHandler, nodePath)) {
172 throw new IllegalStateException("Should never happen!!!");
173 }
174 migrateChildren(newTrueChild.getNodePath());
175 } else if (cr.subPredicate instanceof CommutativeAnd && ((CommutativeAnd<E,C>) cr.subPredicate).getParts().size()>1) {
176 List<Predicate<E,C>> parts = new ArrayList<Predicate<E,C>>(((CommutativeAnd<E,C>) cr.subPredicate).getParts());
177 Collections.sort(parts, new Comparator<Predicate<E,C>>() {
178
179 @Override
180 public int compare(Predicate<E, C> o1, Predicate<E, C> o2) {
181 double delta = o1.getCost() - o2.getCost();
182 if (delta < -Double.MIN_VALUE) {
183 return -1;
184 }
185
186 if (delta > Double.MIN_VALUE) {
187 return 1;
188 }
189 return o1.hashCode() - o2.hashCode();
190 }
191
192 });
193
194 PredicatedInferenceNode<E, P, C, K, H, S> newTrueChild = getMatcher().createPredicatedInferenceNode(this, parts.get(0), handler.getContext());
195 getTrueChildren().add(newTrueChild);
196 if (!newTrueChild.addHandler(subHandler, nodePath)) {
197 throw new IllegalStateException("Should never happen!!!");
198 }
199 migrateChildren(newTrueChild.getNodePath());
200 } else {
201 PredicatedInferenceNode<E, P, C, K, H, S> newTrueChild = getMatcher().createPredicatedInferenceNode(this, cr.subPredicate, handler.getContext());
202 newTrueChild.getTrueHandlers().add(subHandler);
203 getTrueChildren().add(newTrueChild);
204
205 // Try to migrate existing nodes under the new one.
206 migrateChildren(newTrueChild.getNodePath());
207 }
208
209 return true;
210 case SUB_FALSE:
211 for (PredicatedInferenceNode<E, P, C, K, H, S> falseChild: getFalseChildren()) {
212 if (falseChild.addHandler(subHandler, nodePath)) {
213 return true;
214 }
215 }
216
217 if (nodePath!=null) {
218 return false;
219 }
220
221 if (cr.subPredicate instanceof And && ((And<E,C>) cr.subPredicate).getParts().size()>1) {
222 PredicatedInferenceNode<E, P, C, K, H, S> newFalseChild = getMatcher().createPredicatedInferenceNode(this, ((And<E,C>) cr.subPredicate).getParts().get(0), handler.getContext());
223 getFalseChildren().add(newFalseChild);
224 if (!newFalseChild.addHandler(subHandler, nodePath)) {
225 throw new IllegalStateException("Should never happen!!!");
226 }
227 migrateChildren(newFalseChild.getNodePath());
228 } else if (cr.subPredicate instanceof CommutativeAnd && ((CommutativeAnd<E,C>) cr.subPredicate).getParts().size()>1) {
229 List<Predicate<E,C>> parts = new ArrayList<Predicate<E,C>>(((CommutativeAnd<E,C>) cr.subPredicate).getParts());
230 Collections.sort(parts, new Comparator<Predicate<E,C>>() {
231
232 @Override
233 public int compare(Predicate<E, C> o1, Predicate<E, C> o2) {
234 double delta = o1.getCost() - o2.getCost();
235 if (delta < -Double.MIN_VALUE) {
236 return -1;
237 }
238
239 if (delta > Double.MIN_VALUE) {
240 return 1;
241 }
242 return o1.hashCode() - o2.hashCode();
243 }
244
245 });
246
247 PredicatedInferenceNode<E, P, C, K, H, S> newFalseChild = getMatcher().createPredicatedInferenceNode(this, parts.get(0), handler.getContext());
248 getFalseChildren().add(newFalseChild);
249 if (!newFalseChild.addHandler(subHandler, nodePath)) {
250 throw new IllegalStateException("Should never happen!!!");
251 }
252 migrateChildren(newFalseChild.getNodePath());
253 } else {
254 PredicatedInferenceNode<E, P, C, K, H, S> newFalseChild = getMatcher().createPredicatedInferenceNode(this, cr.subPredicate, handler.getContext());
255 newFalseChild.getTrueHandlers().add(subHandler);
256 getFalseChildren().add(newFalseChild);
257
258 // Try to migrate existing nodes under the new one.
259 migrateChildren(newFalseChild.getNodePath());
260 }
261
262 return true;
263 default:
264 throw new IllegalArgumentException("Unexpected target: "+cr.target);
265 }
266
267 }
268
269 /**
270 * Rebuilds inference network.
271 */
272 public void rebuild() {
273 for (EventHandlerWrapper<E, P, C, K, H, S> h: getAllHandlers()) {
274 addHandler(EventHandlerWrapperFilter.peel(h), nodePath);
275 }
276 }
277
278 /**
279 * Attempts to migrate this node and child nodes' handlers to the node
280 * specified by the nodePath parameter.
281 * @param nodePath
282 * @return true if the node was fully migrated (empty).
283 */
284 boolean migrate(LinkedList<PredicatedInferenceNode<E,P,C,K,H,S>> nodePath) {
285 if (nodePath.containsAll(this.nodePath)) {
286 return isEmpty(); // Self migration.
287 }
288 Iterator<EventHandlerWrapper<E, P, C, K, H, S>> thit = getTrueHandlers().iterator();
289 while (thit.hasNext()) {
290 EventHandlerWrapper<E, P, C, K, H, S> th = thit.next();
291 if (this.nodePath.getFirst().addHandler(th, nodePath)) {
292 logger.info("Handler "+th+" migrated from "+this.nodePath+" to "+nodePath);
293 thit.remove();
294 }
295 }
296
297 Iterator<EventHandlerWrapper<E, P, C, K, H, S>> fhit = getFalseHandlers().iterator();
298 while (fhit.hasNext()) {
299 EventHandlerWrapper<E, P, C, K, H, S> fh = fhit.next();
300 if (this.nodePath.getFirst().addHandler(fh, nodePath)) {
301 logger.info("Handler "+fh+" migrated from "+this.nodePath+" to "+nodePath);
302 fhit.remove();
303 }
304 }
305
306 migrateChildren(nodePath);
307
308 return isEmpty();
309 }
310
311 private void migrateChildren(LinkedList<PredicatedInferenceNode<E, P, C, K, H, S>> nodePath) {
312 Iterator<PredicatedInferenceNode<E, P, C, K, H, S>> tcit = getTrueChildren().iterator();
313 while (tcit.hasNext()) {
314 PredicatedInferenceNode<E, P, C, K, H, S> tc = tcit.next();
315 if (tc.migrate(nodePath)) {
316 tcit.remove();
317 }
318 }
319
320 Iterator<PredicatedInferenceNode<E, P, C, K, H, S>> fcit = getTrueChildren().iterator();
321 while (fcit.hasNext()) {
322 PredicatedInferenceNode<E, P, C, K, H, S> fc = fcit.next();
323 if (fc.migrate(nodePath)) {
324 fcit.remove();
325 }
326 }
327 }
328
329 private enum Target {
330 // Predicates equal, add to this true
331 THIS_TRUE,
332 // Predicates opposite, add to this false.
333 THIS_FALSE,
334 // Parameter predicate is more restrictive than this predicate or
335 // composite with extracted part for this predicate, add (merge) to true children.
336 SUB_TRUE,
337 // Parameter predicate is composite with opposite part extracted,
338 // or this predicate is opposite less restrictive than parameter predicate
339 // add (merge) to false children.
340 SUB_FALSE
341 }
342
343 private class CR {
344
345 // Predicate for sub-node.
346 Predicate<E, C> subPredicate;
347
348 Target target;
349
350 public CR(Predicate<E, C> subPredicate, Target target) {
351 this.subPredicate = subPredicate;
352 this.target = target;
353 }
354
355 }
356
357 private enum CONTEXT_DEPENDENCY {
358 BOTH,
359 NODE,
360 HANDLER,
361 NONE
362 }
363
364 /**
365 * Compares parameter predicate with this predicate.
366 * @param predicate
367 * @return
368 */
369 private CR compare(EventHandlerWrapper<E, P, C, K, H, S> handler) {
370 if (this.predicate==handler.getPredicate()) {
371 return new CR(null, Target.THIS_TRUE);
372 }
373
374 if (this.predicate.isContextDependent() && !handler.getPredicate().isContextDependent()) {
375 return null; // This predicate is automatically more restrictive because it is context dependent.
376 }
377
378 CONTEXT_DEPENDENCY contextDependency;
379 if (this.predicate.isContextDependent()) {
380 if (handler.getPredicate().isContextDependent()) {
381 contextDependency = CONTEXT_DEPENDENCY.BOTH;
382 } else {
383 contextDependency = CONTEXT_DEPENDENCY.NODE;
384 }
385 } else {
386 if (handler.getPredicate().isContextDependent()) {
387 contextDependency = CONTEXT_DEPENDENCY.HANDLER;
388 } else {
389 contextDependency = CONTEXT_DEPENDENCY.NONE;
390 }
391 }
392
393 if (CONTEXT_DEPENDENCY.BOTH.equals(contextDependency)) {
394 if (this.context==null) {
395 if (handler.getContext()!=null) {
396 return null;
397 }
398 } else {
399 if (!this.context.equals(handler.getContext())) {
400 return null;
401 }
402 }
403 }
404
405 // Both are context independent or
406 // contexts are both null or equal.
407 Predicate<E, C> handlerPredicate = handler.getPredicate();
408 // System.out.println("Comparing ---\n\t"+this.predicate+"\n\t"+handlerPredicate);
409 ComparisonResult cr = this.predicate.compareTo(handlerPredicate);
410 if (cr!=null && cr.isOneToOneMapping()) {
411 // System.out.println("\t"+cr.getType());
412 switch (cr.getType()) {
413 case EQUAL:
414 return new CR(null, Target.THIS_TRUE);
415 case OPPOSITE:
416 return new CR(null, Target.THIS_FALSE);
417 case LESS_RESTRICTIVE:
418 if (handlerPredicate instanceof And) {
419 Predicate<E,C> firstPart = ((And<E,C>) handlerPredicate).getParts().get(0);
420 ComparisonResult pcr = firstPart.compareTo(this.predicate);
421 if (ComparisonResult.EQUAL_NM.equals(pcr)) {
422 return new CR(((And<E,C>) handlerPredicate).remove(firstPart), Target.SUB_TRUE);
423 }
424 } else if (handlerPredicate instanceof CommutativeAnd) {
425 for (Predicate<E,C> part: ((CommutativeAnd<E, C>) handlerPredicate).getParts()) {
426 if (ComparisonResult.EQUAL_NM.equals(part.compareTo(this.predicate))) {
427 return new CR(((CommutativeAnd<E,C>) handlerPredicate).remove(part), Target.SUB_TRUE);
428 }
429 }
430 }
431
432 return new CR(handlerPredicate, Target.SUB_TRUE);
433 case OPPOSITE_LESS_RESTRICTIVE:
434 if (handlerPredicate instanceof And) {
435 Predicate<E,C> firstPart = ((And<E,C>) handlerPredicate).getParts().get(0);
436 if (ComparisonResult.OPPOSITE_NM.equals(firstPart.compareTo(this.predicate))) {
437 return new CR(((And<E,C>) handlerPredicate).remove(firstPart), Target.SUB_FALSE);
438 }
439 } else if (handlerPredicate instanceof CommutativeAnd) {
440 for (Predicate<E,C> part: ((CommutativeAnd<E, C>) handlerPredicate).getParts()) {
441 if (ComparisonResult.OPPOSITE_NM.equals(part.compareTo(this.predicate))) {
442 return new CR(((And<E,C>) handlerPredicate).remove(part), Target.SUB_FALSE);
443 }
444 }
445 }
446
447 return new CR(handlerPredicate, Target.SUB_FALSE);
448 }
449 }
450
451 if (handlerPredicate instanceof And) {
452 // Should have at least one part if reached here
453 And<E,C> ahp = (And<E,C>) handlerPredicate;
454 Predicate<E, C> firstPart = ahp.getParts().get(0);
455 cr = this.predicate.compareTo(firstPart);
456 if (cr!=null && cr.isOneToOneMapping()) {
457 // System.out.println("\t firstPart "+cr.getType());
458 switch (cr.getType()) {
459 case EQUAL:
460 return new CR(ahp.remove(firstPart), Target.SUB_TRUE);
461 case LESS_RESTRICTIVE:
462 return new CR(ahp, Target.SUB_TRUE);
463 case OPPOSITE:
464 return new CR(ahp.remove(firstPart), Target.SUB_FALSE);
465 case OPPOSITE_LESS_RESTRICTIVE:
466 return new CR(ahp, Target.SUB_FALSE);
467 }
468 }
469 } else if (handlerPredicate instanceof CommutativeAnd) {
470 // Should have at least one part if reached here
471 CommutativeAnd<E,C> cahp = (CommutativeAnd<E,C>) handlerPredicate;
472 for (Predicate<E, C> part: cahp.getParts()) {
473 cr = this.predicate.compareTo(part);
474 if (cr!=null && cr.isOneToOneMapping()) {
475 // System.out.println("\t part "+cr.getType());
476 switch (cr.getType()) {
477 case EQUAL:
478 return new CR(cahp.remove(part), Target.SUB_TRUE);
479 case LESS_RESTRICTIVE:
480 return new CR(cahp, Target.SUB_TRUE);
481 case OPPOSITE:
482 return new CR(cahp.remove(part), Target.SUB_FALSE);
483 case OPPOSITE_LESS_RESTRICTIVE:
484 return new CR(cahp, Target.SUB_FALSE);
485 }
486 }
487 }
488 }
489 return null;
490 }
491
492 boolean isEmpty() {
493 return getTrueChildren().isEmpty()
494 && getTrueHandlers().isEmpty()
495 && getFalseChildren().isEmpty()
496 && getFalseHandlers().isEmpty();
497 }
498
499 /**
500 * Collects handlers synchronously.
501 */
502 @Override
503 public void collectHandlers(
504 Map<C, Map<Extractor<E, ? super Boolean, C>, ? super Boolean>> cache,
505 Collection<EventHandlerWrapper<E, P, C, K, H, S>> collector,
506 E event) {
507
508 @SuppressWarnings("unchecked")
509 E[] events = (E[]) Array.newInstance(matcher.getEventBus().getEventType(), 1);
510 events[0] = event;
511
512 if (getPredicate().extract(getContext(), cache, events)) {
513 for (PredicatedInferenceNode<E, P, C, K, H, S> trueChild: getTrueChildren()) {
514 trueChild.collectHandlers(cache, collector, event);
515 }
516 collector.addAll(getTrueHandlers());
517 } else {
518 for (PredicatedInferenceNode<E, P, C, K, H, S> falseChild: getFalseChildren()) {
519 falseChild.collectHandlers(cache, collector, event);
520 }
521 collector.addAll(getFalseHandlers());
522 }
523 }
524
525 /**
526 * Collects handlers asynchronously.
527 */
528 @Override
529 public void collectHandlers(
530 final Map<C, Map<Extractor<E, ? super Boolean, C>, ? super Boolean>> cache,
531 final ExecutorService executor,
532 final AtomicReference<Collection<Future<Collection<EventHandlerWrapper<E, P, C, K, H, S>>>>> collector,
533 final E event) {
534
535 // Evaluates predicate and submits tasks for sub-nodes.
536 Callable<Collection<EventHandlerWrapper<E, P, C, K, H, S>>> task = createCollectorTask(cache, executor, collector, event);
537 Collection<Future<Collection<EventHandlerWrapper<E, P, C, K, H, S>>>> c = collector.get();
538 if (c==null) {
539 logger.severe("Collecting handlers after join()");
540 throw new EventBusException("Collecting handlers after join()");
541 }
542 c.add(executor.submit(task));
543
544 }
545
546 @Override
547 public boolean remove(List<PredicatedInferenceNode<E, P, C, K, H, S>> parentTrueChildren, List<PredicatedInferenceNode<E, P, C, K, H, S>> parentFalseChildren, boolean isTrueChild, Iterable<K> keys) {
548 for (K key: keys) {
549 Iterator<EventHandlerWrapper<E, P, C, K, H, S>> tit = getTrueHandlers().iterator();
550 while (tit.hasNext()) {
551 EventHandlerWrapper<E, P, C, K, H, S> eh = tit.next();
552 if (eh.getRegistrationKeys().remove(key)) {
553 if (eh.getRegistrationKeys().isEmpty()) {
554 tit.remove();
555 }
556 }
557 }
558 Iterator<EventHandlerWrapper<E, P, C, K, H, S>> fit = getFalseHandlers().iterator();
559 while (fit.hasNext()) {
560 EventHandlerWrapper<E, P, C, K, H, S> eh = fit.next();
561 if (eh.getRegistrationKeys().remove(key)) {
562 if (eh.getRegistrationKeys().isEmpty()) {
563 fit.remove();
564 }
565 }
566 }
567
568 Iterator<PredicatedInferenceNode<E, P, C, K, H, S>> tcit = getTrueChildren().iterator();
569 while (tcit.hasNext()) {
570 if (!tcit.next().remove(getTrueChildren(), getFalseChildren(), true, keys)) {
571 tcit.remove();
572 }
573 }
574
575 Iterator<PredicatedInferenceNode<E, P, C, K, H, S>> fcit = getFalseChildren().iterator();
576 while (fcit.hasNext()) {
577 if (!fcit.next().remove(getTrueChildren(), getFalseChildren(), false, keys)) {
578 fcit.remove();
579 }
580 }
581 }
582
583 if (!getTrueHandlers().isEmpty() || !getFalseHandlers().isEmpty()) {
584 return true;
585 }
586
587 // TODO implement sub-node promotion to parent. Two-phase - a) collect. b) if nothing remains - promote.
588
589 return !getTrueChildren().isEmpty() || !getFalseChildren().isEmpty();
590 }
591
592 @Override
593 public void reset() {
594 for (EventHandlerWrapper<E, P, C, K, H, S> eh: getTrueHandlers()) {
595 eh.reset();
596 }
597 for (EventHandlerWrapper<E, P, C, K, H, S> eh: getFalseHandlers()) {
598 eh.reset();
599 }
600 for (PredicatedInferenceNode<E, P, C, K, H, S> child: getTrueChildren()) {
601 child.reset();
602 }
603 for (PredicatedInferenceNode<E, P, C, K, H, S> child: getFalseChildren()) {
604 child.reset();
605 }
606 }
607
608 void takeSnapshot(AbstractEventBus.Snapshot<E, P, C, K, H, S> snapshot, Set<K> taken) {
609 if (taken.add(id)) {
610 Collection<K> trueChildrenIds = new ArrayList<K>();
611 for (PredicatedInferenceNode<E, P, C, K, H, S> tc: getTrueChildren()) {
612 tc.takeSnapshot(snapshot, taken);
613 trueChildrenIds.add(tc.id);
614 }
615
616 Collection<K> trueHandlersIds = new ArrayList<K>();
617 for (EventHandlerWrapper<E, P, C, K, H, S> th: getTrueHandlers()) {
618 th.takeSnapshot(snapshot, taken);
619 trueHandlersIds.addAll(getMatcher().extractHandlerIds(th));
620 }
621
622 Collection<K> falseChildrenIds = new ArrayList<K>();
623 for (PredicatedInferenceNode<E, P, C, K, H, S> fc: getFalseChildren()) {
624 fc.takeSnapshot(snapshot, taken);
625 falseChildrenIds.add(fc.id);
626 }
627
628 Collection<K> falseHandlersIds = new ArrayList<K>();
629 for (EventHandlerWrapper<E, P, C, K, H, S> fh: getFalseHandlers()) {
630 fh.takeSnapshot(snapshot, taken);
631 falseHandlersIds.addAll(getMatcher().extractHandlerIds(fh));
632 }
633
634 snapshot.predicateNode(id, predicate, trueChildrenIds, trueHandlersIds, falseChildrenIds, falseHandlersIds, isRoot);
635 }
636 }
637
638 @Override
639 public Collection<EventHandlerWrapper<E, P, C, K, H, S>> getAllHandlers() {
640 Collection<EventHandlerWrapper<E, P, C, K, H, S>> ret = new LinkedList<EventHandlerWrapper<E,P,C,K,H,S>>();
641
642 ret.addAll(getTrueHandlers());
643 ret.addAll(getFalseHandlers());
644
645 for (PredicatedInferenceNode<E, P, C, K, H, S> tc: getTrueChildren()) {
646 ret.addAll(tc.getAllHandlers());
647 }
648
649 for (PredicatedInferenceNode<E, P, C, K, H, S> fc: getFalseChildren()) {
650 ret.addAll(fc.getAllHandlers());
651 }
652
653 return ret;
654 }
655 }