Passed
Push — master ( c71db0...37262d )
by Alessandro
05:46 queued 14s
created

isActive(Decision)   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
c 0
b 0
f 0
cc 1
rs 10
1
package it.cnr.istc.pst.platinum.ai.framework.domain.component;
2
3
4
import java.lang.reflect.Constructor;
5
import java.util.ArrayList;
6
import java.util.Collections;
7
import java.util.HashMap;
8
import java.util.HashSet;
9
import java.util.List;
10
import java.util.Map;
11
import java.util.Set;
12
import java.util.concurrent.atomic.AtomicInteger;
13
14
import it.cnr.istc.pst.platinum.ai.executive.pdb.ExecutionNodeStatus;
15
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.DecisionPropagationException;
16
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.FlawSolutionApplicationException;
17
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.RelationPropagationException;
18
import it.cnr.istc.pst.platinum.ai.framework.domain.component.pdb.SynchronizationRule;
19
import it.cnr.istc.pst.platinum.ai.framework.microkernel.FrameworkObject;
20
import it.cnr.istc.pst.platinum.ai.framework.microkernel.annotation.inject.framework.ParameterFacadePlaceholder;
21
import it.cnr.istc.pst.platinum.ai.framework.microkernel.annotation.inject.framework.ResolverListPlaceholder;
22
import it.cnr.istc.pst.platinum.ai.framework.microkernel.annotation.inject.framework.TemporalFacadePlaceholder;
23
import it.cnr.istc.pst.platinum.ai.framework.microkernel.annotation.lifecycle.PostConstruct;
24
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.ex.ConstraintPropagationException;
25
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.Flaw;
26
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.FlawSolution;
27
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.FlawType;
28
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.Relation;
29
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.RelationType;
30
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.parameter.ParameterRelation;
31
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.temporal.TemporalRelation;
32
import it.cnr.istc.pst.platinum.ai.framework.microkernel.query.TemporalQueryType;
33
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.Resolver;
34
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.ex.UnsolvableFlawException;
35
import it.cnr.istc.pst.platinum.ai.framework.parameter.ParameterFacade;
36
import it.cnr.istc.pst.platinum.ai.framework.parameter.ex.ParameterCreationException;
37
import it.cnr.istc.pst.platinum.ai.framework.parameter.ex.ParameterNotFoundException;
38
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.Parameter;
39
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.ParameterConstraint;
40
import it.cnr.istc.pst.platinum.ai.framework.time.TemporalFacade;
41
import it.cnr.istc.pst.platinum.ai.framework.time.TemporalInterval;
42
import it.cnr.istc.pst.platinum.ai.framework.time.ex.TemporalIntervalCreationException;
43
import it.cnr.istc.pst.platinum.ai.framework.time.lang.TemporalConstraint;
44
import it.cnr.istc.pst.platinum.ai.framework.time.lang.query.IntervalScheduleQuery;
45
import it.cnr.istc.pst.platinum.ai.framework.utils.view.component.ComponentView;
46
import it.cnr.istc.pst.platinum.ai.framework.utils.view.component.gantt.GanttComponentView;
47
48
/**
49
 * 
50
 * @author anacleto
51
 *
52
 */
53
public abstract class DomainComponent extends FrameworkObject
54
{
55
	@TemporalFacadePlaceholder
56
	protected TemporalFacade tdb;
57
	
58
	@ParameterFacadePlaceholder
59
	protected ParameterFacade pdb;
60
	
61
	@ResolverListPlaceholder
62
	protected List<Resolver<?>> resolvers;
63
	protected Map<FlawType, Resolver<?>> flawType2resolver;
64
	
65
	// component's name
66
	protected String name;
67
	protected DomainComponentType type;
68
	
69
	// current (local) plan
70
	protected Map<PlanElementStatus, Set<Decision>> decisions;
71
	protected Set<Relation> localRelations;
72
	
73
	// display data concerning this component
74
	private ComponentView view;
75
	
76
	// static information
77
	
78
	// rules from the planning domain
79
	protected static final Map<DomainComponent, Map<ComponentValue, List<SynchronizationRule>>> rules = new HashMap<>();
80
	// current (global) relations
81
	protected static final Set<Relation> globalRelations = new HashSet<>();
82
	// predicate ID counter
83
	protected static final AtomicInteger PREDICATE_COUNTER = new AtomicInteger(0);
84
	protected static final AtomicInteger DecisionIdCounter = new AtomicInteger(0);
85
	protected static final AtomicInteger RELATION_COUNTER = new AtomicInteger(0);
86
	
87
	/**
88
	 * 
89
	 * @param name
90
	 * @param type
91
	 */
92
	protected DomainComponent(String name, DomainComponentType type) {
93
		super();
94
		this.type = type;
95
		this.name = name;
96
		
97
		// set decisions of the (local) plan
98
		this.decisions = 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...
99
		for (PlanElementStatus status : PlanElementStatus.values()) {
100
			this.decisions.put(status, new HashSet<>());
101
		}
102
		
103
		// set relations of the (local) plan
104
		this.localRelations = new HashSet<>();
105
		// set up the list of resolvers
106
		this.resolvers = new ArrayList<>();
107
		this.flawType2resolver = 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...
108
	}
109
	
110
	/**
111
	 * 
112
	 */
113
	@PostConstruct
114
	protected synchronized void init() {
115
		
116
		
117
		// set component view
118
		this.view = new GanttComponentView(this);
119
		// setup resolver index
120
		for (Resolver<?> resv : this.resolvers) {
121
			for (FlawType ft : resv.getFlawTypes()) {
122
				this.flawType2resolver.put(ft, resv);
123
			}
124
		}
125
	}
126
	
127
	/**
128
	 * 
129
	 * @return
130
	 */
131
	public String getName() {
132
		return name;
133
	}
134
	
135
	/**
136
	 * 
137
	 * @return
138
	 */
139
	public DomainComponentType getType() {
140
		return type;
141
	}
142
	
143
	/**
144
	 * 
145
	 * @return
146
	 */
147
	public boolean isExternal() {
148
		return false;
149
	}
150
	
151
	/**
152
	 * 
153
	 * @return
154
	 */
155
	public long getOrigin() {
156
		return this.tdb.getOrigin();
157
	}
158
	
159
	/**
160
	 * 
161
	 * @return
162
	 */
163
	public long getHorizon() {
164
		return this.tdb.getHorizon();
165
	}
166
	
167
	/**
168
	 * Clear component data structure
169
	 */
170
	public synchronized void clear() 
171
	{
172
		// delete all active relations
173
		for (Relation relation : this.getActiveRelations()) {
174
			// deactivate relation
175
			this.deactivate(relation);
176
			// delete relation data
177
			this.delete(relation);
178
		}
179
		
180
		// delete all active decisions
181
		for (Decision decision : this.getActiveDecisions()) {
182
			// deactivate decision
183
			this.deactivate(decision);
184
			// free decision
185
			this.free(decision);
186
			// delete decision
187
			this.delete(decision);
188
		}
189
		
190
		// clear component data structures
191
		this.decisions.clear();
192
		this.localRelations.clear();
193
	}
194
	
195
	/**
196
	 * Compute the makespan of a component as minimal and maximal duration of its activities
197
	 *  
198
	 * @return
199
	 */
200
	public synchronized double[] getMakespan() 
201
	{
202
		// set makespan initial values
203
		double[] makespan = new double[] {
204
			0,
205
			0
206
		};
207
		
208
		// get active decisions
209
		List<Decision> list = this.getActiveDecisions();
210
		// check scheduled end-times 
211
		for (Decision a : list) {
212
			// increment minimal makespan
213
			makespan[0] = Math.max(makespan[0], a.getEnd()[0]);
214
			// increment maximal makespan
215
			makespan[1] = Math.max(makespan[1], a.getEnd()[1]);
216
		}
217
		
218
		// get computed makespan
219
		return makespan;
220
	}
221
	
222
	/**
223
	 * 
224
	 * @return
225
	 */
226
	public synchronized double[] getBehaviorDuration() {
227
		// set duration initial values
228
		double[] duration = new double[] {
229
			0,
230
			0
231
		};
232
		
233
		// get active decisions
234
		List<Decision> list = this.getActiveDecisions();
235
		// check scheduled end-times 
236
		for (Decision a : list) {
237
			// increment minimal duration
238
			duration[0] += a.getDuration()[0];
239
			// increment maximal duration
240
			duration[1] += a.getDuration()[1];
241
		}
242
		
243
		// get computed makespan
244
		return duration;
245
	}
246
	
247
	/**
248
	 * 
249
	 */
250
	public void display() {
251
		this.view.display();
252
	}
253
254
	/**
255
	 * 
256
	 * @return
257
	 */
258
	public final List<SynchronizationRule> getSynchronizationRules() {
259
		// get all rules
260
		List<SynchronizationRule> list = new ArrayList<>();
261
		synchronized (rules) {
262
			for (DomainComponent comp : rules.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...
263
				// check if a rule has been defined on the component
264
				if (rules.containsKey(comp)) {
265
					for (ComponentValue v : rules.get(comp).keySet()) {
266
						// add rules
267
						list.addAll(rules.get(comp).get(v));
268
					}
269
				}
270
			}
271
		}
272
		
273
		// get rules
274
		return list;
275
	}
276
	
277
	/**
278
	 * 
279
	 */
280
	public final  List<SynchronizationRule> getSynchronizationRules(ComponentValue value) 
281
	{
282
		// list of rules
283
		List<SynchronizationRule> list = new ArrayList<>();
284
		synchronized (rules) {
285
			// check domain specification
286
			if (rules.containsKey(value.getComponent()) && rules.get(value.getComponent()).containsKey(value)) {
287
				list.addAll(rules.get(value.getComponent()).get(value));
288
			}
289
		}
290
		
291
		// get rules
292
		return list;
293
	}
294
	
295
	/**
296
	 * 
297
	 */
298
	public final List<SynchronizationRule> getSynchronizationRules(DomainComponent component) 
299
	{
300
		// list of rules
301
		List<SynchronizationRule> list = new ArrayList<>();
302
		synchronized (rules) {
303
			// check domain specification
304
			if (rules.containsKey(component)) {
305
				for (ComponentValue value : rules.get(component).keySet()) {
306
					list.addAll(rules.get(component).get(value));
307
				}
308
			}
309
		}
310
		
311
		// get rules
312
		return list;
313
	}
314
	
315
	/**
316
	 * Get the set of active global relations
317
	 * 
318
	 * @return
319
	 */
320
	public static final Set<Relation> getGlobalActiveRelations() {
321
		// set of active global relations
322
		Set<Relation> set = new HashSet<>();
323
		synchronized (globalRelations) {
324
			for (Relation rel : globalRelations) {
325
				if (rel.isActive()) {
326
					set.add(rel);
327
				}
328
			}
329
		}
330
		// get the list of global active relations
331
		return set;
332
	}
333
	
334
	/**
335
	 * Get the set of global relations
336
	 * @return
337
	 */
338
	public static final Set<Relation> getGlobalRelations() {
339
		// set of active global relations
340
		Set<Relation> set = new HashSet<>();
341
		synchronized (globalRelations) {
342
			for (Relation rel : globalRelations) {
343
				set.add(rel);
344
			}
345
		}
346
		// get the list of global active relations
347
		return set;
348
	}
349
	
350
	/**
351
	 * Get the set of pending global relations
352
	 * @return
353
	 */
354
	public static final Set<Relation> getGlobalPendingRelations() {
355
		// set of active global relations
356
		Set<Relation> set = new HashSet<>();
357
		synchronized (globalRelations) {
358
			for (Relation rel : globalRelations) {
359
				if (rel.isPending()) {
360
					set.add(rel);
361
				}
362
			}
363
		}
364
		// get the list of global active relations
365
		return set;
366
	}
367
	
368
	/**
369
	 * 
370
	 * @return
371
	 */
372
	public synchronized List<Decision> getActiveDecisions() 
373
	{
374
		// list of active decisions with schedule information
375
		List<Decision> list = new ArrayList<>();
376
		// get schedule information
377
		for (Decision dec : this.decisions.get(PlanElementStatus.ACTIVE)) 
378
		{
379
			// create query
380
			IntervalScheduleQuery query = this.tdb.createTemporalQuery(TemporalQueryType.INTERVAL_SCHEDULE);
381
			// set related temporal interval
382
			query.setInterval(dec.getToken().getInterval());
383
			// process 
384
			this.tdb.process(query);
385
			// add the updated token to the list
386
			list.add(dec);
387
		}
388
389
		// sort decisions
390
		Collections.sort(list);
391
		// get sorted list of active decisions
392
		return list;
393
	}
394
	
395
	/**
396
	 * 
397
	 * @return
398
	 */
399
	public synchronized List<Decision> getPendingDecisions() {
400
		return new ArrayList<>(this.decisions.get(PlanElementStatus.PENDING));
401
	}
402
	
403
	/**
404
	 * Restore the selected decision as pending into the component
405
	 * 
406
	 * @param dec
407
	 */
408 View Code Duplication
	public synchronized void restore(Decision dec) 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
409
	{
410
		// check decision component
411
		if (!dec.getComponent().equals(this)) {
412
			throw new RuntimeException("Trying to restore a not local decision on component:\n- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
413
		}
414
		
415
		// if active something goes wrong
416
		if (this.isActive(dec)) {
417
			// unexpected behavior
418
			throw new RuntimeException("Trying to restore an active decision:\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
419
		}
420
		
421
		// check if pending
422
		if (this.isPending(dec)) {
423
			// warning information
424
			warning("Trying to restore an already pending decision:\n- decision: " + dec + "\n");
425
//			throw new RuntimeException("Trying to restore an already pending decision:\n- decision: " + dec + "\n");
426
		}
427
		
428
		// check if silent decision
429
		if (this.isSilent(dec)) {
430
			// remove from silent set
431
			this.decisions.get(PlanElementStatus.SILENT).remove(dec);
432
			// add to pending set
433
			this.decisions.get(PlanElementStatus.PENDING).add(dec);
434
		}
435
	}
436
	
437
	/**
438
	 * 
439
	 * @param rel
440
	 */
441
	public synchronized void restore(Relation rel) 
442
	{
443
		// get reference component
444
		DomainComponent refComp = rel.getReference().getComponent();
445
		DomainComponent targetComp = rel.getTarget().getComponent();
446
		// check components
447
		if (!refComp.equals(this) && !targetComp.equals(this)) {
448
			// unknown relation - global "external" relation
449
			throw new RuntimeException("Trying to restore a relation \"unknown\" to component:\n- component: " + this.name + "\n- relation: " + rel + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
450
		}
451
		
452
		// restore local relation
453
		if (rel.isLocal()) 
454
		{
455
			// check if still present in the data structure
456
			if (this.localRelations.contains(rel)) 
457
			{
458
				// check also if active - FIXME: check if this case occurs
0 ignored issues
show
Code Smell introduced by
Tasks associated with this FIXME comment should be completed and this comment removed.
Loading history...
459
				if (rel.getConstraint() != null) {
460
					// warning trying to restore an active relation
461
					warning("Trying to restore an active relation!");
462
					// deactivate relation
463
					this.deactivate(rel);
464
				}
465
				else {
466
					// warning trying to restore an existing relation
467
					warning("Traying to restore an already existing relation");
468
				}
469
			}
470
			else {
471
				// add "back" local relation
472
				this.localRelations.add(rel);
473
			}
474
		}
475
		else 
476
		{
477
			// restore global relation
478
			synchronized (globalRelations) {
479
				// check if still present in the data structure
480
				if (globalRelations.contains(rel)) 
481
				{
482
					// check also if active - FIXME: check if this case occurs
0 ignored issues
show
Code Smell introduced by
Tasks associated with this FIXME comment should be completed and this comment removed.
Loading history...
483
					if (rel.getConstraint() != null) {
484
						// warning trying to restore an active relation
485
						warning("Trying to restore an active relation!");
486
						// deactive relation
487
						this.deactivate(rel);
488
					}
489
					else {
490
						// warning trying to restore an existing relation
491
						warning("Traying to restore an already existing relation");
492
					}
493
				}
494
				else {
495
					// add "back" global relation
496
					globalRelations.add(rel);
497
				}
498
			}
499
		}
500
	}
501
	
502
	/**
503
	 * The method creates a pending decision of the plan with the given component's value
504
	 * 
505
	 * @param value
506
	 * @return
507
	 */
508
	public synchronized Decision create(ComponentValue value, String[] labels) 
509
	{
510
		// create decision
511
		return this.create(
512
				value,
513
				labels,
514
				new long[] {this.tdb.getOrigin(), this.tdb.getHorizon()}, 
515
				new long[] {this.tdb.getOrigin(), this.tdb.getHorizon()}, 
516
				value.getDurationBounds());
517
	}
518
	
519
	/**
520
	 * 
521
	 * @param value
522
	 * @param labels
523
	 * @param duration
524
	 * @return
525
	 */
526
	public synchronized Decision create(ComponentValue value, String[] labels, long[] duration) {
527
		// create decision
528
		return this.create(
529
				value,
530
				labels,
531
				new long[] {this.tdb.getOrigin(), this.tdb.getHorizon()}, 
532
				new long[] {this.tdb.getOrigin(), this.tdb.getHorizon()}, 
533
				duration);
534
	}
535
	
536
	/**
537
	 * 
538
	 * @param value
539
	 * @param labels
540
	 * @param end
541
	 * @param duration
542
	 * @return
543
	 */
544
	public synchronized Decision create(ComponentValue value, String[] labels, long[] end, long[] duration) {
545
		// create decision
546
		return this.create(
547
				value,
548
				labels,
549
				new long[] {this.tdb.getOrigin(), this.tdb.getHorizon()}, 
550
				end, 
551
				duration);
552
	}
553
	
554
	/**
555
	 * 
556
	 * @param value
557
	 * @param labels
558
	 * @param start
559
	 * @param end
560
	 * @param duration
561
	 * @return
562
	 */
563 View Code Duplication
	public synchronized Decision create(ComponentValue value, String[] labels, long[] start, long[] end, long[] duration) 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
564
	{
565
		// check if value is known to the component
566
		if (!value.getComponent().equals(this)) {
567
			throw new RuntimeException("Trying to add a decision with a value unknown to the component:\n- component: " + this.name + "\n- value: " + value + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
568
		}
569
		
570
		// set decision
571
		Decision dec = new Decision(DecisionIdCounter.getAndIncrement(), value, labels, start, end, duration);
572
		// add decision the the agenda
573
		this.decisions.get(PlanElementStatus.PENDING).add(dec);
574
		// get decision
575
		return dec;
576
	}
577
	
578
	/**
579
	 * 
580
	 * @param value
581
	 * @param labels
582
	 * @param start
583
	 * @param end
584
	 * @param duration
585
	 * @return
586
	 */
587 View Code Duplication
	public synchronized Decision create(ComponentValue value, String[] labels, long[] start, long[] end, long[] duration, ExecutionNodeStatus status) 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
588
	{
589
		// check if value is known to the component
590
		if (!value.getComponent().equals(this)) {
591
			throw new RuntimeException("Trying to add a decision with a value unknown to the component:\n- component: " + this.name + "\n- value: " + value + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
592
		}
593
		
594
		// set decision
595
		Decision dec = new Decision(DecisionIdCounter.getAndIncrement(), value, labels, start, end, duration, status);
596
		// add decision the the agenda
597
		this.decisions.get(PlanElementStatus.PENDING).add(dec);
598
		// get set decision
599
		return dec;
600
	}
601
	
602
	/**
603
	 * The method adds a pending decision to the current plan. The status of the decision 
604
	 * changes from PENDING to ACTIVE.
605
	 * 
606
	 * The method returns the set of local and global relations propagate during decision activation.
607
	 * 
608
	 * @param dec
609
	 * @return
610
	 * @throws DecisionPropagationException
611
	 * 
612
	 */
613
	public synchronized Set<Relation> activate(Decision dec) 
614
			throws DecisionPropagationException 
615
	{
616
		// check decision component
617
		if (!dec.getComponent().equals(this)) {
618
			throw new RuntimeException("Trying to add a not local decision to a component:\n- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
619
		}
620
		
621
		// list of relations to activate
622
		Set<Relation> rels = new HashSet<>();
623
		// check if already active
624
		if (this.isActive(dec)) {
625
			// warning information
626
			warning("Trying to activate an already active decision:\n- decision: " + dec + "\n");
627
		}
628
		else
629
		{
630
			// flag in case of roll-back
631
			boolean free = false;
632
			// check if decision is silent
633
			if (this.isSilent(dec)) {
634
				// restore decision 
635
				this.restore(dec);
636
				// set free flag
637
				free = true;
638
			}
639
			
640
			// check if decision is pending
641
			if (this.isPending(dec)) 
642
			{
643
				// token to create
644
				Token token = null;
645
				try 
646
				{
647
					// create a token
648
					token = this.createToken(
649
							dec.getId(),
650
							dec.getValue(),
651
							dec.getParameterLabels(),
652
							dec.getStart(), 
653
							dec.getEnd(), 
654
							dec.getNominalDuration(),
655
							dec.getStartExecutionState());
656
					
657
					// set token to decision 
658
					dec.setToken(token);
659
					// remove decision from agenda
660
					this.decisions.get(PlanElementStatus.PENDING).remove(dec);
661
					// add decision to the plan
662
					this.decisions.get(PlanElementStatus.ACTIVE).add(dec);
663
				
664
					// get local and global relations to activate
665
					for (Relation rel : this.getToActivateRelations(dec)) {
666
						// propagate relations
667
						this.activate(rel);
668
						// add relation to the list
669
						rels.add(rel);
670
					}
671
				}
672
				catch (RelationPropagationException ex) 
673
				{
674
					// deactivate relations
675
					for (Relation rel : rels) {
676
						this.deactivate(rel);
677
					}
678
					
679
					// deactivate decision ACTIVE -> PENDING
680
					this.deactivate(dec);
681
					
682
					// reset SILENT decision if necessary
683
					if (free) {
684
						// PENDING -> FREE
685
						this.free(dec);
686
					}
687
					
688
					// throw exception
689
					throw new DecisionPropagationException(ex.getMessage());
690
				}
691
				catch (TemporalIntervalCreationException | ParameterCreationException ex) {
692
					
693
					// reset SILENT decision if necessary
694
					if (free) {
695
						
696
						// PENDING -> FREE
697
						this.free(dec);
698
					}
699
					
700
					// throw exception
701
					throw new DecisionPropagationException(ex.getMessage());
702
				}
703
			}
704
		}
705
		
706
		// get list of "local" activated relations
707
		return rels;
708
	}
709
710
	/**
711
	 * 
712
	 * @param dec
713
	 */
714
	public synchronized Set<Relation> deactivate(Decision dec) 
715
	{
716
		// check decision component
717
		if (!dec.getComponent().equals(this)) {
718
			throw new RuntimeException("Trying to delete a not local decision from a component:\n- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
719
		}
720
		
721
		// check if already pending
722
		if (this.isSilent(dec)) {
723
			// warning information
724
			throw new RuntimeException("Trying to deactivate a silent decision:\n- decision: " + dec + "\n");	
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
725
		}
726
		
727
		// check if already pending
728
		if (this.isPending(dec)) {
729
			// warning information
730
			warning("Trying to deactivate an already pending decision:\n- decision: " + dec + "\n");
731
		}
732
		
733
		// set of deactivated relations
734
		Set<Relation> rDeactivated = new HashSet<>(); 
735
		// check if active
736
		if (this.isActive(dec)) 
737
		{
738
			// get active relations to retract
739
			for (Relation rel :  this.getActiveRelations(dec)) {
740
				// deactivate relations
741
				this.deactivate(rel);
742
				// add 
743
				rDeactivated.add(rel);
744
			}
745
			
746
			// delete related token
747
			Token token = dec.getToken();
748
			// delete parameters of token predicate
749
			for (Parameter<?> param : token.getPredicate().getParameters()) 
750
			{
751
				try 
752
				{
753
					// delete parameter variable
754
					this.pdb.deleteParameter(param);
755
				}
756
				catch (ParameterNotFoundException ex) {
757
					warning(ex.getMessage());
758
				}
759
			}
760
			
761
			// delete the temporal interval
762
			this.tdb.deleteTemporalInterval(token.getInterval());
763
			// remove decision from active
764
			this.decisions.get(PlanElementStatus.ACTIVE).remove(dec);
765
			// add back to pending
766
			this.decisions.get(PlanElementStatus.PENDING).add(dec);
767
			// clear decision
768
			dec.clear();
769
		}
770
		
771
		// get deactivated relations
772
		return rDeactivated;
773
	}
774
	
775
	/**
776
	 * 
777
	 * @param dec
778
	 */
779 View Code Duplication
	public synchronized void free(Decision dec) 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
780
	{
781
		// check decision component
782
		if (!dec.getComponent().equals(this)) {
783
			throw new RuntimeException("Trying to free a not local decision from a component:\n- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
784
		}
785
		
786
		// check if already SILENT
787
		if (this.isSilent(dec)) {
788
			// warning information
789
			warning("Trying to free an already SILENT decision:\n- decision: " + dec + "\n");
790
		}
791
		
792
		// check if ACTIVE
793
		if (this.isActive(dec)) {
794
			// check as this could be a potential bug in the backtracking procedure when "restoring" plan states 
795
			throw new RuntimeException("Trying to free an ACTIVE decision:\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
796
		}
797
		
798
		// complete transition PENDING -> SILENT
799
		if (this.isPending(dec)) {
800
			// delete pending decision
801
			this.decisions.get(PlanElementStatus.PENDING).remove(dec);
802
			// add to silent decisions
803
			this.decisions.get(PlanElementStatus.SILENT).add(dec);
804
		}
805
	}
806
	
807
	/**
808
	 * Force delete of the decision from the component
809
	 * 
810
	 * @param dec
811
	 */
812
	public void delete(Decision dec)
813
	{
814
		// check decision component
815
		if (!dec.getComponent().equals(this)) {
816
			throw new RuntimeException("Trying to free a not local decision from a component:\n- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
817
		}
818
		
819
		// check if active ACTIVE -> PENDING
820
		if (this.isActive(dec)) {
821
			// deactivate decision and associated active relations
822
			this.deactivate(dec);
823
		}
824
		
825
		// complete transition PENDING -> SILENT
826
		if (this.isPending(dec)) {
827
			// delete pending decision
828
			this.decisions.get(PlanElementStatus.PENDING).remove(dec);
829
			// add to silent decisions
830
			this.decisions.get(PlanElementStatus.SILENT).add(dec);
831
		}
832
		
833
		if (this.isSilent(dec)) {
834
			// remove decision from silent set
835
			this.decisions.get(PlanElementStatus.SILENT).remove(dec);
836
		}
837
	}
838
	
839
	/**
840
	 * 
841
	 * @param reference
842
	 * @param target
843
	 * @param type
844
	 * @return
845
	 */
846
	@SuppressWarnings("unchecked")
847
	public synchronized <T extends Relation> T create(RelationType type, Decision reference, Decision target) 
848
	{
849
		// get reference component
850
		DomainComponent refComp = reference.getComponent();
851
		// get target component
852
		DomainComponent targetComp = target.getComponent();
853
		if (!refComp.equals(this) && !targetComp.equals(this)) {
854
			// "external" relation
855
			throw new RuntimeException("Trying to create an \"external\" relation for component:\n- component: " + this.name + "\n- reference: " + reference + "\n- target: " + target + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
856
		}
857
		
858
		// relation 
859
		T rel = null;
860
		try 
861
		{
862
			// get class
863
			Class<T> clazz = (Class<T>) Class.forName(type.getRelationClassName());
864
			// get constructor
865
			Constructor<T> c = clazz.getDeclaredConstructor(Integer.TYPE, Decision.class, Decision.class);
866
			c.setAccessible(true);
867
			// create instance
868
			rel = c.newInstance(RELATION_COUNTER.getAndIncrement(), reference, target);
869
			
870
			// check if local relation
871
			if (rel.isLocal()) {
872
				// add to local relations
873
				this.localRelations.add(rel);
874
			} else {
875
				// mutually access global relations
876
				synchronized (globalRelations) {
877
					// add to global relations
878
					globalRelations.add(rel);
879
				}
880
			}
881
		}
882
		catch (Exception ex) {
883
			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...
884
		}
885
		
886
		// get created relation
887
		return rel;
888
	}
889
	
890
	/**
891
	 * Get the set of local and global active relations concerning a particular decision
892
	 * 
893
	 * @param dec
894
	 * @return
895
	 */
896 View Code Duplication
	public synchronized Set<Relation> getActiveRelations(Decision dec)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
897
	{
898
		// check if local relation
899
		if (!dec.getComponent().equals(this)) {
900
			throw new RuntimeException("Unknown decision to component:- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
901
		}
902
		
903
		// list of active relations
904
		Set<Relation> set = new HashSet<>();
905
		// check local relations
906
		for (Relation rel : this.localRelations) {
907
			// check related decisions and relation status
908
			if ((rel.getReference().equals(dec) || 
909
					rel.getTarget().equals(dec)) 
910
					&& rel.isActive()) 
911
			{
912
				// add relation
913
				set.add(rel);
914
			}
915
		}
916
		
917
		// check global relations
918
		synchronized (globalRelations) {
919
			for (Relation rel : globalRelations) {
920
				// check related decision and relation status
921
				if ((rel.getReference().equals(dec) || 
922
						rel.getTarget().equals(dec)) && 
923
						rel.isActive()) 
924
				{
925
					// add relation
926
					set.add(rel);
927
				}
928
			}
929
		}
930
		
931
		// get the list
932
		return set;
933
	}
934
	
935
	/**
936
	 * Get the set of local and global active relations concerning a particular decision
937
	 * 
938
	 * @param reference
939
	 * @param target
940
	 * @return
941
	 */
942
	public synchronized Set<Relation> getActiveRelations(Decision reference, Decision target)
943
	{
944
		// check if local relation
945
		if (!reference.getComponent().equals(this) && !target.getComponent().equals(this)) {
946
			throw new RuntimeException("Unknown decisions to component:- component: " + this.name + "\n- reference: " + reference + "\n- target: " + target + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
947
		}
948
		
949
		// list of active relations
950
		Set<Relation> set = new HashSet<>();
951
		// check local relations
952
		for (Relation rel : this.localRelations) {
953
			// check decisions and relation status
954
			if (rel.getReference().equals(reference) && 
955
					rel.getTarget().equals(target) && 
956
					rel.isActive()) {
957
				
958
				// add relation
959
				set.add(rel);
960
			}
961
		}
962
		
963
		// check global relations
964
		synchronized (globalRelations) {
965
			for (Relation rel : globalRelations) {
966
				// check decisions and relation status
967
				if (rel.getReference().equals(reference) && 
968
						rel.getTarget().equals(target) && 
969
						rel.isActive()) {
970
					
971
					// add relation
972
					set.add(rel);
973
				}
974
			}
975
		}
976
		
977
		// get the list
978
		return set;
979
	}
980
	
981
	/**
982
	 * Get the set of local active relations on a component
983
	 *  
984
	 * @param dec
985
	 * @return
986
	 */
987
	public synchronized Set<Relation> getActiveRelations()
988
	{
989
		// list of active relations
990
		Set<Relation> set = new HashSet<>();
991
		// check local relations
992
		for (Relation rel : this.localRelations) {
993
			// check if active relation
994
			if (rel.isActive()) {
995
				// add relation
996
				set.add(rel);
997
			}
998
		}
999
		
1000
		// get the list
1001
		return set;
1002
	}
1003
	
1004
	/**
1005
	 * Get the list of local pending relations
1006
	 * 
1007
	 * @return
1008
	 */
1009
	public synchronized Set<Relation> getPendingRelations()
1010
	{
1011
		// list of active relations
1012
		Set<Relation> set = new HashSet<>();
1013
		// check local relations
1014
		for (Relation rel : this.localRelations) {
1015
			// check if active relation
1016
			if (rel.isPending()) {
1017
				// add relation
1018
				set.add(rel);
1019
			}
1020
		}
1021
		
1022
		// get the list
1023
		return set;
1024
	}
1025
	
1026
	/**
1027
	 * Get the list of both pending and active local relations
1028
	 * 
1029
	 * @return
1030
	 */
1031
	public synchronized Set<Relation> getRelations() {
1032
		// list of active relations
1033
		Set<Relation> set = new HashSet<>();
1034
		// check local relations
1035
		for (Relation rel : this.localRelations) {
1036
			// add relation
1037
			set.add(rel);
1038
		}
1039
		
1040
		// get the list
1041
		return set;
1042
	}
1043
	
1044
	/**
1045
	 * Get the set of not activated relations that concern a particular decision 
1046
	 * 
1047
	 * @param dec
1048
	 * @return
1049
	 */
1050 View Code Duplication
	public synchronized Set<Relation> getToActivateRelations(Decision dec) 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1051
	{
1052
		// check decision component
1053
		if (!dec.getComponent().equals(this)) {
1054
			throw new RuntimeException("Unknown decision to component:\n- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
1055
		}
1056
		
1057
		// list of relations
1058
		Set<Relation> set = new HashSet<>();
1059
		// check pending local relations
1060
		for (Relation rel : this.localRelations) {
1061
			// check decisions and relation status
1062
			if ((rel.getReference().equals(dec) || 
1063
					rel.getTarget().equals(dec)) && 
1064
					rel.canBeActivated()) 
1065
			{
1066
				// add pending local relation
1067
				set.add(rel);
1068
			}
1069
		}
1070
		
1071
		// check pending global relations
1072
		synchronized (globalRelations) {
1073
			for (Relation rel : globalRelations) {
1074
				// check reference and target decisions
1075
				if ((rel.getReference().equals(dec) || 
1076
						rel.getTarget().equals(dec)) && 
1077
						rel.canBeActivated()) 
1078
				{
1079
					// add pending global relation
1080
					set.add(rel);
1081
				}
1082
			}
1083
		}
1084
		
1085
		// get list 
1086
		return set;
1087
	}
1088
	
1089
	/**
1090
	 * Get the set of local and global pending relations concerning the decision 
1091
	 * @param dec
1092
	 * @return
1093
	 */
1094 View Code Duplication
	public synchronized Set<Relation> getPendingRelations(Decision dec) 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1095
	{
1096
		// check if local decision
1097
		if (!dec.getComponent().equals(this)) {
1098
			throw new RuntimeException("Unknown decision to component:- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
1099
		}
1100
		
1101
		// list of relations
1102
		Set<Relation> set = new HashSet<>();
1103
		// check local relations
1104
		for (Relation rel : this.localRelations) 
1105
		{
1106
			// check decisions and relation status
1107
			if ((rel.getReference().equals(dec) || 
1108
					rel.getTarget().equals(dec)) && 
1109
					rel.isPending()) {
1110
				// add pending relation
1111
				set.add(rel);
1112
			}
1113
		}
1114
		
1115
		// check global relations
1116
		synchronized (globalRelations) {
1117
			for (Relation rel : globalRelations) {
1118
				// check decisions and relation status
1119
				if ((rel.getReference().equals(dec) || rel.getTarget().equals(dec)) && rel.isPending()) {
1120
					// add pending relation
1121
					set.add(rel);
1122
				}
1123
			}
1124
		}
1125
		
1126
		// get list 
1127
		return set;
1128
	}
1129
	
1130
	/**
1131
	 * Get the set of all local and global relations concerning a decision
1132
	 * 
1133
	 * @param dec
1134
	 * @return
1135
	 */
1136 View Code Duplication
	public synchronized Set<Relation> getRelations(Decision dec)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1137
	{
1138
		// check if local decision
1139
		if (!dec.getComponent().equals(this)) {
1140
			throw new RuntimeException("Unknown decision to component:- component: " + this.name + "\n- decision: " + dec + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
1141
		}
1142
		
1143
		// list local of relations
1144
		Set<Relation> set = new HashSet<>();
1145
		for (Relation rel : this.localRelations) {
1146
			// check decisions and relation status
1147
			if (dec.equals(rel.getReference()) || 
1148
					dec.equals(rel.getTarget())) {
1149
				// add relation
1150
				set.add(rel);
1151
			}
1152
		}
1153
		
1154
		// check global relations
1155
		synchronized (globalRelations) {
1156
			// get also global relation
1157
			for (Relation rel : globalRelations) {
1158
				if (dec.equals(rel.getReference()) || 
1159
						dec.equals(rel.getTarget())) {
1160
					// add relation
1161
					set.add(rel);
1162
				}
1163
	 		}
1164
		}
1165
		
1166
		// get list 
1167
		return set;		
1168
	}
1169
	
1170
	/**
1171
	 * 
1172
	 * @param dec
1173
	 * @return
1174
	 */
1175
	public synchronized boolean isActive(Decision dec) {
1176
		return this.decisions.get(PlanElementStatus.ACTIVE) != null && 
1177
				decisions.get(PlanElementStatus.ACTIVE).contains(dec);
1178
	}
1179
	
1180
	/**
1181
	 * 
1182
	 * @param dec
1183
	 * @return
1184
	 */
1185
	public synchronized boolean isPending(Decision dec) {
1186
		return this.decisions.get(PlanElementStatus.PENDING) != null &&
1187
				this.decisions.get(PlanElementStatus.PENDING).contains(dec);
1188
	}
1189
	
1190
	/**
1191
	 * 
1192
	 * @param dec
1193
	 * @return
1194
	 */
1195
	public synchronized boolean isSilent(Decision dec) {
1196
		return this.decisions.get(PlanElementStatus.SILENT) != null &&
1197
				this.decisions.get(PlanElementStatus.SILENT).contains(dec);
1198
	}
1199
	
1200
	/**
1201
	 * 
1202
	 * @param relation
1203
	 */
1204
	public synchronized void delete(Relation relation) 
1205
	{
1206
		// check reference and target components
1207
		DomainComponent refComp = relation.getReference().getComponent();
1208
		DomainComponent tarComp = relation.getTarget().getComponent();
1209
		if (!refComp.equals(this) && !tarComp.equals(this)) {
1210
			// "external" relation
1211
			throw new RuntimeException("Trying to free an \"external\" relation for component:\n- component: " + this.name + "\n- relation: " + relation + "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
1212
		}
1213
		
1214
		// deactivate relation if necessary
1215
		this.deactivate(relation);
1216
		// check if local relation
1217
		if (this.localRelations.contains(relation)) {
1218
			// remove relation from component 
1219
			this.localRelations.remove(relation);
1220
		}
1221
		
1222
		// check global relation
1223
		synchronized (globalRelations) {
1224
			if (globalRelations.contains(relation)) {
1225
				// remove from global relations
1226
				globalRelations.remove(relation);
1227
			}
1228
		}
1229
	}
1230
	
1231
	/**
1232
	 * Only for debugging 
1233
	 * 
1234
	 * @return
1235
	 */
1236
	public synchronized List<Decision> getSilentDecisions() {
1237
		return new ArrayList<>(this.decisions.get(PlanElementStatus.SILENT));
1238
	}
1239
	
1240
	/**
1241
	 * Get the list of silent local relations
1242
	 * 
1243
	 * Only for debugging 
1244
	 * 
1245
	 * @return
1246
	 */
1247
	public synchronized Set<Relation> getSilentRelations() {
1248
		// relations
1249
		Set<Relation> set = new HashSet<>();
1250
		// check local relations
1251
		for (Relation rel : this.localRelations) {
1252
			// check status
1253
			if (rel.isSilent()) {
1254
				set.add(rel);
1255
			}
1256
		}
1257
		// get the set
1258
		return set;
1259
	}
1260
	
1261
	/**
1262
	 * Propagate a local temporal relation.
1263
	 * 
1264
	 * Precondition: The related temporal intervals must be activated, i.e. they must have
1265
	 * temporal intervals associated
1266
	 * 
1267
	 * @param reference
1268
	 * @param target
1269
	 * @param constraint
1270
	 * @return
1271
	 * @throws RelationPropagationException
1272
	 */
1273
	public synchronized boolean activate(Relation rel) 
1274
			throws RelationPropagationException 
1275
	{
1276
		// check reference and target components
1277
		DomainComponent refComp = rel.getReference().getComponent();
1278
		DomainComponent tarComp = rel.getTarget().getComponent();
1279
		if (!refComp.equals(this) && !tarComp.equals(this)) {
1280
			// "external" relation
1281
			throw new RuntimeException("Trying to add an \"external\" relation for component:\n- component: " + this.name + "\n- relation: " + rel+ "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
1282
		}
1283
		
1284
		// check if can be activated
1285
		boolean canBeActivated = rel.canBeActivated();
1286
		// check no constraint is associated and if related decisions are active 
1287
		if (canBeActivated) 
1288
		{
1289
			try
1290
			{
1291
				// check relation type
1292
				switch (rel.getCategory()) 
1293
				{
1294
					// temporal constraint
1295
					case TEMPORAL_CONSTRAINT : 
1296
					{
1297
						// get temporal relation
1298
						TemporalRelation trel = (TemporalRelation) rel;
1299
						// create interval constraint
1300
						TemporalConstraint c = trel.create();
1301
						// propagate constraint
1302
						this.tdb.propagate(c);
1303
					}
1304
					break;
1305
					
1306
					// parameter constraint
1307
					case PARAMETER_CONSTRAINT : 
1308
					{
1309
						// get parameter relation
1310
						ParameterRelation prel = (ParameterRelation) rel;
1311
						// create related constraint
1312
						ParameterConstraint constraint = prel.create();
1313
						// propagate constraint
1314
						this.pdb.propagate(constraint);
1315
					}
1316
					break;
1317
				}
1318
			}
1319
			catch (ConstraintPropagationException ex) {
1320
				// clear relation
1321
				rel.clear();
1322
				// not that the relation is still "pending"
1323
				throw new RelationPropagationException(ex.getMessage());
1324
			}
1325
		}
1326
		else {
1327
			// debug information
1328
			debug("The decision you want to activate is already active or the related decision are not active yet:\n- " + rel + "\n");
1329
		}
1330
		
1331
		// get flag
1332
		return canBeActivated;
1333
	}
1334
	
1335
	/**
1336
	 * Propagate pending relations 
1337
	 * 
1338
	 * @param relations
1339
	 */
1340
	public synchronized void activate(Set<Relation> relations) 
1341
			throws RelationPropagationException 
1342
	{
1343
		// list of committed relations
1344
		List<Relation> committed = new ArrayList<>();
1345
		try 
1346
		{
1347
			// propagate relations
1348
			for (Relation rel : relations) {
1349
				// propagate relation
1350
				if (this.activate(rel)) {
1351
					// add to committed
1352
					committed.add(rel);
1353
				}
1354
			}
1355
		} 
1356
		catch (RelationPropagationException ex) {
1357
			
1358
			// error while propagating relations
1359
			for (Relation rel : committed) {
1360
				// deactivated committed relations
1361
				this.deactivate(rel);
1362
			}
1363
			
1364
			// forward exception
1365
			throw new RelationPropagationException(ex.getMessage());
1366
		}
1367
	}
1368
	
1369
	/**
1370
	 * Deactivate a relation by removing the related constraint if any. The relation remains into the component data 
1371
	 * structure as a "pending" relation
1372
	 * 
1373
	 * @param rel
1374
	 */
1375
	public synchronized void deactivate(Relation rel) 
1376
	{
1377
		// check reference and target components
1378
		DomainComponent refComp = rel.getReference().getComponent();
1379
		DomainComponent tarComp = rel.getTarget().getComponent();
1380
		if (!refComp.equals(this) && !tarComp.equals(this)) {
1381
			// "external" relation
1382
			throw new RuntimeException("Trying to delete an \"external\" relation for component:\n- component: " + this.name + "\n- relation: " + rel+ "\n");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
1383
		}
1384
		
1385
		// check underlying constraint
1386
		if (rel.getConstraint() != null)
1387
		{
1388
			// check relation type
1389
			switch (rel.getCategory()) 
1390
			{
1391
				// temporal constraint
1392
				case TEMPORAL_CONSTRAINT : 
1393
				{
1394
					// get temporal relation
1395
					TemporalRelation trel = (TemporalRelation) rel;
1396
					// retract the related constraint
1397
					this.tdb.retract(trel.getConstraint());
1398
					// clear relation
1399
					rel.clear();
1400
				}
1401
				break;
1402
				
1403
				// parameter constraint
1404
				case PARAMETER_CONSTRAINT : 
1405
				{
1406
					// get parameter relation
1407
					ParameterRelation prel = (ParameterRelation) rel;
1408
					// retract the related constraint
1409
					this.pdb.retract(prel.getConstraint());
1410
					// clear relation
1411
					rel.clear();
1412
				}
1413
				break;
1414
			}
1415
		}
1416
	}
1417
	
1418
	/**
1419
	 * 
1420
	 * @return
1421
	 */
1422
	public abstract <V extends ComponentValue> List<V> getValues();
1423
	
1424
	/**
1425
	 * 
1426
	 * @param name
1427
	 * @return
1428
	 */
1429
	public abstract ComponentValue getValueByName(String name);
1430
	
1431
	/**
1432
	 * 
1433
	 * @return
1434
	 */
1435
	public synchronized List<Flaw> checkFlaws() 
1436
	{
1437
		// list of flaws to solve
1438
		List<Flaw> list = new ArrayList<>();
1439
		// call resolvers to check flaws 
1440
		for (Resolver<?> resv : this.resolvers) {
1441
			// add detected flaws
1442
			list.addAll(resv.checkFlaws());
1443
		}
1444
1445
		// get the list of detected flaws
1446
		return list;
1447
	}
1448
	
1449
	/**
1450
	 * 
1451
	 * @param types
1452
	 * @return
1453
	 */
1454
	public synchronized List<Flaw> checkFlaws(FlawType[] types)
1455
	{
1456
		// list of flaws to solve
1457
		List<Flaw> list = new ArrayList<>();
1458
		for (FlawType fType : types) {
1459
			// check if exists
1460
			if (this.flawType2resolver.containsKey(fType)) {
1461
				// get resolver associated to the specified types
1462
				Resolver<?> resv = this.flawType2resolver.get(fType);
1463
				// add detected flaws
1464
				list.addAll(resv.checkFlaws());
1465
			}
1466
		}
1467
1468
		// get the list of detected flaws
1469
		return list;
1470
	}
1471
	
1472
	
1473
	/**
1474
	 * 
1475
	 * @return
1476
	 * @throws UnsolvableFlawException
1477
	 */
1478
	public synchronized List<Flaw> detectFlaws() 
1479
			throws UnsolvableFlawException 
1480
	{
1481
		// list of flaws to solve
1482
		List<Flaw> list = new ArrayList<>();
1483
		// flag about existence of unsolvable flaws
1484
		boolean unsolvable = false;
1485
		// call resolvers to detect flaws and possible solutions
1486
		for (Resolver<?> resv : this.resolvers) 
1487
		{
1488
			try 
1489
			{
1490
				// add detected flaws
1491
				list.addAll(resv.findFlaws());
1492
			}
1493
			catch (UnsolvableFlawException ex) {
1494
				// set unsolvable flag
1495
				unsolvable = true;
1496
				// warning 
1497
				warning("Component [" + this.name + "] detects flaws with not solutions:\n"
1498
						+ "- message= " + ex.getMessage() + "\n");
1499
			}
1500
		}
1501
1502
		// check flaws exist and are all unsolvable
1503
		if (list.isEmpty() && unsolvable) {
1504
			// throw exception if no solvable flaw was found by resolvers
1505
			throw new UnsolvableFlawException("Component [" + this.name + "] detects unsolvable flaws only!");
1506
		}
1507
		
1508
		// get the list of detected flaws
1509
		return list;
1510
	}
1511
	
1512
	
1513
1514
	/**
1515
	 * 
1516
	 * @param type
1517
	 * @return
1518
	 * @throws UnsolvableFlawException
1519
	 */
1520
	public synchronized List<Flaw> detectFlaws(FlawType type) 
1521
			throws UnsolvableFlawException
1522
	{
1523
		// list of flaws to solve
1524
		List<Flaw> list = new ArrayList<>();
1525
		// get resolver capable to handle the desired set of flaws, if any
1526
		if (this.flawType2resolver.containsKey(type))
1527
		{
1528
			// get related resolver
1529
			Resolver<?> resv = this.flawType2resolver.get(type);
1530
			// detect flaws
1531
			list.addAll(resv.findFlaws());
1532
		}
1533
		
1534
		// get the list of detected flaws
1535
		return list;
1536
	}
1537
	
1538
	/**
1539
	 * Solve a flaw by applying the selected solution
1540
	 * 
1541
	 * @param flaw
1542
	 * @param sol
1543
	 * @throws FlawSolutionApplicationException
1544
	 */
1545
	public synchronized void commit(FlawSolution solution) 
1546
			throws FlawSolutionApplicationException {
1547
		// dispatch the flaw to the correct resolver
1548
		this.flawType2resolver.get(solution.getFlaw().getType()).apply(solution);
1549
	}
1550
	
1551
	/**
1552
	 * 
1553
	 * @param solution
1554
	 * @throws Exception
1555
	 */
1556
	public synchronized void restore(FlawSolution solution) 
1557
			throws Exception {
1558
		// dispatch the flaw to the correct resolver
1559
		this.flawType2resolver.get(solution.getFlaw().getType()).restore(solution);
1560
	}
1561
	
1562
	/**
1563
	 * 
1564
	 * @param solution
1565
	 */
1566
	public synchronized void rollback(FlawSolution solution) {
1567
		// dispatch to the correct resolver
1568
		this.flawType2resolver.get(solution.getFlaw().getType()).retract(solution);
1569
	}
1570
1571
	/**
1572
	 * 
1573
	 */
1574
	@Override
1575
	public int hashCode() {
1576
		final int prime = 31;
1577
		int result = 1;
1578
		result = prime * result + ((name == null) ? 0 : name.hashCode());
1579
		return result;
1580
	}
1581
1582
	/**
1583
	 * 
1584
	 */
1585
	@Override
1586
	public boolean equals(Object obj) {
1587
		if (this == obj)
1588
			return true;
1589
		if (obj == null)
1590
			return false;
1591
		if (getClass() != obj.getClass())
1592
			return false;
1593
		DomainComponent other = (DomainComponent) obj;
1594
		if (name == null) {
1595
			if (other.name != null)
1596
				return false;
1597
		} else if (!name.equals(other.name))
1598
			return false;
1599
		return true;
1600
	}
1601
1602
	/**
1603
	 * 
1604
	 */
1605
	@Override
1606
	public String toString() {
1607
		return "{ \"name\": \"" + this.name + "\" }";
1608
	}
1609
	
1610
	/**
1611
	 * 
1612
	 * @param id
1613
	 * @param value
1614
	 * @param labels
1615
	 * @param start
1616
	 * @param end
1617
	 * @param duration
1618
	 * @param state
1619
	 * @return
1620
	 * @throws TemporalIntervalCreationException
1621
	 * @throws ParameterCreationException
1622
	 */
1623
	public synchronized Token createToken(int id, ComponentValue value, String[] labels, long[] start, long[] end, long[] duration, ExecutionNodeStatus state) 
1624
			throws TemporalIntervalCreationException, ParameterCreationException
1625
	{
1626
		// create a temporal interval
1627
		TemporalInterval interval = this.tdb.
1628
				createTemporalInterval(
1629
						start,
1630
						end, 
1631
						duration, 
1632
						value.isControllable());
1633
		
1634
		// create predicate
1635
		Predicate predicate = new Predicate(PREDICATE_COUNTER.getAndIncrement(), value);
1636
		
1637
		// get place holders
1638
		for (int index = 0; index < labels.length; index++) 
1639
		{
1640
			// get value's parameter place holder
1641
			ParameterPlaceHolder ph = value.getParameterPlaceHolderByIndex(index);
1642
			
1643
			// create a parameter
1644
			Parameter<?> param = this.pdb.createParameter(labels[index], ph.getDomain());
1645
1646
			// add parameter to predicate
1647
			
1648
			// add parameter
1649
			this.pdb.addParameter(param);
1650
			
1651
			// add parameter to the predicate at the specified position
1652
			predicate.setParameter(index, labels[index], param);
1653
		}
1654
		
1655
		// create token
1656
		return new Token(id, this, interval, predicate, state);
1657
	}
1658
}