1 | package com.hammurapi.eventbus; |
2 | |
3 | import java.lang.reflect.Array; |
4 | import java.util.ArrayList; |
5 | import java.util.Collection; |
6 | import java.util.Collections; |
7 | import java.util.Comparator; |
8 | import java.util.Iterator; |
9 | import java.util.LinkedList; |
10 | import java.util.List; |
11 | import java.util.Map; |
12 | import java.util.Set; |
13 | import java.util.concurrent.Callable; |
14 | import java.util.concurrent.ExecutorService; |
15 | import java.util.concurrent.Future; |
16 | import java.util.concurrent.atomic.AtomicReference; |
17 | import java.util.logging.Logger; |
18 | |
19 | import com.hammurapi.extract.And; |
20 | import com.hammurapi.extract.CommutativeAnd; |
21 | import com.hammurapi.extract.ComparisonResult; |
22 | import com.hammurapi.extract.Extractor; |
23 | import com.hammurapi.extract.False; |
24 | import com.hammurapi.extract.Predicate; |
25 | import com.hammurapi.extract.True; |
26 | |
27 | /** |
28 | * |
29 | * @author Pavel Vlasov. |
30 | * |
31 | * @param <E> |
32 | * @param <P> |
33 | * @param <C> |
34 | */ |
35 | 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> { |
36 | private static final Logger logger = Logger.getLogger(PredicatedInferenceNode.class.getName()); |
37 | |
38 | protected abstract List<PredicatedInferenceNode<E, P, C, K, H, S>> getFalseChildren(); |
39 | |
40 | protected abstract List<PredicatedInferenceNode<E, P, C, K, H, S>> getTrueChildren(); |
41 | |
42 | protected abstract List<EventHandlerWrapper<E, P, C, K, H, S>> getFalseHandlers(); |
43 | |
44 | protected abstract List<EventHandlerWrapper<E, P, C, K, H, S>> getTrueHandlers(); |
45 | |
46 | protected PredicateChainingMatcher<E, P, C, K, H, S> getMatcher() { |
47 | return matcher; |
48 | } |
49 | |
50 | protected abstract Callable<Collection<EventHandlerWrapper<E, P, C, K, H, S>>> createCollectorTask( |
51 | Map<C, Map<Extractor<E, ? super Boolean, C>, ? super Boolean>> cache, |
52 | ExecutorService executor, |
53 | AtomicReference<Collection<Future<Collection<EventHandlerWrapper<E, P, C, K, H, S>>>>> collector, |
54 | E event); |
55 | |
56 | private Predicate<E, C> predicate; |
57 | |
58 | private C context; |
59 | |
60 | private K id; |
61 | |
62 | private boolean isRoot; |
63 | |
64 | private LinkedList<PredicatedInferenceNode<E, P, C, K, H, S>> nodePath; |
65 | |
66 | protected PredicateChainingMatcher<E, P, C, K, H, S> matcher; |
67 | |
68 | public void setRoot(boolean isRoot) { |
69 | this.isRoot = isRoot; |
70 | } |
71 | |
72 | public boolean isRoot() { |
73 | return isRoot; |
74 | } |
75 | |
76 | public PredicatedInferenceNode( |
77 | PredicatedInferenceNode<E,P,C,K,H,S> parent, |
78 | PredicateChainingMatcher<E,P,C,K,H,S> matcher, |
79 | Predicate<E, C> predicate, |
80 | C context, |
81 | K id) { |
82 | this.predicate = predicate; |
83 | this.context = context; |
84 | this.id = id; |
85 | if (parent==null) { |
86 | this.nodePath = new LinkedList<PredicatedInferenceNode<E,P,C,K,H,S>>(); |
87 | } else { |
88 | this.nodePath = new LinkedList<PredicatedInferenceNode<E,P,C,K,H,S>>(parent.getNodePath()); |
89 | } |
90 | this.nodePath.add(this); |
91 | this.matcher = matcher; |
92 | } |
93 | |
94 | LinkedList<PredicatedInferenceNode<E, P, C, K, H, S>> getNodePath() { |
95 | return nodePath; |
96 | } |
97 | |
98 | public K getId() { |
99 | 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 | } |