Total Complexity | 98 |
Total Lines | 1117 |
Duplicated Lines | 9.31 % |
Changes | 4 | ||
Bugs | 1 | 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.control.acting.GoalOrientedActingAgent 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.control.acting; |
||
42 | public class GoalOrientedActingAgent implements PlatformObserver { |
||
43 | |||
44 | private final Object lock; // lock state; |
||
45 | private ActingAgentStatus status; // agent status |
||
46 | |||
47 | private final Map<GoalStatus, List<Goal>> queue; // goal queue |
||
48 | |||
49 | private String ddl; // path to the domain specification file |
||
50 | private PlanDataBase pdb; // internal plan database representation |
||
51 | |||
52 | private List<Thread> processes; // goal oriented processes |
||
53 | private DeliberativeProcess deliberative; // internal deliberative process |
||
54 | private Class<? extends Planner> pClass; // planner class |
||
55 | private boolean displayPlan; // display plan flag |
||
56 | |||
57 | private ExecutiveProcess executive; // internal executive process |
||
58 | private ContingencyHandlerProcess contingencyHandler; // internal contingency handler process |
||
59 | private Class<? extends Executive> eClass; // executive class |
||
60 | |||
61 | protected PlatformProxy proxy; |
||
62 | private FilePropertyReader properties; |
||
63 | |||
64 | /** |
||
65 | * |
||
66 | * @param agentPropertyFile |
||
67 | */ |
||
68 | @SuppressWarnings("unchecked") |
||
69 | public GoalOrientedActingAgent(String agentPropertyFile) { |
||
70 | |||
71 | try { |
||
72 | |||
73 | // set lock and status |
||
74 | this.lock = new Object(); |
||
75 | // set status |
||
76 | this.status = ActingAgentStatus.OFFLINE; |
||
77 | // set goal buffer |
||
78 | this.queue = new HashMap<>(); |
||
|
|||
79 | // set goal queue |
||
80 | for (GoalStatus s : GoalStatus.values()) { |
||
81 | this.queue.put(s, new LinkedList<>()); |
||
82 | } |
||
83 | |||
84 | // set internal plan database representation |
||
85 | this.pdb = null; |
||
86 | // set platform |
||
87 | this.processes = null; |
||
88 | |||
89 | |||
90 | // get agent property file |
||
91 | this.properties = new FilePropertyReader(agentPropertyFile); |
||
92 | |||
93 | // get DDL file |
||
94 | String ddlFile = this.properties.getProperty("model"); |
||
95 | // check if null |
||
96 | if (ddlFile == null || ddlFile.equals("")) { |
||
97 | throw new RuntimeException("You need to specify an acting model of the agent in \"etc/agent.properties\"!"); |
||
98 | } |
||
99 | |||
100 | // set the model |
||
101 | this.ddl = ddlFile; |
||
102 | |||
103 | // read the class name of the planner |
||
104 | String plannerClassName = this.properties.getProperty("planner"); |
||
105 | // set planner class |
||
106 | this.pClass = (Class<? extends Planner>) Class.forName(plannerClassName); |
||
107 | // set display plan flag |
||
108 | this.displayPlan = this.properties.getProperty("display_plan").equals("1") ? true : false; |
||
109 | |||
110 | // read the class name of the executive |
||
111 | String executiveClassName = this.properties.getProperty("executive"); |
||
112 | // set executive class |
||
113 | this.eClass = (Class<? extends Executive>) Class.forName(executiveClassName); |
||
114 | |||
115 | |||
116 | |||
117 | // read the class of the platform |
||
118 | String platformClassName = this.properties.getProperty("platform"); |
||
119 | // check if a platform is necessary |
||
120 | if (platformClassName != null && !platformClassName.equals("")) { |
||
121 | |||
122 | // get platform configuration file |
||
123 | String configFile = this.properties.getProperty("platform_config_file"); |
||
124 | // check platform configuration file |
||
125 | if (configFile == null || configFile.equals("")) { |
||
126 | throw new RuntimeException("Specify a configuration file for the platform in \"" + agentPropertyFile + "\"!"); |
||
127 | } |
||
128 | |||
129 | // print agent configuration |
||
130 | System.out.println("Configuration of the Goal-Oriented Acting Agent:\n" |
||
131 | + "\tDDL file: " + ddlFile + "\n" |
||
132 | + "\tDeliberative Clas: " + plannerClassName + "\n" |
||
133 | + "\tExecutive Class: " + executiveClassName + "\n" |
||
134 | + "\tPlatform Class: " + platformClassName + "\n" |
||
135 | + "\tPlatform Config file: " + configFile + "\n"); |
||
136 | |||
137 | |||
138 | // create platform PROXY |
||
139 | Class<? extends PlatformProxy> clazz = (Class<? extends PlatformProxy>) Class.forName(platformClassName); |
||
140 | // create PROXY |
||
141 | this.proxy = PlatformProxyBuilder.build(clazz, configFile); |
||
142 | |||
143 | } else { |
||
144 | |||
145 | // print agent configuration |
||
146 | System.out.println("Configuration of the Goal-Oriented Acting Agent:\n" |
||
147 | + "\tDDL file: " + ddlFile + "\n" |
||
148 | + "\tDeliberative Clas: " + plannerClassName + "\n" |
||
149 | + "\tExecutive Class: " + executiveClassName + "\n"); |
||
150 | } |
||
151 | |||
152 | |||
153 | // setup deliberative and executive processes |
||
154 | this.setupProcesses(); |
||
155 | |||
156 | } catch (Exception ex) { |
||
157 | throw new RuntimeException(ex.getMessage()); |
||
158 | } |
||
159 | |||
160 | |||
161 | } |
||
162 | |||
163 | |||
164 | /** |
||
165 | * |
||
166 | */ |
||
167 | private void setupProcesses() { |
||
168 | |||
169 | // set the list of processes |
||
170 | this.processes = new ArrayList<>(); |
||
171 | // set goal listener thread |
||
172 | this.processes.add(new Thread(new Runnable() { |
||
173 | |||
174 | /** |
||
175 | * |
||
176 | */ |
||
177 | @Override |
||
178 | public void run() { |
||
179 | |||
180 | boolean running = true; |
||
181 | while(running) { |
||
182 | |||
183 | try { |
||
184 | |||
185 | // check buffered goals |
||
186 | Goal goal = waitGoal(GoalStatus.BUFFERED); |
||
187 | System.out.println("Selecting goal.. \n" + goal + "\n"); |
||
188 | // simply select the extracted goal |
||
189 | select(goal); |
||
190 | |||
191 | } catch (InterruptedException ex) { |
||
192 | running = false; |
||
193 | } |
||
194 | } |
||
195 | } |
||
196 | })); |
||
197 | |||
198 | |||
199 | // set goal deliberative |
||
200 | this.deliberative = new DeliberativeProcess(this.pClass, this.displayPlan, this); |
||
201 | this.processes.add(new Thread(this.deliberative)); |
||
202 | |||
203 | // set goal executive |
||
204 | this.executive = new ExecutiveProcess(this.eClass, this); |
||
205 | this.processes.add(new Thread(this.executive)); |
||
206 | |||
207 | // set goal failure handler |
||
208 | this.contingencyHandler = new ContingencyHandlerProcess(this); |
||
209 | this.processes.add(new Thread(this.contingencyHandler)); |
||
210 | |||
211 | // finally register to platform events |
||
212 | if (this.proxy != null) { |
||
213 | this.proxy.register(this); |
||
214 | } |
||
215 | } |
||
216 | |||
217 | |||
218 | /** |
||
219 | * |
||
220 | * @return |
||
221 | */ |
||
222 | public synchronized ActingAgentStatus getStatus() { |
||
223 | return status; |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * |
||
228 | */ |
||
229 | @Override |
||
230 | public void task(AgentTaskDescription task) { |
||
231 | // buffer task planning request |
||
232 | this.buffer(task); |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * |
||
237 | */ |
||
238 | @Override |
||
239 | public void feedback(PlatformFeedback feedback) { |
||
240 | // nothing to do |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * |
||
245 | */ |
||
246 | @Override |
||
247 | public void observation(PlatformObservation<? extends Object> obs) { |
||
248 | // nothing to do |
||
249 | } |
||
250 | |||
251 | |||
252 | /** |
||
253 | * Trigger acting process by buffering a description of a goal to plan and execute for |
||
254 | * |
||
255 | * @param description |
||
256 | */ |
||
257 | public void buffer(AgentTaskDescription description) { |
||
258 | |||
259 | // protect access to the queue |
||
260 | synchronized (this.queue) { |
||
261 | System.out.println("[Agent] Receiving task ...\n" + description + "\n"); |
||
262 | // create goal |
||
263 | Goal goal = new Goal(description); |
||
264 | // set goal status |
||
265 | goal.setStatus(GoalStatus.BUFFERED); |
||
266 | // add a goal to the queue |
||
267 | this.queue.get(goal.getStatus()).add(goal); |
||
268 | // send signal |
||
269 | this.queue.notifyAll(); |
||
270 | } |
||
271 | } |
||
272 | |||
273 | /** |
||
274 | * Blocking call returning a list of finished or aborted goals. |
||
275 | * |
||
276 | * @return |
||
277 | * @throws InterruptedException |
||
278 | */ |
||
279 | public List<Goal> getResults() |
||
280 | throws InterruptedException { |
||
281 | |||
282 | // wait some finished or aborted goal |
||
283 | List<Goal> goals = new ArrayList<>(); |
||
284 | synchronized (this.queue) { |
||
285 | |||
286 | while (this.queue.get(GoalStatus.ABORTED).isEmpty() && |
||
287 | this.queue.get(GoalStatus.FINISHED).isEmpty()) { |
||
288 | // wait |
||
289 | this.queue.wait(); |
||
290 | } |
||
291 | |||
292 | // take aborted goals |
||
293 | goals.addAll(this.queue.get(GoalStatus.ABORTED)); |
||
294 | // clear queue |
||
295 | this.queue.get(GoalStatus.ABORTED).clear(); |
||
296 | // take finished goals |
||
297 | goals.addAll(this.queue.get(GoalStatus.FINISHED)); |
||
298 | // clear queue |
||
299 | this.queue.get(GoalStatus.FINISHED).clear(); |
||
300 | |||
301 | // send signal |
||
302 | this.queue.notifyAll(); |
||
303 | } |
||
304 | |||
305 | // get finished and aborted goals |
||
306 | return goals; |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * |
||
311 | */ |
||
312 | protected void select(Goal goal) { |
||
313 | |||
314 | // protect access to the queue |
||
315 | synchronized (this.queue) { |
||
316 | |||
317 | // remove goal form the current queue |
||
318 | this.queue.get(goal.getStatus()).remove(goal); |
||
319 | // set goal status |
||
320 | goal.setStatus(GoalStatus.SELECTED); |
||
321 | // add goal to the queue |
||
322 | this.queue.get(goal.getStatus()).add(goal); |
||
323 | // send signal |
||
324 | this.queue.notifyAll(); |
||
325 | } |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * |
||
330 | */ |
||
331 | protected void commit(Goal goal) { |
||
332 | |||
333 | // protect access to the queue |
||
334 | synchronized (this.queue) { |
||
335 | |||
336 | // remove goal form the current queue |
||
337 | this.queue.get(goal.getStatus()).remove(goal); |
||
338 | // set goal status |
||
339 | goal.setStatus(GoalStatus.COMMITTED); |
||
340 | // add goal to the queue |
||
341 | this.queue.get(goal.getStatus()).add(goal); |
||
342 | // send signal |
||
343 | this.queue.notifyAll(); |
||
344 | } |
||
345 | } |
||
346 | |||
347 | /** |
||
348 | * |
||
349 | */ |
||
350 | protected void suspend(Goal goal) { |
||
351 | |||
352 | // protect access to the queue |
||
353 | synchronized (this.queue) { |
||
354 | |||
355 | // remove goal form the current queue |
||
356 | this.queue.get(goal.getStatus()).remove(goal); |
||
357 | // set goal status |
||
358 | goal.setStatus(GoalStatus.SUSPENDED); |
||
359 | // add goal to the queue |
||
360 | this.queue.get(goal.getStatus()).add(goal); |
||
361 | // send signal |
||
362 | this.queue.notifyAll(); |
||
363 | } |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * |
||
368 | */ |
||
369 | protected void finish(Goal goal) { |
||
370 | |||
371 | // protect access to the queue |
||
372 | synchronized (this.queue) { |
||
373 | |||
374 | // remove goal form the current queue |
||
375 | this.queue.get(goal.getStatus()).remove(goal); |
||
376 | // set goal status |
||
377 | goal.setStatus(GoalStatus.FINISHED); |
||
378 | // add goal to the queue |
||
379 | this.queue.get(goal.getStatus()).add(goal); |
||
380 | // send signal |
||
381 | this.queue.notifyAll(); |
||
382 | } |
||
383 | } |
||
384 | |||
385 | /** |
||
386 | * |
||
387 | */ |
||
388 | protected void abort(Goal goal) { |
||
389 | |||
390 | // protect access to the queue |
||
391 | synchronized (this.queue) { |
||
392 | |||
393 | // remove goal form the current queue |
||
394 | this.queue.get(goal.getStatus()).remove(goal); |
||
395 | // set goal status |
||
396 | goal.setStatus(GoalStatus.ABORTED); |
||
397 | // add goal to the queue |
||
398 | this.queue.get(goal.getStatus()).add(goal); |
||
399 | // send signal |
||
400 | this.queue.notifyAll(); |
||
401 | } |
||
402 | } |
||
403 | |||
404 | /** |
||
405 | * |
||
406 | * @throws InterruptedException |
||
407 | * @throws PlatformException |
||
408 | */ |
||
409 | public void start() |
||
410 | throws InterruptedException, PlatformException { |
||
411 | |||
412 | synchronized (this.lock) { |
||
413 | while (!this.status.equals(ActingAgentStatus.OFFLINE)) { |
||
414 | // wait |
||
415 | this.lock.wait(); |
||
416 | } |
||
417 | |||
418 | // change status |
||
419 | this.status = ActingAgentStatus.STARTING; |
||
420 | // send signal |
||
421 | this.lock.notifyAll(); |
||
422 | } |
||
423 | |||
424 | // start PROXY if necessary |
||
425 | if (this.proxy instanceof RunnablePlatformProxy) { |
||
426 | // start runnable PROXY |
||
427 | ((RunnablePlatformProxy) this.proxy).start(); |
||
428 | } |
||
429 | |||
430 | |||
431 | // start all internal processes |
||
432 | for (Thread p : this.processes) { |
||
433 | p.start(); |
||
434 | } |
||
435 | |||
436 | synchronized (this.lock) { |
||
437 | // change status |
||
438 | this.status = ActingAgentStatus.RUNNING; |
||
439 | // notify all |
||
440 | this.lock.notifyAll(); |
||
441 | } |
||
442 | } |
||
443 | |||
444 | /** |
||
445 | * |
||
446 | * @throws InterruptedException |
||
447 | */ |
||
448 | public void stop() |
||
449 | throws InterruptedException, PlatformException |
||
450 | { |
||
451 | synchronized (this.lock) { |
||
452 | while (!this.status.equals(ActingAgentStatus.READY) && |
||
453 | !this.status.equals(ActingAgentStatus.RUNNING)) { |
||
454 | // wait |
||
455 | this.lock.wait(); |
||
456 | } |
||
457 | |||
458 | // change status |
||
459 | this.status = ActingAgentStatus.STOPPING; |
||
460 | // send signal |
||
461 | this.lock.notifyAll(); |
||
462 | } |
||
463 | |||
464 | |||
465 | // interrupt internal processes and wait termination |
||
466 | for (Thread p : this.processes) { |
||
467 | p.interrupt(); |
||
468 | p.join(); |
||
469 | } |
||
470 | |||
471 | // stop platform PROXY |
||
472 | if (this.proxy instanceof RunnablePlatformProxy) { |
||
473 | // stop platform PROXY |
||
474 | ((RunnablePlatformProxy) this.proxy).stop(); |
||
475 | } |
||
476 | |||
477 | synchronized (this.lock) { |
||
478 | // change status |
||
479 | this.status = ActingAgentStatus.OFFLINE; |
||
480 | // notify all |
||
481 | this.lock.notifyAll(); |
||
482 | } |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * |
||
487 | * @throws InterruptedException |
||
488 | * @throws SynchronizationCycleException |
||
489 | * @throws PlatformException |
||
490 | */ |
||
491 | public void initialize() |
||
492 | throws InterruptedException, SynchronizationCycleException, PlatformException { |
||
493 | |||
494 | synchronized (this.lock) { |
||
495 | while(!this.status.equals(ActingAgentStatus.RUNNING)) { |
||
496 | // wait a signal |
||
497 | this.lock.wait(); |
||
498 | } |
||
499 | |||
500 | // change status |
||
501 | this.status = ActingAgentStatus.INITIALIZING; |
||
502 | // send signal |
||
503 | this.lock.notifyAll(); |
||
504 | } |
||
505 | |||
506 | // set plan database on the given planning domain |
||
507 | this.pdb = PlanDataBaseBuilder.createAndSet(this.ddl); |
||
508 | |||
509 | synchronized (this.lock) { |
||
510 | // change status |
||
511 | this.status = ActingAgentStatus.READY; |
||
512 | // send signal |
||
513 | this.lock.notifyAll(); |
||
514 | } |
||
515 | } |
||
516 | |||
517 | /** |
||
518 | * |
||
519 | * @throws InterruptedException |
||
520 | */ |
||
521 | public void clear() |
||
522 | throws InterruptedException { |
||
523 | |||
524 | synchronized (this.lock) { |
||
525 | while (!this.status.equals(ActingAgentStatus.FAILURE) && |
||
526 | !this.status.equals(ActingAgentStatus.READY)) { |
||
527 | // wait |
||
528 | this.lock.wait(); |
||
529 | } |
||
530 | |||
531 | // change status |
||
532 | this.status = ActingAgentStatus.CLEARNING; |
||
533 | // send signal |
||
534 | this.lock.notifyAll(); |
||
535 | } |
||
536 | |||
537 | // clear queue |
||
538 | this.queue.clear(); |
||
539 | // clear domain file specification |
||
540 | this.ddl = null; |
||
541 | // clear plan database |
||
542 | this.pdb = null; |
||
543 | // clear PROXY |
||
544 | this.proxy = null; |
||
545 | |||
546 | synchronized (this.lock) { |
||
547 | // change status |
||
548 | this.status = ActingAgentStatus.RUNNING; |
||
549 | // send signal |
||
550 | this.lock.notifyAll(); |
||
551 | } |
||
552 | } |
||
553 | |||
554 | /** |
||
555 | * |
||
556 | * @return |
||
557 | * @throws InterruptedException |
||
558 | * @throws NoSolutionFoundException |
||
559 | */ |
||
560 | protected boolean plan(Goal goal) |
||
561 | throws InterruptedException { |
||
562 | |||
563 | // wait when planning can be actually performed if necessary |
||
564 | synchronized (this.lock) { |
||
565 | while (!this.status.equals(ActingAgentStatus.READY)) { |
||
566 | // wait |
||
567 | this.lock.wait(); |
||
568 | } |
||
569 | |||
570 | // change status |
||
571 | this.status = ActingAgentStatus.DELIBERATING; |
||
572 | // send signal |
||
573 | this.lock.notifyAll(); |
||
574 | } |
||
575 | |||
576 | // planning process result |
||
577 | boolean success = true; |
||
578 | |||
579 | // list of goal decisions |
||
580 | List<Decision> goals = new ArrayList<>(); |
||
581 | // list of fact decisions |
||
582 | List<Decision> facts = new ArrayList<>(); |
||
583 | try { |
||
584 | |||
585 | // get task description |
||
586 | AgentTaskDescription task = goal.getTaskDescription(); |
||
587 | // set known information concerning components |
||
588 | View Code Duplication | for (TokenDescription f : task.getFacts()) { |
|
589 | |||
590 | // get domain component |
||
591 | DomainComponent component = this.pdb.getComponentByName(f.getComponent()); |
||
592 | // get goal referred value |
||
593 | ComponentValue value = component.getValueByName(f.getValue()); |
||
594 | // check start time bound |
||
595 | long[] start = f.getStart(); |
||
596 | if (start == null) { |
||
597 | start = new long[] { |
||
598 | this.pdb.getOrigin(), |
||
599 | this.pdb.getHorizon() |
||
600 | }; |
||
601 | } |
||
602 | |||
603 | // check end time bound |
||
604 | long[] end = f.getEnd(); |
||
605 | if (end == null) { |
||
606 | end = new long[] { |
||
607 | this.pdb.getOrigin(), |
||
608 | this.pdb.getHorizon() |
||
609 | }; |
||
610 | } |
||
611 | |||
612 | // check duration bound |
||
613 | long[] duration = f.getDuration(); |
||
614 | if (duration == null) { |
||
615 | duration = new long[] { |
||
616 | value.getDurationLowerBound(), |
||
617 | value.getDurationUpperBound() |
||
618 | }; |
||
619 | } |
||
620 | |||
621 | // check labels |
||
622 | String[] labels = f.getLabels(); |
||
623 | if (labels == null) { |
||
624 | labels = new String[] {}; |
||
625 | } |
||
626 | |||
627 | // create fact decision |
||
628 | Decision decision = component.create( |
||
629 | value, |
||
630 | labels, |
||
631 | start, |
||
632 | end, |
||
633 | duration |
||
634 | ); |
||
635 | |||
636 | // also activate fact decision |
||
637 | component.activate(decision); |
||
638 | // add decision to fact list |
||
639 | facts.add(decision); |
||
640 | } |
||
641 | |||
642 | // set planning goals |
||
643 | View Code Duplication | for (TokenDescription g : task.getGoals()) { |
|
644 | |||
645 | // get domain component |
||
646 | DomainComponent component = this.pdb.getComponentByName(g.getComponent()); |
||
647 | // get goal referred value |
||
648 | ComponentValue value = component.getValueByName(g.getValue()); |
||
649 | // check start time bound |
||
650 | long[] start = g.getStart(); |
||
651 | if (start == null) { |
||
652 | start = new long[] { |
||
653 | this.pdb.getOrigin(), |
||
654 | this.pdb.getHorizon() |
||
655 | }; |
||
656 | } |
||
657 | |||
658 | // check end time bound |
||
659 | long[] end = g.getEnd(); |
||
660 | if (end == null) { |
||
661 | end = new long[] { |
||
662 | this.pdb.getOrigin(), |
||
663 | this.pdb.getHorizon() |
||
664 | }; |
||
665 | } |
||
666 | |||
667 | // check duration bound |
||
668 | long[] duration = g.getDuration(); |
||
669 | if (duration == null) { |
||
670 | duration = new long[] { |
||
671 | value.getDurationLowerBound(), |
||
672 | value.getDurationUpperBound() |
||
673 | }; |
||
674 | } |
||
675 | |||
676 | // check labels |
||
677 | String[] labels = g.getLabels(); |
||
678 | if (labels == null) { |
||
679 | labels = new String[] {}; |
||
680 | } |
||
681 | |||
682 | // create goal decision |
||
683 | Decision decision = component.create( |
||
684 | value, |
||
685 | labels, |
||
686 | start, |
||
687 | end, |
||
688 | duration |
||
689 | ); |
||
690 | |||
691 | // set as mandatory expansion decision |
||
692 | decision.setMandatoryExpansion(); |
||
693 | // add decision to goal list |
||
694 | goals.add(decision); |
||
695 | } |
||
696 | |||
697 | |||
698 | // start planning time |
||
699 | long now = System.currentTimeMillis(); |
||
700 | try { |
||
701 | |||
702 | // deliberate on the current status of the plan database |
||
703 | SolutionPlan plan = this.deliberative.doHandle(this.pdb); |
||
704 | // set generated plan |
||
705 | goal.setPlan(plan); |
||
706 | |||
707 | } catch (NoSolutionFoundException ex) { |
||
708 | |||
709 | // failure - no plan can be found |
||
710 | success = false; |
||
711 | // remove and deactivate facts |
||
712 | for (Decision f : facts) { |
||
713 | f.getComponent().deactivate(f); |
||
714 | f.getComponent().free(f); |
||
715 | } |
||
716 | |||
717 | // remove and deactivate goals |
||
718 | for (Decision g : goals) { |
||
719 | g.getComponent().deactivate(g); |
||
720 | g.getComponent().free(g); |
||
721 | } |
||
722 | |||
723 | } finally { |
||
724 | |||
725 | // compute actual planning time |
||
726 | long time = System.currentTimeMillis() - now; |
||
727 | // add planning time attempt to the goal |
||
728 | goal.addPlanningAttempt(time); |
||
729 | } |
||
730 | |||
731 | |||
732 | } catch (DecisionPropagationException ex) { |
||
733 | // problem setup error |
||
734 | success = false; |
||
735 | // remove and deactivate facts |
||
736 | for (Decision f : facts) { |
||
737 | f.getComponent().deactivate(f); |
||
738 | f.getComponent().free(f); |
||
739 | } |
||
740 | |||
741 | // remove and deactivate goals |
||
742 | for (Decision g : goals) { |
||
743 | g.getComponent().deactivate(g); |
||
744 | g.getComponent().free(g); |
||
745 | } |
||
746 | |||
747 | // print an error message |
||
748 | System.err.println("Error while propagating intial facts from task description:\n" |
||
749 | + "\t- message: " + ex.getMessage() + "\n"); |
||
750 | } |
||
751 | |||
752 | |||
753 | // update agent status |
||
754 | synchronized (this.lock) { |
||
755 | |||
756 | // update status according to the result of the planning process |
||
757 | if (success) { |
||
758 | this.status = ActingAgentStatus.PREPARING_EXECUTION; |
||
759 | |||
760 | } else { |
||
761 | |||
762 | // failure |
||
763 | this.status = ActingAgentStatus.FAILURE; |
||
764 | } |
||
765 | |||
766 | // send signal |
||
767 | this.lock.notifyAll(); |
||
768 | } |
||
769 | |||
770 | // return planning process result |
||
771 | return success; |
||
772 | } |
||
773 | |||
774 | /** |
||
775 | * This method returns an execution code denoting the outcome of the execution. |
||
776 | * |
||
777 | * Possible values are the following: |
||
778 | * 1 - execution successfully completed |
||
779 | * 2 - some execution failure has been detected and re-planning is necessary to fix the plan and restore the executive |
||
780 | * 3 - some major error occurred during the execution and no re-planning can be done |
||
781 | * |
||
782 | * @param goal |
||
783 | * @return execution code within {1, 2, 3} |
||
784 | * @throws InterruptedException |
||
785 | */ |
||
786 | protected int execute(Goal goal) |
||
787 | throws InterruptedException { |
||
788 | |||
789 | synchronized (this.lock) { |
||
790 | while (!this.status.equals(ActingAgentStatus.PREPARING_EXECUTION)) { |
||
791 | // wait |
||
792 | this.lock.wait(); |
||
793 | } |
||
794 | |||
795 | // update status |
||
796 | this.status = ActingAgentStatus.EXECUTING; |
||
797 | // send signal |
||
798 | this.lock.notifyAll(); |
||
799 | } |
||
800 | |||
801 | // execution result |
||
802 | boolean complete = true; |
||
803 | // re-planning flag |
||
804 | boolean replanning = false; |
||
805 | // start execution time |
||
806 | long now = System.currentTimeMillis(); |
||
807 | try { |
||
808 | |||
809 | // execute the plan |
||
810 | this.executive.doHandle(goal); |
||
811 | |||
812 | } catch (ExecutionPreparationException ex) { |
||
813 | |||
814 | // execution failure |
||
815 | complete = false; |
||
816 | // no re-planning since the execution has not even started |
||
817 | replanning = false; |
||
818 | |||
819 | // print message |
||
820 | System.err.println(ex.getMessage()); |
||
821 | |||
822 | } catch (Exception ex) { |
||
823 | |||
824 | // execution failure |
||
825 | complete = false; |
||
826 | // re-planning is necessary |
||
827 | replanning = true; |
||
828 | |||
829 | // print message |
||
830 | System.err.println(ex.getMessage()); |
||
831 | |||
832 | } finally { |
||
833 | |||
834 | // compute actual execution time |
||
835 | long time = System.currentTimeMillis() - now; |
||
836 | // add execution attempt time |
||
837 | goal.addExecutionAttempt(time); |
||
838 | } |
||
839 | |||
840 | // update agent status |
||
841 | synchronized (this.lock) { |
||
842 | |||
843 | // update status according to the execution results |
||
844 | if (complete) { |
||
845 | |||
846 | // set ready status |
||
847 | this.status = ActingAgentStatus.READY; |
||
848 | |||
849 | } else { |
||
850 | |||
851 | // suspend status for contingency handling and re-planning |
||
852 | this.status = ActingAgentStatus.SUSPENDED; |
||
853 | } |
||
854 | |||
855 | // send signal |
||
856 | this.lock.notifyAll(); |
||
857 | } |
||
858 | |||
859 | // return execution code |
||
860 | return complete ? 1 : !replanning ? 3 : 2; |
||
861 | } |
||
862 | |||
863 | /** |
||
864 | * |
||
865 | * @param goal |
||
866 | * @return |
||
867 | * @throws InterruptedException |
||
868 | */ |
||
869 | protected boolean repair(Goal goal) |
||
870 | throws InterruptedException { |
||
871 | |||
872 | synchronized (this.lock) { |
||
873 | while (!this.status.equals(ActingAgentStatus.SUSPENDED)) { |
||
874 | // wait |
||
875 | this.lock.wait(); |
||
876 | } |
||
877 | |||
878 | // update status |
||
879 | this.status = ActingAgentStatus.DELIBERATING; |
||
880 | // send signal |
||
881 | this.lock.notifyAll(); |
||
882 | } |
||
883 | |||
884 | // repairing result |
||
885 | boolean success = true; |
||
886 | // start contingency handling time |
||
887 | long now = System.currentTimeMillis(); |
||
888 | try { |
||
889 | |||
890 | // list of kept decisions |
||
891 | List<Decision> kept = new ArrayList<>(); |
||
892 | // clear domain components |
||
893 | for (DomainComponent comp : this.pdb.getComponents()) { |
||
894 | |||
895 | // list of pending decisions |
||
896 | List<Decision> pendings = comp.getPendingDecisions(); |
||
897 | for (Decision pending : pendings) { |
||
898 | |||
899 | // completely remove decision and related relations |
||
900 | comp.deactivate(pending); |
||
901 | comp.free(pending); |
||
902 | } |
||
903 | |||
904 | // get execution trace |
||
905 | List<ExecutionNode> trace = goal.getExecutionTraceByComponentName(comp.getName()); |
||
906 | // remove active decisions that have not been executed |
||
907 | List<Decision> actives = comp.getActiveDecisions(); |
||
908 | for (Decision active : actives) { |
||
909 | |||
910 | // check if the token has been executed |
||
911 | boolean executed = false; |
||
912 | for (ExecutionNode node : trace) { |
||
913 | // check if the temporal interval has been executed |
||
914 | if (node.getInterval().equals(active.getToken().getInterval())){ |
||
915 | executed = true; |
||
916 | break; |
||
917 | } |
||
918 | } |
||
919 | |||
920 | // check flag |
||
921 | if (executed) { |
||
922 | |||
923 | // keep the decision as active |
||
924 | kept.add(active); |
||
925 | |||
926 | } else { |
||
927 | |||
928 | // clear and remove decision and related relations |
||
929 | comp.deactivate(active); |
||
930 | comp.free(active); |
||
931 | } |
||
932 | } |
||
933 | } |
||
934 | |||
935 | |||
936 | // check execution failure cause |
||
937 | ExecutionFailureCause cause = goal.getFailureCause(); |
||
938 | // check type |
||
939 | switch (cause.getType()) { |
||
940 | |||
941 | case NODE_DURATION_OVERFLOW : { |
||
942 | |||
943 | // keep the decision as active and consider it as executed |
||
944 | ExecutionNode node = cause.getInterruptionNode(); |
||
945 | // find the related decision |
||
946 | for (DomainComponent comp : this.pdb.getComponents()) { |
||
947 | // get active decisions |
||
948 | List<Decision> actives = comp.getActiveDecisions(); |
||
949 | for (Decision active : actives) { |
||
950 | // check temporal intervals |
||
951 | if (node.getInterval().equals(active.getToken().getInterval())) { |
||
952 | // keep the decision as active |
||
953 | System.out.println("\nKEEP DECISION " + active + "\n"); |
||
954 | kept.add(active); |
||
955 | } |
||
956 | } |
||
957 | } |
||
958 | } |
||
959 | break; |
||
960 | |||
961 | case NODE_EXECUTION_ERROR : |
||
962 | case NODE_START_OVERFLOW : { |
||
963 | |||
964 | // remove decisions they are going to be re-planned |
||
965 | ExecutionNode node = cause.getInterruptionNode(); |
||
966 | // find the related decision |
||
967 | for (DomainComponent comp : this.pdb.getComponents()) { |
||
968 | // get active decisions |
||
969 | List<Decision> actives = comp.getActiveDecisions(); |
||
970 | for (Decision active : actives) { |
||
971 | |||
972 | // check temporal intervals |
||
973 | if (node.getInterval().equals(active.getToken().getInterval())) { |
||
974 | // keep the decision as active |
||
975 | comp.deactivate(active); |
||
976 | comp.free(active); |
||
977 | } |
||
978 | } |
||
979 | } |
||
980 | } |
||
981 | break; |
||
982 | |||
983 | default: |
||
984 | |||
985 | throw new RuntimeException("Unknown Execution Failure Cause : " + cause.getType()); |
||
986 | } |
||
987 | |||
988 | |||
989 | |||
990 | // get task description |
||
991 | AgentTaskDescription task = goal.getTaskDescription(); |
||
992 | // set planning goals |
||
993 | for (TokenDescription g : task.getGoals()) { |
||
994 | |||
995 | // get domain component |
||
996 | DomainComponent component = this.pdb.getComponentByName(g.getComponent()); |
||
997 | // get goal referred value |
||
998 | ComponentValue value = component.getValueByName(g.getValue()); |
||
999 | // check start time bound |
||
1000 | long[] start = g.getStart(); |
||
1001 | if (start == null) { |
||
1002 | start = new long[] { |
||
1003 | this.pdb.getOrigin(), |
||
1004 | this.pdb.getHorizon() |
||
1005 | }; |
||
1006 | } |
||
1007 | |||
1008 | // check end time bound |
||
1009 | long[] end = g.getEnd(); |
||
1010 | if (end == null) { |
||
1011 | end = new long[] { |
||
1012 | |||
1013 | this.pdb.getOrigin(), |
||
1014 | this.pdb.getHorizon() |
||
1015 | }; |
||
1016 | } |
||
1017 | |||
1018 | // check duration bound |
||
1019 | long[] duration = g.getDuration(); |
||
1020 | if (duration == null) { |
||
1021 | duration = new long[] { |
||
1022 | value.getDurationLowerBound(), |
||
1023 | value.getDurationUpperBound() |
||
1024 | }; |
||
1025 | } |
||
1026 | |||
1027 | // check labels |
||
1028 | String[] labels = g.getLabels(); |
||
1029 | if (labels == null) { |
||
1030 | labels = new String[] {}; |
||
1031 | } |
||
1032 | |||
1033 | /* |
||
1034 | * TODO : check parameter relations |
||
1035 | */ |
||
1036 | |||
1037 | // create goal decision |
||
1038 | Decision decision = component.create( |
||
1039 | value, |
||
1040 | labels, |
||
1041 | start, |
||
1042 | end, |
||
1043 | duration, |
||
1044 | ExecutionNodeStatus.IN_EXECUTION); |
||
1045 | |||
1046 | // add decision to goal list |
||
1047 | System.out.println("REPAIR GOAL : [" + decision.getId() +"]:" + decision.getComponent().getName() + "." + decision.getValue().getLabel() + " " |
||
1048 | + "AT [" + decision.getStart()[0] + ", " + decision.getStart()[1] + "] " |
||
1049 | + "[" + decision.getEnd()[0] + ", " + decision.getEnd()[1] + "] " |
||
1050 | + "[" + decision.getDuration()[0] + ", " + decision.getDuration()[1] + "]"); |
||
1051 | } |
||
1052 | |||
1053 | |||
1054 | // deliberate on the current status of the plan database |
||
1055 | SolutionPlan plan = this.contingencyHandler.doHandle( |
||
1056 | this.pClass, |
||
1057 | this.pdb); |
||
1058 | |||
1059 | |||
1060 | // set repaired plan |
||
1061 | goal.setPlan(plan); |
||
1062 | // set goal as repaired |
||
1063 | goal.setRepaired(true); |
||
1064 | // set the tick the execution will start |
||
1065 | goal.setExecutionTick(goal.getFailureCause().getInterruptionTick()); |
||
1066 | // clear execution trace |
||
1067 | goal.clearExecutionTrace(); |
||
1068 | |||
1069 | } catch (Exception ex) { |
||
1070 | |||
1071 | // error while repairing |
||
1072 | success = false; |
||
1073 | // error message |
||
1074 | System.err.println("Error while trying to repair the plan\n" |
||
1075 | + "\t- message: " + ex.getMessage() + "\n"); |
||
1076 | |||
1077 | // completely clear all the plan database |
||
1078 | for (DomainComponent comp : this.pdb.getComponents()) { |
||
1079 | // remove all pending decisions |
||
1080 | List<Decision> pendings = comp.getPendingDecisions(); |
||
1081 | for (Decision pending : pendings) { |
||
1082 | comp.deactivate(pending); |
||
1083 | comp.free(pending); |
||
1084 | |||
1085 | } |
||
1086 | |||
1087 | // remove all active decisions |
||
1088 | List<Decision> actives = comp.getActiveDecisions(); |
||
1089 | for (Decision active : actives) { |
||
1090 | comp.deactivate(active); |
||
1091 | comp.free(active); |
||
1092 | } |
||
1093 | |||
1094 | // finally completely clear component |
||
1095 | comp.clear(); |
||
1096 | } |
||
1097 | |||
1098 | |||
1099 | } finally { |
||
1100 | |||
1101 | // compute actual planning time |
||
1102 | long time = System.currentTimeMillis() - now; |
||
1103 | // add planning time attempt to the goal |
||
1104 | goal.addContingencyHandlingAttempt(time); |
||
1105 | goal.addPlanningAttempt(time); |
||
1106 | } |
||
1107 | |||
1108 | |||
1109 | synchronized (this.lock) { |
||
1110 | |||
1111 | // update status according to the execution results |
||
1112 | if (success) { |
||
1113 | |||
1114 | this.status = ActingAgentStatus.READY; |
||
1115 | |||
1116 | } else { |
||
1117 | |||
1118 | this.status = ActingAgentStatus.FAILURE; |
||
1119 | } |
||
1120 | |||
1121 | // send signal |
||
1122 | this.lock.notifyAll(); |
||
1123 | } |
||
1124 | |||
1125 | // return execution result |
||
1126 | return success; |
||
1127 | } |
||
1128 | |||
1129 | |||
1130 | |||
1131 | |||
1132 | |||
1133 | /** |
||
1134 | * |
||
1135 | * @param status |
||
1136 | * @throws InterruptedException |
||
1137 | */ |
||
1138 | protected Goal waitGoal(GoalStatus status) |
||
1139 | throws InterruptedException |
||
1140 | { |
||
1141 | // goal |
||
1142 | Goal goal = null; |
||
1143 | // wait a selected goal |
||
1144 | synchronized (this.queue) { |
||
1145 | // check selected buffer |
||
1146 | while (this.queue.get(status).isEmpty()) { |
||
1147 | // wait a selected goal |
||
1148 | this.queue.wait(); |
||
1149 | } |
||
1150 | |||
1151 | // remove the first selected goal from the queue |
||
1152 | goal = this.queue.get(status).remove(0); |
||
1153 | // send signal |
||
1154 | this.queue.notifyAll(); |
||
1155 | } |
||
1156 | |||
1157 | // get extracted goal |
||
1158 | return goal; |
||
1159 | } |
||
1161 |
The Java documentation explain EnumMap.