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