Total Complexity | 97 |
Total Lines | 1110 |
Duplicated Lines | 22.07 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like it.cnr.istc.pst.platinum.ai.executive.pdb.ExecutivePlanDataBase often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | package it.cnr.istc.pst.platinum.ai.executive.pdb; |
||
62 | @TemporalFacadeConfiguration( |
||
63 | |||
64 | // temporal network |
||
65 | network = TemporalNetworkType.STNU, |
||
66 | |||
67 | // temporal solver |
||
68 | solver = TemporalSolverType.APSP |
||
69 | ) |
||
70 | public class ExecutivePlanDataBase extends FrameworkObject |
||
71 | { |
||
72 | private PlanProtocolDescriptor plan; // the plan to execute |
||
73 | |||
74 | @TemporalFacadePlaceholder |
||
75 | protected TemporalFacade facade; // temporal data base |
||
76 | |||
77 | // plan locks |
||
78 | private final Object[] locks; |
||
79 | |||
80 | // plan's nodes |
||
81 | protected Map<ExecutionNodeStatus, List<ExecutionNode>> nodes; |
||
82 | |||
83 | // execution dependency graphs |
||
84 | protected Map<ExecutionNode, Map<ExecutionNode, ExecutionNodeStatus>> sdg; // start dependency graph |
||
85 | protected Map<ExecutionNode, Map<ExecutionNode, ExecutionNodeStatus>> edg; // end dependency graph |
||
86 | |||
87 | /** |
||
88 | * |
||
89 | * @param origin |
||
90 | * @param horizon |
||
91 | */ |
||
92 | protected ExecutivePlanDataBase() { |
||
93 | super(); |
||
94 | |||
95 | // set array of locks |
||
96 | this.locks = new Object[ExecutionNodeStatus.values().length]; |
||
97 | // add locks |
||
98 | for (ExecutionNodeStatus s : ExecutionNodeStatus.values()) { |
||
99 | // set lock |
||
100 | this.locks[s.getIndex()] = new Object(); |
||
101 | } |
||
102 | |||
103 | // set data structures |
||
104 | this.nodes = new HashMap<>(); |
||
|
|||
105 | for (ExecutionNodeStatus s : ExecutionNodeStatus.values()) { |
||
106 | // set the index of execution nodes |
||
107 | this.nodes.put(s, new LinkedList<ExecutionNode>()); |
||
108 | } |
||
109 | |||
110 | // set the dependency graph |
||
111 | this.sdg = new HashMap<>(); |
||
112 | this.edg = new HashMap<>(); |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * |
||
117 | * @return |
||
118 | */ |
||
119 | public long getOrigin() { |
||
120 | return this.facade.getOrigin(); |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * |
||
125 | * @return |
||
126 | */ |
||
127 | public long getHorizon() { |
||
128 | return this.facade.getHorizon(); |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * |
||
133 | * @return |
||
134 | */ |
||
135 | public String export() throws IOException { |
||
136 | |||
137 | // prepare file |
||
138 | //System.out.println("Prepare file plans/exported/plan.txt... "); |
||
139 | File output = new File("plans/exported/plan.txt"); |
||
140 | // export current plan (if any) to a known file |
||
141 | if (this.plan != null) |
||
142 | { |
||
143 | // get plan encoding |
||
144 | String encoding = this.plan.export(); |
||
145 | // write to a file |
||
146 | System.out.println("Writing file:\n"); |
||
147 | try (BufferedWriter writer = new BufferedWriter(new FileWriter(output))) { |
||
148 | // get data |
||
149 | //System.out.println(encoding +"\n"); |
||
150 | writer.write(encoding); |
||
151 | //System.out.println("Done!"); |
||
152 | writer.close(); |
||
153 | } |
||
154 | } |
||
155 | |||
156 | // get absolute file |
||
157 | //System.out.println(output.getAbsolutePath()); |
||
158 | return output.getAbsolutePath(); |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * |
||
163 | * @return |
||
164 | */ |
||
165 | public String getName() { |
||
166 | return this.plan.getName(); |
||
167 | } |
||
168 | |||
169 | |||
170 | /** |
||
171 | * |
||
172 | * @param plan |
||
173 | */ |
||
174 | public void setup(PlanProtocolDescriptor plan) { |
||
175 | |||
176 | try { |
||
177 | |||
178 | // clear executed nodes |
||
179 | this.clearExecutedNodes(); |
||
180 | |||
181 | |||
182 | |||
183 | |||
184 | // get plan descriptor |
||
185 | this.plan = plan; |
||
186 | // map token descriptor to nodes |
||
187 | Map<TokenProtocolDescriptor, ExecutionNode> dictionary = new HashMap<>(); |
||
188 | // check time-lines |
||
189 | View Code Duplication | for (TimelineProtocolDescriptor tl : plan.getTimelines()) { |
|
190 | |||
191 | // setup node arrays |
||
192 | ExecutionNode[] list = new ExecutionNode[tl.getTokens().size()]; |
||
193 | // list index |
||
194 | int counter = 0; |
||
195 | // create an execution node for each token |
||
196 | for (TokenProtocolDescriptor token : tl.getTokens()) { |
||
197 | // check predicate |
||
198 | if (!token.getPredicate().toLowerCase().equals("unallocated")) { |
||
199 | |||
200 | // get token's bound |
||
201 | long[] start = token.getStartTimeBounds(); |
||
202 | long[] end = token.getEndTimeBounds(); |
||
203 | long[] duration = token.getDurationBounds(); |
||
204 | |||
205 | // set default controllability type |
||
206 | ControllabilityType controllability = null; |
||
207 | // check specific type |
||
208 | if (tl.isExternal()) { |
||
209 | // uncontrollable |
||
210 | controllability = ControllabilityType.UNCONTROLLABLE; |
||
211 | |||
212 | } else if (token.getPredicate().startsWith("_")) { |
||
213 | // partially controllable token |
||
214 | controllability = ControllabilityType.PARTIALLY_CONTROLLABLE; |
||
215 | |||
216 | } else { |
||
217 | // controllable |
||
218 | controllability = ControllabilityType.CONTROLLABLE; |
||
219 | } |
||
220 | |||
221 | // set parameter information |
||
222 | String signature = token.getPredicate(); |
||
223 | String[] paramValues = new String[token.getParameters().size()]; |
||
224 | ParameterType[] paramTypes = new ParameterType[token.getParameters().size()]; |
||
225 | for (int index = 0; index < token.getParameters().size(); index++) { |
||
226 | |||
227 | // get parameter |
||
228 | ParameterDescriptor param= token.getParameter(index); |
||
229 | // check type |
||
230 | if (param.getType().equals(ParameterTypeDescriptor.NUMERIC)) |
||
231 | { |
||
232 | // set type |
||
233 | paramTypes[index] = ParameterType.NUMERIC_PARAMETER_TYPE; |
||
234 | // set value |
||
235 | paramValues[index] = Long.toString(param.getBounds()[0]); |
||
236 | } |
||
237 | else |
||
238 | { |
||
239 | // enumeration |
||
240 | paramTypes[index] = ParameterType.ENUMERATION_PARAMETER_TYPE; |
||
241 | // set value |
||
242 | paramValues[index] = param.getValues()[0]; |
||
243 | } |
||
244 | } |
||
245 | |||
246 | // create a node |
||
247 | ExecutionNode node = this.createNode(tl.getComponent(), tl.getName(), |
||
248 | signature, paramTypes, paramValues, |
||
249 | start, end, duration, controllability, token.getStartExecutionState()); |
||
250 | |||
251 | // add node |
||
252 | this.addNode(node); |
||
253 | // add entry to the dictionary |
||
254 | dictionary.put(token, node); |
||
255 | |||
256 | // add node to list |
||
257 | list[counter] = node; |
||
258 | counter++; |
||
259 | } |
||
260 | } |
||
261 | |||
262 | // link subsequent nodes |
||
263 | if (list.length > 1) { |
||
264 | for (int pos = 0; pos < list.length; pos++) { |
||
265 | |||
266 | // check first node |
||
267 | if (pos == 0) { |
||
268 | |||
269 | // first node of the timeline |
||
270 | ExecutionNode first = list[pos]; |
||
271 | // set next node |
||
272 | first.setNext(list[pos+1]); |
||
273 | |||
274 | } else if (pos == list.length - 1) { |
||
275 | |||
276 | // last node of the timeline |
||
277 | ExecutionNode last = list[pos]; |
||
278 | // set previous node |
||
279 | last.setPrev(list[pos-1]); |
||
280 | |||
281 | } else { |
||
282 | |||
283 | // intermediate node |
||
284 | ExecutionNode i = list[pos]; |
||
285 | // set previous |
||
286 | i.setPrev(list[pos-1]); |
||
287 | // set next |
||
288 | i.setNext(list[pos+1]); |
||
289 | } |
||
290 | } |
||
291 | } |
||
292 | } |
||
293 | |||
294 | // check observations |
||
295 | View Code Duplication | for (TimelineProtocolDescriptor tl : plan.getObservations()) { |
|
296 | |||
297 | // setup node arrays |
||
298 | ExecutionNode[] list = new ExecutionNode[tl.getTokens().size()]; |
||
299 | // list index |
||
300 | int counter = 0; |
||
301 | // create an execution node for each token |
||
302 | for (TokenProtocolDescriptor token : tl.getTokens()) { |
||
303 | // check predicate |
||
304 | if (!token.getPredicate().toLowerCase().equals("unallocated")) { |
||
305 | |||
306 | // get token's bound |
||
307 | long[] start = token.getStartTimeBounds(); |
||
308 | long[] end = token.getEndTimeBounds(); |
||
309 | long[] duration = token.getDurationBounds(); |
||
310 | |||
311 | // check controllability type |
||
312 | // set default controllability type |
||
313 | ControllabilityType controllability = null; |
||
314 | // check specific type |
||
315 | if (tl.isExternal()) { |
||
316 | |||
317 | // uncontrollable |
||
318 | controllability = ControllabilityType.UNCONTROLLABLE; |
||
319 | |||
320 | } else if (token.getPredicate().startsWith("_")) { |
||
321 | |||
322 | // partially controllable token |
||
323 | controllability = ControllabilityType.PARTIALLY_CONTROLLABLE; |
||
324 | |||
325 | } else { |
||
326 | |||
327 | // controllable token |
||
328 | controllability = ControllabilityType.CONTROLLABLE; |
||
329 | } |
||
330 | |||
331 | // set parameter information |
||
332 | String signature = token.getPredicate(); |
||
333 | String[] paramValues = new String[token.getParameters().size()]; |
||
334 | ParameterType[] paramTypes = new ParameterType[token.getParameters().size()]; |
||
335 | for (int index = 0; index < token.getParameters().size(); index++) { |
||
336 | |||
337 | // get parameter |
||
338 | ParameterDescriptor param= token.getParameter(index); |
||
339 | // check type |
||
340 | if (param.getType().equals(ParameterTypeDescriptor.NUMERIC)) { |
||
341 | // set t ype |
||
342 | paramTypes[index] = ParameterType.NUMERIC_PARAMETER_TYPE; |
||
343 | // set value |
||
344 | paramValues[index] = Long.toString(param.getBounds()[0]); |
||
345 | |||
346 | } else { |
||
347 | |||
348 | // enumeration |
||
349 | paramTypes[index] = ParameterType.ENUMERATION_PARAMETER_TYPE; |
||
350 | // set value |
||
351 | paramValues[index] = param.getValues()[0]; |
||
352 | } |
||
353 | } |
||
354 | |||
355 | // create a node |
||
356 | ExecutionNode node = this.createNode(tl.getComponent(), tl.getName(), |
||
357 | signature, paramTypes, paramValues, |
||
358 | start, end, duration, controllability, token.getStartExecutionState()); |
||
359 | |||
360 | // add node |
||
361 | this.addNode(node); |
||
362 | // add entry to the dictionary |
||
363 | dictionary.put(token, node); |
||
364 | |||
365 | // add node to list |
||
366 | list[counter] = node; |
||
367 | counter++; |
||
368 | } |
||
369 | |||
370 | } |
||
371 | |||
372 | // link subsequent nodes |
||
373 | for (int pos = 0; pos < list.length; pos++) { |
||
374 | |||
375 | // check first node |
||
376 | if (pos == 0) { |
||
377 | |||
378 | // first node of the timeline |
||
379 | ExecutionNode first = list[pos]; |
||
380 | // set next node |
||
381 | first.setNext(list[pos+1]); |
||
382 | |||
383 | } else if (pos == list.length - 1) { |
||
384 | // last node of the timeline |
||
385 | ExecutionNode last = list[pos]; |
||
386 | // set previous ndoe |
||
387 | last.setPrev(list[pos-1]); |
||
388 | |||
389 | } else { |
||
390 | |||
391 | // intermediate node |
||
392 | ExecutionNode i = list[pos]; |
||
393 | // set prev |
||
394 | i.setPrev(list[pos-1]); |
||
395 | // set next |
||
396 | i.setNext(list[pos+1]); |
||
397 | } |
||
398 | } |
||
399 | } |
||
400 | |||
401 | // check relations |
||
402 | for (RelationProtocolDescriptor rel : plan.getRelations()) { |
||
403 | try { |
||
404 | |||
405 | // get related nodes |
||
406 | ExecutionNode reference = dictionary.get(rel.getFrom()); |
||
407 | ExecutionNode target = dictionary.get(rel.getTo()); |
||
408 | // add temporal constraints and related execution dependencies |
||
409 | this.createConstraintsAndDependencies(reference, target, rel); |
||
410 | |||
411 | } catch (Exception ex) { |
||
412 | |||
413 | // exception |
||
414 | throw new TemporalConsistencyException("Error while propagating plan's relation " + rel + "\n" + ex.getMessage()); |
||
415 | } |
||
416 | } |
||
417 | |||
418 | // check consistency |
||
419 | this.facade.verifyTemporalConsistency(); |
||
420 | // check the schedule for all temporal intervals |
||
421 | for (ExecutionNode node : dictionary.values()) { |
||
422 | // check node schedule |
||
423 | IntervalScheduleQuery query = this.facade.createTemporalQuery(TemporalQueryType.INTERVAL_SCHEDULE); |
||
424 | query.setInterval(node.getInterval()); |
||
425 | this.facade.process(query); |
||
426 | } |
||
427 | |||
428 | // prepare log message |
||
429 | String msg = ""; |
||
430 | // print execution dependency graph (for debug only) |
||
431 | for (ExecutionNodeStatus status : this.nodes.keySet()) { |
||
432 | // get nodes by status |
||
433 | for (ExecutionNode node : this.nodes.get(status)) { |
||
434 | |||
435 | // print node and the related execution conditions |
||
436 | msg += "Execution node " + node + "\n"; |
||
437 | msg += "\tNode execution starting conditions:\n"; |
||
438 | Map<ExecutionNode, ExecutionNodeStatus> dependencies = this.getNodeStartDependencies(node); |
||
439 | for (ExecutionNode dep : dependencies.keySet()) { |
||
440 | msg += "\t\tCan start if -> " + dep.getId() + ":"+ dep.getGroundSignature() + " is in " + dependencies.get(dep) + "\n"; |
||
441 | } |
||
442 | |||
443 | // get end conditions |
||
444 | dependencies = this.getNodeEndDependencies(node); |
||
445 | msg += "\tNode execution ending conditions:\n"; |
||
446 | for (ExecutionNode dep : dependencies.keySet()) { |
||
447 | msg += "\t\tCan end if -> " + dep.getId() + ":" + dep.getGroundSignature() + " is in " + dependencies.get(dep) + "\n"; |
||
448 | } |
||
449 | } |
||
450 | } |
||
451 | |||
452 | // print log message |
||
453 | debug(msg); |
||
454 | |||
455 | } catch (TemporalIntervalCreationException ex) { |
||
456 | throw new RuntimeException(ex.getMessage()); |
||
457 | |||
458 | } catch (TemporalConsistencyException ex) { |
||
459 | throw new RuntimeException(ex.getMessage()); |
||
460 | } |
||
461 | } |
||
462 | |||
463 | |||
464 | |||
465 | /** |
||
466 | * |
||
467 | * @param reference |
||
468 | * @param target |
||
469 | * @param rel |
||
470 | * @throws Exception |
||
471 | */ |
||
472 | protected void createConstraintsAndDependencies(ExecutionNode reference, ExecutionNode target, Relation rel) |
||
473 | throws Exception { |
||
474 | |||
475 | // check temporal category |
||
476 | if (rel.getCategory().equals(ConstraintCategory.TEMPORAL_CONSTRAINT)) { |
||
477 | // check relation |
||
478 | switch (rel.getType()) { |
||
479 | |||
480 | // meets temporal relation |
||
481 | case MEETS : { |
||
482 | // get meets relation |
||
483 | MeetsRelation meets = (MeetsRelation) rel; |
||
484 | // prepare meets constraint |
||
485 | this.prepareMeetsTemporalConstraint(reference, target, meets.getBounds()); |
||
486 | } |
||
487 | break; |
||
488 | |||
489 | // before temporal relation |
||
490 | case BEFORE : { |
||
491 | // get before relation |
||
492 | BeforeRelation before = (BeforeRelation) rel; |
||
493 | // prepare before constraint |
||
494 | this.prepareBeforeTemporalConstraint(reference, target, before.getBounds()); |
||
495 | } |
||
496 | break; |
||
497 | |||
498 | case MET_BY : { |
||
499 | // get met-by relation |
||
500 | MetByRelation metby = (MetByRelation) rel; |
||
501 | this.prepareAfterTemporalConstraint(reference, target, metby.getBounds()); |
||
502 | } |
||
503 | break; |
||
504 | |||
505 | case AFTER : { |
||
506 | // get after relation |
||
507 | AfterRelation after = (AfterRelation) rel; |
||
508 | // prepare after constraint |
||
509 | this.prepareAfterTemporalConstraint(reference, target, after.getBounds()); |
||
510 | } |
||
511 | break; |
||
512 | |||
513 | case CONTAINS : { |
||
514 | // get contains relation |
||
515 | ContainsRelation contains = (ContainsRelation) rel; |
||
516 | // prepare contains constraint |
||
517 | this.prepareContainsTemporalConstraint(reference, target, contains.getBounds()); |
||
518 | } |
||
519 | break; |
||
520 | |||
521 | case DURING : { |
||
522 | // get during relation |
||
523 | DuringRelation during = (DuringRelation) rel; |
||
524 | // prepare during constraint |
||
525 | this.prepareDuringTemporalConstraint(reference, target, during.getBounds()); |
||
526 | } |
||
527 | break; |
||
528 | |||
529 | case EQUALS : { |
||
530 | // get equals relation |
||
531 | EqualsRelation equals = (EqualsRelation) rel; |
||
532 | // prepare equals constraint |
||
533 | this.prepareEqualsTemporalConstraint(reference, target, equals.getBounds()); |
||
534 | } |
||
535 | break; |
||
536 | |||
537 | case STARTS_DURING : { |
||
538 | // get starts-during relation |
||
539 | StartsDuringRelation sduring = (StartsDuringRelation) rel; |
||
540 | // prepare starts-during constraint |
||
541 | this.prepareStartsDuringTemporalConstraint(reference, target, sduring.getBounds()); |
||
542 | } |
||
543 | break; |
||
544 | |||
545 | case ENDS_DURING : { |
||
546 | // get ends-during relation |
||
547 | EndsDuringRelation eduring = (EndsDuringRelation) rel; |
||
548 | // prepare ends-during constraint |
||
549 | this.prepareEndsDuringTemporalConstraint(reference, target, eduring.getBounds()); |
||
550 | } |
||
551 | break; |
||
552 | |||
553 | default : { |
||
554 | throw new RuntimeException("Unknown relation " + rel.getType()); |
||
555 | } |
||
556 | |||
557 | } |
||
558 | } |
||
559 | } |
||
560 | |||
561 | /** |
||
562 | * |
||
563 | * @param reference |
||
564 | * @param target |
||
565 | * @param rel |
||
566 | */ |
||
567 | protected void createConstraintsAndDependencies(ExecutionNode reference, ExecutionNode target, RelationProtocolDescriptor rel) |
||
568 | throws Exception { |
||
569 | |||
570 | // check relation type |
||
571 | switch (rel.getType()) { |
||
572 | |||
573 | // meets temporal relation |
||
574 | case "meets" : { |
||
575 | // prepare meets constraint |
||
576 | this.prepareMeetsTemporalConstraint(reference, target, new long[][] { |
||
577 | {0, 0} |
||
578 | }); |
||
579 | } |
||
580 | break; |
||
581 | |||
582 | case "before" : { |
||
583 | // prepare before constraint |
||
584 | this.prepareBeforeTemporalConstraint(reference, target, new long[][] { |
||
585 | rel.getFirstBound() |
||
586 | }); |
||
587 | } |
||
588 | break; |
||
589 | |||
590 | case "met-by" : { |
||
591 | // prepare after constraint |
||
592 | this.prepareMeetsTemporalConstraint(target, reference, new long[][] { |
||
593 | {0, 0} |
||
594 | }); |
||
595 | } |
||
596 | break; |
||
597 | |||
598 | case "after" : { |
||
599 | // prepare after constraint |
||
600 | this.prepareAfterTemporalConstraint(reference, target, new long[][] { |
||
601 | rel.getFirstBound() |
||
602 | }); |
||
603 | } |
||
604 | break; |
||
605 | |||
606 | case "during" : { |
||
607 | // prepare during constraint |
||
608 | this.prepareDuringTemporalConstraint(reference, target, new long[][] { |
||
609 | rel.getFirstBound(), |
||
610 | rel.getSecondBound() |
||
611 | }); |
||
612 | } |
||
613 | break; |
||
614 | |||
615 | case "contains" : { |
||
616 | // prepare contains constraint |
||
617 | this.prepareContainsTemporalConstraint(reference, target, new long[][] { |
||
618 | rel.getFirstBound(), |
||
619 | rel.getSecondBound() |
||
620 | }); |
||
621 | } |
||
622 | break; |
||
623 | |||
624 | case "equals" : { |
||
625 | // prepare equals constraint |
||
626 | this.prepareEqualsTemporalConstraint(reference, target, new long[][] { |
||
627 | {0, 0}, |
||
628 | {0, 0} |
||
629 | }); |
||
630 | } |
||
631 | break; |
||
632 | |||
633 | case "starts_during" : { |
||
634 | // prepare starts-during constraint |
||
635 | this.prepareStartsDuringTemporalConstraint(reference, target, new long[][] { |
||
636 | rel.getFirstBound(), |
||
637 | rel.getSecondBound() |
||
638 | }); |
||
639 | } |
||
640 | break; |
||
641 | |||
642 | case "ends_during" : { |
||
643 | // prepare ends-during constraint |
||
644 | this.prepareEndsDuringTemporalConstraint(reference, target, new long[][] { |
||
645 | rel.getFirstBound(), |
||
646 | rel.getSecondBound() |
||
647 | }); |
||
648 | } |
||
649 | break; |
||
650 | |||
651 | default : { |
||
652 | // unknown temporal relation |
||
653 | throw new RuntimeException("Unknown relation " + rel.getType()); |
||
654 | } |
||
655 | } |
||
656 | } |
||
657 | |||
658 | |||
659 | /** |
||
660 | * |
||
661 | * @return |
||
662 | */ |
||
663 | public List<ExecutionNode> getNodesByStatus(ExecutionNodeStatus status) { |
||
664 | |||
665 | // list of nodes |
||
666 | List<ExecutionNode> list = new LinkedList<>(); |
||
667 | synchronized (this.locks[status.getIndex()]) { |
||
668 | // get all nodes with the desired status |
||
669 | list.addAll(this.nodes.get(status)); |
||
670 | } |
||
671 | |||
672 | // get the list of node with the desired status |
||
673 | return list; |
||
674 | } |
||
675 | |||
676 | /** |
||
677 | * |
||
678 | * @param node |
||
679 | * @param status |
||
680 | */ |
||
681 | public synchronized void updateNodeStatus(ExecutionNode node, ExecutionNodeStatus status) { |
||
682 | |||
683 | // remove node from the current status |
||
684 | synchronized (this.locks[node.getStatus().getIndex()]) { |
||
685 | // remove node from list |
||
686 | this.nodes.get(node.getStatus()).remove(node); |
||
687 | } |
||
688 | |||
689 | // add node to the new status |
||
690 | synchronized (this.locks[status.getIndex()]) { |
||
691 | // add node |
||
692 | this.nodes.get(status).add(node); |
||
693 | // update status |
||
694 | node.setStatus(status); |
||
695 | } |
||
696 | } |
||
697 | |||
698 | /** |
||
699 | * |
||
700 | * @param node |
||
701 | * @return |
||
702 | */ |
||
703 | public Map<ExecutionNode, ExecutionNodeStatus> getNodeStartDependencies(ExecutionNode node) { |
||
704 | return new HashMap<>(this.sdg.get(node)); |
||
705 | } |
||
706 | |||
707 | /** |
||
708 | * |
||
709 | * @param node |
||
710 | * @return |
||
711 | */ |
||
712 | public Map<ExecutionNode, ExecutionNodeStatus> getNodeEndDependencies(ExecutionNode node) { |
||
713 | return new HashMap<>(this.edg.get(node)); |
||
714 | } |
||
715 | |||
716 | /** |
||
717 | * |
||
718 | * @param node |
||
719 | */ |
||
720 | public void checkSchedule(ExecutionNode node) { |
||
721 | |||
722 | // check resulting schedule of the interval |
||
723 | IntervalScheduleQuery query = this.facade. |
||
724 | createTemporalQuery(TemporalQueryType.INTERVAL_SCHEDULE); |
||
725 | query.setInterval(node.getInterval()); |
||
726 | this.facade.process(query); |
||
727 | } |
||
728 | |||
729 | /** |
||
730 | * |
||
731 | * @param node |
||
732 | */ |
||
733 | public void addNode(ExecutionNode node) { |
||
734 | |||
735 | // check expected initial execution state |
||
736 | ExecutionNodeStatus initial = node.getStartExecutionState(); |
||
737 | node.setStatus(initial); |
||
738 | this.nodes.get(initial).add(node); |
||
739 | // setup dependency graph data structures |
||
740 | this.sdg.put(node, new HashMap<ExecutionNode, ExecutionNodeStatus>()); |
||
741 | this.edg.put(node, new HashMap<ExecutionNode, ExecutionNodeStatus>()); |
||
742 | } |
||
743 | |||
744 | /** |
||
745 | * |
||
746 | */ |
||
747 | public void clearExecutedNodes() { |
||
748 | |||
749 | // check executed nodes |
||
750 | Set<ExecutionNode> nodes = new HashSet<>(this.nodes.get(ExecutionNodeStatus.EXECUTED)); |
||
751 | // clear nodes |
||
752 | this.nodes.get(ExecutionNodeStatus.EXECUTED).clear(); |
||
753 | // clear execution graph |
||
754 | for (ExecutionNode node : nodes) { |
||
755 | // clear map entries |
||
756 | this.sdg.remove(node); |
||
757 | this.edg.remove(node); |
||
758 | |||
759 | // clear edges |
||
760 | for (ExecutionNode n : this.sdg.keySet()) { |
||
761 | // remove edge |
||
762 | this.sdg.get(n).remove(node); |
||
763 | |||
764 | } |
||
765 | |||
766 | // clear edges |
||
767 | for (ExecutionNode n : this.edg.keySet()) { |
||
768 | // remove edge |
||
769 | this.edg.get(n).remove(node); |
||
770 | } |
||
771 | } |
||
772 | } |
||
773 | |||
774 | /** |
||
775 | * |
||
776 | * @param component |
||
777 | * @param timeline |
||
778 | * @param signature |
||
779 | * @param pTypes |
||
780 | * @param pValues |
||
781 | * @param start |
||
782 | * @param end |
||
783 | * @param duration |
||
784 | * @param controllability |
||
785 | * @param state |
||
786 | * @return |
||
787 | * @throws TemporalIntervalCreationException |
||
788 | */ |
||
789 | protected ExecutionNode createNode(String component, String timeline, |
||
790 | String signature, ParameterType[] pTypes, String[] pValues, |
||
791 | long[] start, long[] end, long[] duration, |
||
792 | ControllabilityType controllability, |
||
793 | ExecutionNodeStatus state) |
||
794 | throws TemporalIntervalCreationException { |
||
795 | |||
796 | // create temporal interval - consider all intervals as controllable during execution |
||
797 | TemporalInterval interval = this.facade.createTemporalInterval(start, end, duration, true); |
||
798 | // create predicate |
||
799 | NodePredicate predicate = new NodePredicate(component, timeline, signature, pTypes, pValues); |
||
800 | // create execution node |
||
801 | return new ExecutionNode(predicate, interval, controllability, state); |
||
802 | } |
||
803 | |||
804 | /** |
||
805 | * |
||
806 | * @param node |
||
807 | * @param dependency |
||
808 | * @param condition |
||
809 | */ |
||
810 | protected void addStartExecutionDependency(ExecutionNode node, ExecutionNode dependency, ExecutionNodeStatus condition) { |
||
811 | // add node's start dependency and related condition |
||
812 | this.sdg.get(node).put(dependency, condition); |
||
813 | } |
||
814 | |||
815 | /** |
||
816 | * |
||
817 | * @param node |
||
818 | * @param dependency |
||
819 | * @param condition |
||
820 | */ |
||
821 | protected void addEndExecutionDependency(ExecutionNode node, ExecutionNode dependency, ExecutionNodeStatus condition) { |
||
822 | // add node's end dependency and related condition |
||
823 | this.edg.get(node).put(dependency, condition); |
||
824 | } |
||
825 | |||
826 | /** |
||
827 | * |
||
828 | * @param node |
||
829 | * @return |
||
830 | */ |
||
831 | public boolean checkEndExecutionDependencies(ExecutionNode node) { |
||
832 | |||
833 | // flag |
||
834 | boolean canEnd = true; |
||
835 | Map<ExecutionNode, ExecutionNodeStatus> dependencies = this.getNodeEndDependencies(node); |
||
836 | if (!dependencies.isEmpty()) { |
||
837 | // check if conditions are satisfied |
||
838 | Iterator<ExecutionNode> it = dependencies.keySet().iterator(); |
||
839 | while (it.hasNext() && canEnd) { |
||
840 | // get next dependency |
||
841 | ExecutionNode d = it.next(); |
||
842 | canEnd = d.getStatus().equals(dependencies.get(d)); |
||
843 | } |
||
844 | } |
||
845 | |||
846 | // true if the node can end execution |
||
847 | return canEnd; |
||
848 | } |
||
849 | |||
850 | /** |
||
851 | * |
||
852 | * @param node |
||
853 | * @return |
||
854 | */ |
||
855 | public boolean checkStartExecutionDependencies(ExecutionNode node) { |
||
856 | |||
857 | // flag |
||
858 | boolean canStart = true; |
||
859 | // get node's start dependencies |
||
860 | Map<ExecutionNode, ExecutionNodeStatus> dependencies = this.getNodeStartDependencies(node); |
||
861 | if (!dependencies.isEmpty()) { |
||
862 | |||
863 | // check if conditions are satisfied |
||
864 | Iterator<ExecutionNode> it = dependencies.keySet().iterator(); |
||
865 | while (it.hasNext() && canStart) { |
||
866 | // get a dependency parent |
||
867 | ExecutionNode d = it.next(); |
||
868 | // check condition |
||
869 | canStart = d.getStatus().equals(dependencies.get(d)); |
||
870 | } |
||
871 | } |
||
872 | |||
873 | // true if ready |
||
874 | return canStart; |
||
875 | } |
||
876 | |||
877 | /** |
||
878 | * |
||
879 | * @param node |
||
880 | * @param duration |
||
881 | * @throws TemporalConstraintPropagationException |
||
882 | */ |
||
883 | public final void scheduleDuration(ExecutionNode node, long duration) |
||
884 | throws TemporalConstraintPropagationException { |
||
885 | |||
886 | // fix start time first |
||
887 | FixIntervalDurationConstraint fix = this.facade. |
||
888 | createTemporalConstraint(TemporalConstraintType.FIX_INTERVAL_DURATION); |
||
889 | fix.setReference(node.getInterval()); |
||
890 | fix.setDuration(duration); |
||
891 | // propagate constraint |
||
892 | this.facade.propagate(fix); |
||
893 | try { |
||
894 | |||
895 | // check the consistency of the resulting network |
||
896 | this.facade.verifyTemporalConsistency(); |
||
897 | |||
898 | } catch (TemporalConsistencyException ex) { |
||
899 | // retract propagated constraint and throw exception |
||
900 | this.facade.retract(fix); |
||
901 | throw new TemporalConstraintPropagationException("Error while propagating duration constraint for node\n- duration= " + duration +"\n- node= " + node + "\n"); |
||
902 | } |
||
903 | } |
||
904 | |||
905 | /** |
||
906 | * |
||
907 | * @param node |
||
908 | * @param time |
||
909 | * @throws TemporalConstraintPropagationException |
||
910 | */ |
||
911 | View Code Duplication | public final void scheduleStartTime(ExecutionNode node, long time) |
|
912 | throws TemporalConstraintPropagationException { |
||
913 | |||
914 | // create constraint |
||
915 | FixTimePointConstraint fix = this.facade. |
||
916 | createTemporalConstraint(TemporalConstraintType.FIX_TIME_POINT); |
||
917 | // set time point |
||
918 | fix.setReference(node.getInterval().getStartTime()); |
||
919 | fix.setTime(time); |
||
920 | // propagate constraint |
||
921 | this.facade.propagate(fix); |
||
922 | try { |
||
923 | |||
924 | // check consistency of the resulting network |
||
925 | this.facade.verifyTemporalConsistency(); |
||
926 | |||
927 | } catch (TemporalConsistencyException ex) { |
||
928 | // retract propagated constraint and throw exception |
||
929 | this.facade.retract(fix); |
||
930 | throw new TemporalConstraintPropagationException("Error while propagating start constraint for node\n- " |
||
931 | + "time= " + time+ "\n- node= " + node + "\n"); |
||
932 | } |
||
933 | } |
||
934 | |||
935 | /** |
||
936 | * |
||
937 | * @param node |
||
938 | * @param end |
||
939 | * @throws TemporalConstraintPropagationException |
||
940 | */ |
||
941 | View Code Duplication | public void scheduleEndTime(ExecutionNode node, long time) |
|
942 | throws TemporalConstraintPropagationException { |
||
943 | |||
944 | // create constraint |
||
945 | FixTimePointConstraint fix = this.facade. |
||
946 | createTemporalConstraint(TemporalConstraintType.FIX_TIME_POINT); |
||
947 | // set time point |
||
948 | fix.setReference(node.getInterval().getEndTime()); |
||
949 | // set time |
||
950 | fix.setTime(time); |
||
951 | // propagate constraint |
||
952 | this.facade.propagate(fix); |
||
953 | try { |
||
954 | |||
955 | // check consistency of the resulting network |
||
956 | this.facade.verifyTemporalConsistency(); |
||
957 | |||
958 | } catch (TemporalConsistencyException ex) { |
||
959 | // retract propagated constraint and throw exception |
||
960 | this.facade.retract(fix); |
||
961 | throw new TemporalConstraintPropagationException("Error while propagating end constraint for node\n" |
||
962 | + "- time= " + time+ "\n- node= " + node + "\n"); |
||
963 | } |
||
964 | } |
||
965 | |||
966 | /** |
||
967 | * |
||
968 | * @param reference |
||
969 | * @param target |
||
970 | * @param bounds |
||
971 | * @throws Exception |
||
972 | */ |
||
973 | protected void prepareBeforeTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
974 | throws Exception { |
||
975 | |||
976 | // create and propagate temporal constraint |
||
977 | BeforeIntervalConstraint constraint = this.facade. |
||
978 | createTemporalConstraint(TemporalConstraintType.BEFORE); |
||
979 | |||
980 | // set data |
||
981 | constraint.setReference(reference.getInterval()); |
||
982 | constraint.setTarget(target.getInterval()); |
||
983 | constraint.setLowerBound(bounds[0][0]); |
||
984 | constraint.setUpperBound(bounds[0][1]); |
||
985 | // propagate constraint |
||
986 | this.facade.propagate(constraint); |
||
987 | |||
988 | // set execution constraints |
||
989 | this.addStartExecutionDependency(target, reference, ExecutionNodeStatus.EXECUTED); |
||
990 | } |
||
991 | |||
992 | /** |
||
993 | * |
||
994 | * @param reference |
||
995 | * @param target |
||
996 | * @param bounds |
||
997 | * @throws Exception |
||
998 | */ |
||
999 | protected void prepareMeetsTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
1000 | throws Exception { |
||
1001 | |||
1002 | // create and propagate temporal constraint |
||
1003 | MeetsIntervalConstraint constraint = this.facade. |
||
1004 | createTemporalConstraint(TemporalConstraintType.MEETS); |
||
1005 | // set data |
||
1006 | constraint.setReference(reference.getInterval()); |
||
1007 | constraint.setTarget(target.getInterval()); |
||
1008 | // propagate constraint |
||
1009 | this.facade.propagate(constraint); |
||
1010 | |||
1011 | // set execution constraints |
||
1012 | this.addStartExecutionDependency(target, reference, ExecutionNodeStatus.EXECUTED); |
||
1013 | } |
||
1014 | |||
1015 | /** |
||
1016 | * |
||
1017 | * @param reference |
||
1018 | * @param target |
||
1019 | * @param bounds |
||
1020 | * @throws Exception |
||
1021 | */ |
||
1022 | protected void prepareAfterTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
1023 | throws Exception { |
||
1024 | |||
1025 | // create constraint |
||
1026 | AfterIntervalConstraint constraint = this.facade. |
||
1027 | createTemporalConstraint(TemporalConstraintType.AFTER); |
||
1028 | // set references |
||
1029 | constraint.setReference(reference.getInterval()); |
||
1030 | constraint.setTarget(target.getInterval()); |
||
1031 | |||
1032 | // set bounds |
||
1033 | constraint.setLowerBound(bounds[0][0]); |
||
1034 | constraint.setUpperBound(bounds[0][1]); |
||
1035 | // propagate temporal constraint |
||
1036 | this.facade.propagate(constraint); |
||
1037 | |||
1038 | // add execution dependencies |
||
1039 | this.addStartExecutionDependency(reference, target, ExecutionNodeStatus.EXECUTED); |
||
1040 | } |
||
1041 | |||
1042 | /** |
||
1043 | * |
||
1044 | * @param reference |
||
1045 | * @param target |
||
1046 | * @param bounds |
||
1047 | * @throws Exception |
||
1048 | */ |
||
1049 | protected void prepareDuringTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
1050 | throws Exception { |
||
1051 | |||
1052 | // create constraint |
||
1053 | DuringIntervalConstraint constraint = this.facade. |
||
1054 | createTemporalConstraint(TemporalConstraintType.DURING); |
||
1055 | // set references |
||
1056 | constraint.setReference(reference.getInterval()); |
||
1057 | constraint.setTarget(target.getInterval()); |
||
1058 | |||
1059 | // set bounds |
||
1060 | constraint.setStartTimeBound(bounds[0]); |
||
1061 | constraint.setEndTimeBound(bounds[1]); |
||
1062 | // propagate temporal constraint |
||
1063 | this.facade.propagate(constraint); |
||
1064 | // add execution dependencies |
||
1065 | this.addStartExecutionDependency(reference, target, ExecutionNodeStatus.IN_EXECUTION); |
||
1066 | this.addEndExecutionDependency(reference, target, ExecutionNodeStatus.IN_EXECUTION); |
||
1067 | |||
1068 | this.addEndExecutionDependency(target, reference, ExecutionNodeStatus.EXECUTED); |
||
1069 | } |
||
1070 | |||
1071 | /** |
||
1072 | * |
||
1073 | * @param reference |
||
1074 | * @param target |
||
1075 | * @param bounds |
||
1076 | * @throws Exception |
||
1077 | */ |
||
1078 | protected void prepareContainsTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
1079 | throws Exception { |
||
1080 | |||
1081 | // create constraint |
||
1082 | ContainsIntervalConstraint constraint = this.facade. |
||
1083 | createTemporalConstraint(TemporalConstraintType.CONTAINS); |
||
1084 | // set references |
||
1085 | constraint.setReference(reference.getInterval()); |
||
1086 | constraint.setTarget(target.getInterval()); |
||
1087 | |||
1088 | // set bounds |
||
1089 | constraint.setStartTimeBound(bounds[0]); |
||
1090 | constraint.setEndTimeBound(bounds[1]); |
||
1091 | // propagate temporal constraint |
||
1092 | this.facade.propagate(constraint); |
||
1093 | // add execution dependencies |
||
1094 | this.addStartExecutionDependency(target, reference, ExecutionNodeStatus.IN_EXECUTION); |
||
1095 | this.addEndExecutionDependency(target, reference, ExecutionNodeStatus.IN_EXECUTION); |
||
1096 | |||
1097 | this.addEndExecutionDependency(reference, target, ExecutionNodeStatus.EXECUTED); |
||
1098 | } |
||
1099 | |||
1100 | /** |
||
1101 | * |
||
1102 | * @param reference |
||
1103 | * @param target |
||
1104 | * @param bounds |
||
1105 | * @throws Exception |
||
1106 | */ |
||
1107 | protected void prepareEqualsTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
1108 | throws Exception { |
||
1109 | |||
1110 | // create constraint |
||
1111 | EqualsIntervalConstraint constraint = this.facade. |
||
1112 | createTemporalConstraint(TemporalConstraintType.EQUALS); |
||
1113 | // set references |
||
1114 | constraint.setReference(reference.getInterval()); |
||
1115 | constraint.setTarget(target.getInterval()); |
||
1116 | // propagate temporal constraint |
||
1117 | this.facade.propagate(constraint); |
||
1118 | } |
||
1119 | |||
1120 | /** |
||
1121 | * |
||
1122 | * @param reference |
||
1123 | * @param target |
||
1124 | * @param bounds |
||
1125 | * @throws Exception |
||
1126 | */ |
||
1127 | protected void prepareStartsDuringTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
1128 | throws Exception { |
||
1129 | |||
1130 | // create constraint |
||
1131 | StartsDuringIntervalConstraint constraint = this.facade. |
||
1132 | createTemporalConstraint(TemporalConstraintType.STARTS_DURING); |
||
1133 | // set references |
||
1134 | constraint.setReference(reference.getInterval()); |
||
1135 | constraint.setTarget(target.getInterval()); |
||
1136 | |||
1137 | // set bounds |
||
1138 | constraint.setFirstBound(bounds[0]); |
||
1139 | constraint.setSecondBound(bounds[1]); |
||
1140 | // propagate temporal constraint |
||
1141 | this.facade.propagate(constraint); |
||
1142 | |||
1143 | // add start dependency |
||
1144 | this.addStartExecutionDependency(reference, target, ExecutionNodeStatus.IN_EXECUTION); |
||
1145 | } |
||
1146 | |||
1147 | /** |
||
1148 | * |
||
1149 | * @param reference |
||
1150 | * @param target |
||
1151 | * @param bounds |
||
1152 | * @throws Exception |
||
1153 | */ |
||
1154 | protected void prepareEndsDuringTemporalConstraint(ExecutionNode reference, ExecutionNode target, long[][] bounds) |
||
1155 | throws Exception { |
||
1156 | |||
1157 | // create constraint |
||
1158 | EndsDuringIntervalConstraint constraint = this.facade. |
||
1159 | createTemporalConstraint(TemporalConstraintType.ENDS_DURING); |
||
1160 | |||
1161 | // set references |
||
1162 | constraint.setReference(reference.getInterval()); |
||
1163 | constraint.setTarget(target.getInterval()); |
||
1164 | // set bounds |
||
1165 | constraint.setFirstBound(bounds[0]); |
||
1166 | constraint.setSecondBound(bounds[1]); |
||
1167 | // propagate temporal constraint |
||
1168 | this.facade.propagate(constraint); |
||
1169 | |||
1170 | // add end dependency |
||
1171 | this.addEndExecutionDependency(reference, target, ExecutionNodeStatus.IN_EXECUTION); |
||
1172 | } |
||
1173 | } |
The Java documentation explain EnumMap.