it.cnr.istc.pst.platinum.control.acting.GoalOrientedActingAgent   F
last analyzed

Complexity

Total Complexity 98

Size/Duplication

Total Lines 1117
Duplicated Lines 9.31 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
eloc 452
dl 104
loc 1117
rs 2
c 4
b 1
f 0
wmc 98

22 Methods

Rating   Name   Duplication   Size   Complexity  
A stop() 0 34 5
$Runnable$.run() 0 16 ?
A getStatus() 0 2 1
A getResults() 0 28 3
A buffer(AgentTaskDescription) 0 13 1
A waitGoal(GoalStatus) 0 21 2
A select(Goal) 0 13 1
A finish(Goal) 0 13 1
A task(AgentTaskDescription) 0 4 1
D GoalOrientedActingAgent(String) 0 90 10
A suspend(Goal) 0 13 1
A clear() 0 30 3
A feedback(PlatformFeedback) 0 2 1
A commit(Goal) 0 13 1
A initialize() 0 23 2
B setupProcesses() 0 47 5
A abort(Goal) 0 13 1
F plan(Goal) 104 212 19
A start() 0 32 4
A observation(PlatformObservation) 0 2 1
B execute(Goal) 0 75 7
F repair(Goal) 0 258 28

How to fix   Duplicated Code    Complexity   

Duplicated Code

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:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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;
2
3
import java.util.ArrayList;
4
import java.util.HashMap;
5
import java.util.LinkedList;
6
import java.util.List;
7
import java.util.Map;
8
9
import it.cnr.istc.pst.platinum.ai.deliberative.Planner;
10
import it.cnr.istc.pst.platinum.ai.executive.Executive;
11
import it.cnr.istc.pst.platinum.ai.executive.lang.ex.ExecutionPreparationException;
12
import it.cnr.istc.pst.platinum.ai.executive.lang.failure.ExecutionFailureCause;
13
import it.cnr.istc.pst.platinum.ai.executive.pdb.ExecutionNode;
14
import it.cnr.istc.pst.platinum.ai.executive.pdb.ExecutionNodeStatus;
15
import it.cnr.istc.pst.platinum.ai.framework.domain.PlanDataBaseBuilder;
16
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ComponentValue;
17
import it.cnr.istc.pst.platinum.ai.framework.domain.component.Decision;
18
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponent;
19
import it.cnr.istc.pst.platinum.ai.framework.domain.component.PlanDataBase;
20
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.DecisionPropagationException;
21
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.ex.NoSolutionFoundException;
22
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.ex.SynchronizationCycleException;
23
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.plan.SolutionPlan;
24
import it.cnr.istc.pst.platinum.ai.framework.utils.properties.FilePropertyReader;
25
import it.cnr.istc.pst.platinum.control.lang.AgentTaskDescription;
26
import it.cnr.istc.pst.platinum.control.lang.Goal;
27
import it.cnr.istc.pst.platinum.control.lang.GoalStatus;
28
import it.cnr.istc.pst.platinum.control.lang.PlatformFeedback;
29
import it.cnr.istc.pst.platinum.control.lang.PlatformObservation;
30
import it.cnr.istc.pst.platinum.control.lang.TokenDescription;
31
import it.cnr.istc.pst.platinum.control.lang.ex.PlatformException;
32
import it.cnr.istc.pst.platinum.control.platform.PlatformObserver;
33
import it.cnr.istc.pst.platinum.control.platform.PlatformProxy;
34
import it.cnr.istc.pst.platinum.control.platform.PlatformProxyBuilder;
35
import it.cnr.istc.pst.platinum.control.platform.RunnablePlatformProxy;
36
37
/**
38
 * 
39
 * @author alessandro
40
 *
41
 */
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<>();
0 ignored issues
show
Performance introduced by
When using a map whose keys are EnumValues, consider using an EnumMap instead, which is more performant in this case.

The Java documentation explain EnumMap.

Loading history...
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\"!");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
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 + "\"!");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
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());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
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) {
0 ignored issues
show
introduced by
Either re-interrupt this method or rethrow the "InterruptedException".
Loading history...
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()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
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
	}
1160
}
1161