it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponent   F
last analyzed

Complexity

Total Complexity 203

Size/Duplication

Total Lines 1612
Duplicated Lines 13.46 %

Importance

Changes 0
Metric Value
eloc 607
c 0
b 0
f 0
dl 217
loc 1612
rs 1.993
wmc 203

61 Methods

Rating   Name   Duplication   Size   Complexity  
A DomainComponent(String,DomainComponentType) 0 16 2
A getSynchronizationRules() 0 17 4
A create(ComponentValue,String[],long[],long[],long[]) 13 13 2
A create(ComponentValue,String[],long[]) 0 8 1
A getBehaviorDuration() 0 19 2
A isExternal() 0 2 1
A getGlobalPendingRelations() 0 12 3
A getName() 0 2 1
A clear() 0 23 3
A getSynchronizationRules(DomainComponent) 0 15 3
A getHorizon() 0 2 1
A getPendingDecisions() 0 2 1
A init() 0 7 3
A getActiveDecisions() 0 21 2
A getMakespan() 0 20 2
A create(ComponentValue,String[],long[],long[],long[],ExecutionNodeStatus) 13 13 2
A create(ComponentValue,String[]) 0 9 1
C activate(Decision) 0 95 11
A getGlobalRelations() 0 10 2
A restore(Decision) 26 26 5
A getOrigin() 0 2 1
A getSynchronizationRules(ComponentValue) 0 13 3
A display() 0 10 2
B restore(Relation) 0 48 8
A getType() 0 2 1
A getGlobalActiveRelations() 0 12 3
A create(ComponentValue,String[],long[],long[]) 0 8 1
B getActiveRelations(Decision) 37 37 8
B deactivate(Decision) 0 66 8
A free(Decision) 25 25 5
A getRelations() 0 11 2
A getPendingRelations() 0 15 3
A getActiveRelations() 0 15 3
A delete(Decision) 0 24 5
C getActiveRelations(Decision,Decision) 0 37 11
B create(RelationType,Decision,Decision) 0 43 5
A hashCode() 0 6 2
A getSilentRelations() 0 12 3
B activate(Relation) 0 60 7
A detectFlaws() 0 32 4
A activate(Set) 0 26 5
B getToActivateRelations(Decision) 37 38 8
A checkFlaws() 0 12 2
A restore(FlawSolution) 0 4 1
A isPending(Decision) 0 3 1
A isSilent(Decision) 0 3 1
B deactivate(Relation) 0 39 6
A delete(Relation) 0 23 5
A getSilentDecisions() 0 2 1
A isActive(Decision) 0 3 1
A rollback(FlawSolution) 0 3 1
getValueByName(String) 0 1 ?
B getPendingRelations(Decision) 34 34 8
A checkFlaws(FlawType[]) 0 16 3
A detectFlaws(FlawType) 0 16 2
B getRelations(Decision) 32 32 8
A createToken(int,ComponentValue,String[],long[],long[],long[],ExecutionNodeStatus) 0 36 4
A toString() 0 3 1
B equals(Object) 0 15 7
A commit(FlawSolution) 0 4 1
getValues() 0 1 ?

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

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

Complex classes like it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponent often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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