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

Complexity

Total Complexity 98

Size/Duplication

Total Lines 1115
Duplicated Lines 9.33 %

Importance

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

22 Methods

Rating   Name   Duplication   Size   Complexity  
D GoalOrientedActingAgent(String) 0 90 10
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
A suspend(Goal) 0 13 1
B execute(Goal) 0 75 7
A clear() 0 30 3
F repair(Goal) 0 258 28
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

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