Passed
Push — master ( 9e7d47...503479 )
by Alessandro
08:14
created

clearExecutedNodes()   A

Complexity

Conditions 4

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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