doApply(FlawSolution)   F
last analyzed

Complexity

Conditions 20

Size

Total Lines 166
Code Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 76
dl 0
loc 166
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.timeline.behavior.planning.TimelineBehaviorPlanningResolver.doApply(FlawSolution) 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.microkernel.resolver.timeline.behavior.planning;
2
3
import java.util.ArrayList;
4
import java.util.HashSet;
5
import java.util.List;
6
import java.util.Set;
7
8
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ComponentValue;
9
import it.cnr.istc.pst.platinum.ai.framework.domain.component.Decision;
10
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponent;
11
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.DecisionPropagationException;
12
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.FlawSolutionApplicationException;
13
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.RelationPropagationException;
14
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.TransitionNotFoundException;
15
import it.cnr.istc.pst.platinum.ai.framework.domain.component.sv.StateVariable;
16
import it.cnr.istc.pst.platinum.ai.framework.domain.component.sv.Transition;
17
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.ex.ConsistencyCheckException;
18
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.Flaw;
19
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.FlawSolution;
20
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.Relation;
21
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.RelationType;
22
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.parameter.EqualParameterRelation;
23
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.parameter.NotEqualParameterRelation;
24
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.temporal.MeetsRelation;
25
import it.cnr.istc.pst.platinum.ai.framework.microkernel.query.TemporalQueryType;
26
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.Resolver;
27
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.ResolverType;
28
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.ex.UnsolvableFlawException;
29
import it.cnr.istc.pst.platinum.ai.framework.parameter.lang.constraints.ParameterConstraintType;
30
import it.cnr.istc.pst.platinum.ai.framework.time.lang.query.IntervalDistanceQuery;
31
import it.cnr.istc.pst.platinum.ai.framework.time.lang.query.IntervalOverlapQuery;
32
import it.cnr.istc.pst.platinum.ai.framework.utils.properties.FilePropertyReader;
33
34
/**
35
 * 
36
 * @author alessandro
37
 *
38
 */
39
public final class TimelineBehaviorPlanningResolver extends Resolver<StateVariable> {
40
	
41
	private boolean load;
42
	private double cost;
43
	
44
	/**
45
	 * 
46
	 */
47
	protected TimelineBehaviorPlanningResolver() {
48
		super(ResolverType.TIMELINE_BEHAVIOR_PLANNING_RESOLVER.getLabel(), 
49
				ResolverType.TIMELINE_BEHAVIOR_PLANNING_RESOLVER.getFlawTypes());
50
		// set load flag
51
		this.load = false;
52
	}
53
	
54
	/**
55
	 * 
56
	 */
57
	private void load() {
58
		// get deliberative property file
59
		FilePropertyReader properties = new FilePropertyReader(
60
				FRAMEWORK_HOME + FilePropertyReader.DEFAULT_DELIBERATIVE_PROPERTY);
61
		// get weight
62
		this.cost = Double.parseDouble(properties.getProperty("completion-cost"));
63
		// set flag
64
		this.load = true;
65
	}
66
	
67
	/**
68
	 * 
69
	 */
70
	@Override
71
	protected void doApply(FlawSolution solution) 
72
			throws FlawSolutionApplicationException 
73
	{
74
		// get the flaw solution to apply
75
		GapCompletion completion = (GapCompletion) solution;
76
		// check solution path
77
		if (completion.getPath().isEmpty()) 
78
		{
79
			try 
80
			{
81
				// direct token transition between active decisions
82
				Decision reference = completion.getLeftDecision();
83
				Decision target = completion.getRightDecision();
84
				
85
				// create meets constraint to enforce the desired transition
86
				MeetsRelation meets = this.component.create(RelationType.MEETS, reference, target);
87
				// add created relation
88
				solution.addCreatedRelation(meets);
89
				// propagate relation
90
				if (this.component.activate(meets)) {
91
					// add activated relation to solution
92
					solution.addActivatedRelation(meets);
93
				}
94
				
95
				// create parameter relations
96
				Set<Relation> pRels = this.createParameterRelations(reference, target);
97
				// add created relation
98
				solution.addCreatedRelations(pRels);
99
				// propagate relation
100
				for (Relation pRel : pRels) {
101
					// activate relation if possible
102
					if (this.component.activate(pRel)) {
103
						// add activated relation to solution
104
						solution.addActivatedRelation(pRel);
105
					}
106
				}
107
				
108
				// check feasibility
109
				this.tdb.verify();
110
				this.pdb.verify();
111
			}
112
			catch (TransitionNotFoundException | RelationPropagationException | ConsistencyCheckException ex) 
113
			{
114
				// deactivate activated relations
115
				for (Relation rel : solution.getActivatedRelations()) {
116
					// get reference component
117
					DomainComponent refComp = rel.getReference().getComponent();
118
					refComp.deactivate(rel);
119
				}
120
				
121
				// delete created relations
122
				for (Relation rel : solution.getCreatedRelations()) {
123
					// get reference component
124
					DomainComponent refComp = rel.getReference().getComponent();
125
					// delete relation
126
					refComp.delete(rel);
127
				}
128
				
129
				// not feasible solution
130
				throw new FlawSolutionApplicationException(ex.getMessage());
131
			}
132
		}
133
		else 
134
		{
135
			// create the list of the decisions
136
			List<Decision> transition = new ArrayList<>();
137
			// add the gap-left decision
138
			transition.add(completion.getLeftDecision());
139
			try {
140
				
141
				// intermediate values and related relations can be activated since no synchronization is entailed
142
				for (ComponentValue value : completion.getPath()) 
143
				{
144
					// create parameters' labels
145
					String[] labels = new String[value.getNumberOfParameterPlaceHolders()];
146
					for (int index = 0; index < labels.length; index++) {
147
						// set parameter label
148
						labels[index] = "label-" + index;
149
					}
150
					
151
					// create pending decision
152
					Decision dec = this.component.create(value, labels);
153
					// these decisions can be set as mandatory expansion
154
					dec.setMandatoryExpansion();
155
					// add created decision to transition
156
					transition.add(dec);
157
					// add pending decision
158
					solution.addCreatedDecision(dec);
159
160
					// activate the decision if possible
161
					if (!value.isComplex()) {
162
						
163
						// activated decision
164
						Set<Relation> list = this.component.activate(dec);
165
						// add activated decisions
166
						solution.addActivatedDecision(dec);
167
						// add activated relations
168
						solution.addActivatedRelations(list);
169
					}
170
				}
171
				
172
				// add the gap-right decision
173
				transition.add(completion.getRightDecision());
174
				
175
				// create relations needed to enforce the transition
176
				for (int index = 0; index < transition.size() - 1; index++) 
177
				{
178
					// get adjacent decisions
179
					Decision reference = transition.get(index);
180
					Decision target = transition.get(index + 1);
181
					
182
					// create pending relation
183
					MeetsRelation meets = this.component.create(RelationType.MEETS, reference, target);
184
					// add created relation
185
					solution.addCreatedRelation(meets);
186
					// activate relation if possible
187
					if (this.component.activate(meets)) {
188
						// add to activated relations
189
						solution.addActivatedRelation(meets);
190
					}
191
						
192
					// create parameter relations
193
					Set<Relation> pRels = this.createParameterRelations(reference, target);
194
					// check relations
195
					for (Relation prel : pRels) {
196
						// add relation to solution
197
						solution.addCreatedRelation(prel);
198
						// activate relation if possible
199
						if (this.component.activate(prel)) {
200
							// add to activated relations
201
							solution.addActivatedRelation(prel);
202
						}
203
					}
204
				}
205
				
206
				// check consistency
207
				this.tdb.verify();
208
				this.pdb.verify();
209
			}
210
			catch (Exception ex) {
211
			
212
				// deactivate relations
213
				for (Relation rel : solution.getActivatedRelations()) {
214
					this.component.deactivate(rel);
215
				}
216
				
217
				// delete created relations
218
				for (Relation rel : solution.getCreatedRelations()) {
219
					this.component.delete(rel);
220
				}
221
				
222
				// deactivate decisions
223
				for (Decision dec : solution.getActivatedDecisions()) {
224
					this.component.deactivate(dec);
225
				}
226
				
227
				// free created decisions
228
				for (Decision dec : solution.getCreatedDecisions()) {
229
					this.component.free(dec);
230
				}
231
				
232
				// throw exception
233
				throw new FlawSolutionApplicationException("Error while applying flaw solution:\n"
234
						+ "- behavior-completion: " + completion + "\n"
235
						+ "- message: " + ex.getMessage() + "\n");
236
			}
237
		}
238
	}
239
	
240
	/**
241
	 * 
242
	 * @return
243
	 */
244
	@Override
245
	protected List<Flaw> doFindFlaws() 
246
	{
247
		// load flat
248
		if (!this.load) {
249
			this.load();
250
		}
251
				
252
		// list of gaps
253
		List<Flaw> flaws = new ArrayList<>();
254
		// get the "ordered" list of tokens on the component
255
		List<Decision> list = this.component.getActiveDecisions();
256
		
257
		// check gaps between adjacent decisions
258
		for (int index = 0; index < list.size() - 1; index++) 
259
		{
260
			// get two adjacent decisions
261
			Decision left = list.get(index);
262
			Decision right = list.get(index + 1);
263
			
264
			// check if scheduled
265
			IntervalOverlapQuery query = this.tdb.createTemporalQuery(
266
					TemporalQueryType.INTERVAL_OVERLAP);
267
			// set time points
268
			query.setReference(left.getToken().getInterval());
269
			query.setTarget(right.getToken().getInterval());
270
			
271
			// process query
272
			this.tdb.process(query);
273
			// check if they intervals can overlap
274
			if (query.canOverlap())
275
			{
276
				// precondition not satisfied
277
				debug("No timeline behavior flaw can be detected as tokens are not scheduled:\n"
278
						+ "- component: " + this.component + "\n"
279
						+ "- [reason] Behaviors cannot be plant due to potentially overlapping tokens:\n"
280
						+ "\t- reference: " + left + "\n"
281
						+ "\t- target: " + right + "\n");
282
				
283
				// clear data structures and stop inspecting this component for this type of flaws
284
				flaws = new ArrayList<>();
285
				break;
286
			}
287
			else 
288
			{
289
				// check if scheduled
290
				IntervalDistanceQuery distance = this.tdb.createTemporalQuery(
291
						TemporalQueryType.INTERVAL_DISTANCE);
292
				// set time points
293
				distance.setReference(left.getToken().getInterval());
294
				distance.setTarget(right.getToken().getInterval());
295
				// process query
296
				this.tdb.process(distance);
297
				
298
				// check the distance between the two decisions 
299
				if (distance.getDistanceLowerBound() >= 0 && distance.getDistanceUpperBound() > 0) 
300
				{
301
					// a gap has been found on the timeline 
302
					Gap gap = new Gap(FLAW_COUNTER.getAndIncrement(),
303
							this.component, 
304
							left, 
305
							right, 
306
							new long[] {
307
									distance.getDistanceLowerBound(), 
308
									distance.getDistanceUpperBound()});
309
					
310
					// add gap
311
					flaws.add(gap);
312
					debug("Gap found on component: "
313
							+ "- component: " + this.component + "\n"
314
							+ "- reference: " + left + "\n"
315
							+ "- target: " + right + "\n"
316
							+ "- distance: [" + distance.getDistanceLowerBound() + ", " + distance.getDistanceUpperBound() + "]\n");
317
				}
318
			}
319
		}
320
		
321
		
322
		// get flaws
323
		return flaws;
324
	}
325
	
326
	/**
327
	 * 
328
	 */
329
	@Override
330
	protected void doComputeFlawSolutions(Flaw flaw) 
331
			throws UnsolvableFlawException {
332
		
333
		
334
		// get the gap
335
		Gap gap = (Gap) flaw;
336
		// check gap type
337
		switch (gap.getGapType()) {
338
		
339
			// incomplete time-line
340
			case INCOMPLETE_TIMELINE : {
341
				
342
				// extract the direct predecessors of the right decision
343
				List<ComponentValue> predecessors = this.component.getDirectPredecessors(gap.getRightDecision().getValue());
344
				// create an alternative solution for each feasible predecessor
345
				for (ComponentValue pred : predecessors) {
346
					
347
					// check if direct transition
348
					if (pred.equals(gap.getLeftDecision().getValue())) {
349
						
350
						// direct transition from left to right
351
						GapCompletion solution = new GapCompletion(gap, new ArrayList<>(), this.cost);
352
						// list of created and activated decisions
353
						List<Decision> dCreated = new ArrayList<>();
354
						List<Decision> dActivated = new ArrayList<>();
355
						// list of created and activated relations
356
						List<Relation> rCreated = new ArrayList<>();
357
						List<Relation> rActivated = new ArrayList<>();
358
						
359
						try {
360
							
361
							// direct token transition between active decisions
362
							Decision reference = solution.getLeftDecision();
363
							Decision target = solution.getRightDecision();
364
							
365
							// create meets constraint to enforce the desired transition
366
							MeetsRelation meets = this.component.create(RelationType.MEETS, reference, target);
367
							// add created relation
368
							rCreated.add(meets);
369
							// propagate relation and activate it if possible
370
							if (this.component.activate(meets)) {
371
								// add activated relation to solution
372
								rActivated.add(meets);
373
							}
374
							
375
							// create parameter relations
376
							Set<Relation> pRels = this.createParameterRelations(reference, target);
377
							// add created relation
378
							rCreated.add(meets);
379
							// propagate relation
380
							for (Relation pRel : pRels) {
381
								// activate relation if possible
382
								if (this.component.activate(pRel)) {
383
									// add activated relation to solution
384
									rActivated.add(pRel);
385
								}
386
							}
387
							
388
							// the solution is feasible
389
							this.tdb.verify();
390
							this.pdb.verify();
391
							
392
							// valid solution
393
							gap.addSolution(solution);
394
							
395
						} catch (RelationPropagationException | TransitionNotFoundException |  ConsistencyCheckException ex) {
396
							// discard this path as not temporally feasible
397
							warning("Unfeasible direct transition for timelime behavior completion:\n"
398
									+ "- gap distance: [dmin= " + gap.getDmin() +", " + gap.getDmax() + "]");
399
						} finally {
400
							
401
							// deactivate relations
402
							for (Relation rel : rActivated) {
403
								this.component.deactivate(rel);
404
							}
405
							
406
							// delete relation
407
							for (Relation rel : rCreated) {
408
								this.component.delete(rel);
409
							}
410
							
411
							// deactivate decision
412
							for (Decision dec : dActivated) {
413
								this.component.deactivate(dec);
414
							}
415
							
416
							// free and then delete decision
417
							for (Decision dec : dCreated) {
418
								// free decision
419
								this.component.free(dec);
420
								// completely remove decision reference
421
								this.component.delete(dec);
422
							}
423
						}
424
					
425
					} else {
426
						
427
						
428
						// set (partial) steps to complete the gap 
429
						List<ComponentValue> steps = new ArrayList<>();
430
						steps.add(pred);
431
						
432
						// transition from left to right through the "step" value
433
						GapCompletion solution = new GapCompletion(gap, steps, this.cost);
434
						// list of created and activated decisions
435
						List<Decision> dCreated = new ArrayList<>();
436
						List<Decision> dActivated = new ArrayList<>();
437
						// list of created and activated relations
438
						List<Relation> rCreated = new ArrayList<>();
439
						List<Relation> rActivated = new ArrayList<>();
440
						
441
						try {
442
							
443
							
444
							// create parameters' labels
445
							String[] labels = new String[pred.getNumberOfParameterPlaceHolders()];
446
							for (int index = 0; index < labels.length; index++) {
447
								// set parameter label
448
								labels[index] = "label-" + index;
449
							}
450
							
451
							// create pending decision
452
							Decision dec = this.component.create(pred, labels);
453
							// these decisions can be set as mandatory expansion
454
							dec.setMandatoryExpansion();
455
							// add pending decision
456
							dCreated.add(dec);
457
458
							// activate the decision if possible
459
							if (!pred.isComplex()) {
460
								// activated decision
461
								Set<Relation> list = this.component.activate(dec);
462
								// add activated decisions
463
								dActivated.add(dec);
464
								// add activated relations
465
								rActivated.addAll(list);
466
							}
467
							
468
							// create pending relation
469
							MeetsRelation meets = this.component.create(RelationType.MEETS, dec, gap.getRightDecision());
470
							// add created relation
471
							rCreated.add(meets);
472
							// activate relation if possible
473
							if (this.component.activate(meets)) {
474
								// add to activated relations
475
								rActivated.add(meets);
476
							}
477
							
478
							// create parameter relations
479
							Set<Relation> pRels = this.createParameterRelations(dec, gap.getRightDecision());
480
							// check relations
481
							for (Relation prel : pRels) {
482
								// add relation to solution
483
								rCreated.add(prel);
484
								// activate relation if possible
485
								if (this.component.activate(prel)) {
486
									// add to activated relations
487
									rCreated.add(prel);
488
								}
489
							}
490
							
491
							// the solution is feasible
492
							this.tdb.verify();
493
							this.pdb.verify();
494
							
495
							// valid (partial) solution
496
							gap.addSolution(solution);
497
							
498
						} catch (RelationPropagationException | TransitionNotFoundException | DecisionPropagationException |  ConsistencyCheckException ex) {
499
							// discard this path as not temporally feasible
500
							warning("Unfeasible (partial) transition path for timelime behavior completion:\n"
501
									+ "- gap distance: [dmin= " + gap.getDmin() +", " + gap.getDmax() + "]\n"
502
									+ "- intermediate: " + pred + "\n");
503
						} finally {
504
							
505
							// deactivate relations
506
							for (Relation rel : rActivated) {
507
								this.component.deactivate(rel);
508
							}
509
							
510
							// delete relation
511
							for (Relation rel : rCreated) {
512
								this.component.delete(rel);
513
							}
514
							
515
							// deactivate decision
516
							for (Decision dec : dActivated) {
517
								this.component.deactivate(dec);
518
							}
519
							
520
							// free and then delete decision
521
							for (Decision dec : dCreated) {
522
								// free decision
523
								this.component.free(dec);
524
								// completely remove decision reference
525
								this.component.delete(dec);
526
							}
527
						}
528
					}
529
				}
530
			}
531
			break;
532
		
533
			// semantic connection missing
534
			case SEMANTIC_CONNECTION : {
535
				
536
				// direct connection between decisions
537
				GapCompletion solution = new GapCompletion(gap, new ArrayList<ComponentValue>(), this.cost);
538
				// add gap solution
539
				gap.addSolution(solution);
540
			}
541
			break;
542
		}
543
		
544
		// check if solvable
545
		if (!gap.isSolvable()) {
546
			throw new UnsolvableFlawException("Unsolvable gap found on component " + this.component.getName() + ":"
547
					+ "\n- gap: " + flaw + "\n");
548
		}
549
	}
550
	
551
	/**
552
	 * 
553
	 * @param reference
554
	 * @param target
555
	 * @return
556
	 * @throws TransitionNotFoundException
557
	 */
558
	private Set<Relation> createParameterRelations(Decision reference, Decision target) 
559
			throws TransitionNotFoundException 
560
	{
561
		// relations
562
		Set<Relation> rels = new HashSet<>();
563
		// get transition between values
564
		Transition t = this.component.getTransition(reference.getValue(), target.getValue());
565
		
566
		// reference parameter position index
567
		int referenceParameterIndex = 0;
568
		while (referenceParameterIndex < reference.getParameterLabels().length) {
569
			
570
			// target parameter position index
571
			int targetParameterIndex = 0;
572
			while (targetParameterIndex < target.getParameterLabels().length) {
573
				
574
				// check if a parameter constraint exists
575
				if (t.existsParameterConstraint(referenceParameterIndex, targetParameterIndex)) {
576
					// get parameter constraint type
577
					ParameterConstraintType pConsType = t.getParameterConstraintType(referenceParameterIndex, targetParameterIndex);
578
					
579
					// add (local) pending parameter constraint
580
					switch (pConsType) {
581
					
582
						// equal parameter constraint
583
						case EQUAL : {
584
							
585
							// create (pending) local relation
586
							EqualParameterRelation equal = (EqualParameterRelation) this.component.create(RelationType.EQUAL_PARAMETER, reference, target);
587
							// set reference parameter label
588
							equal.setReferenceParameterLabel(reference.getParameterLabelByIndex(referenceParameterIndex));
589
							// set target parameter label
590
							equal.setTargetParameterLabel(target.getParameterLabelByIndex(targetParameterIndex));
591
							// add create relation to solution
592
							rels.add(equal);
593
						}
594
						break;
595
						
596
						// not equal parameter
597
						case NOT_EQUAL : {
598
							
599
							// create (pending) local relation
600
							NotEqualParameterRelation notEqual = (NotEqualParameterRelation) this.component.create(RelationType.NOT_EQUAL_PARAMETER, reference, target);
601
							// set reference parameter label
602
							notEqual.setReferenceParameterLabel(reference.getParameterLabelByIndex(referenceParameterIndex));
603
							notEqual.setTargetParameterLabel(target.getParameterLabelByIndex(targetParameterIndex));
604
							// add create relation to solution
605
							rels.add(notEqual);
606
						}
607
						break;
608
						
609
						default : {
610
							
611
							throw new RuntimeException("Unknown parameter constraint type in state variable transition " + pConsType);
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
612
						}
613
					}
614
				}
615
				
616
				// next target parameter index
617
				targetParameterIndex++;
618
			}
619
			
620
			// next index
621
			referenceParameterIndex++;
622
		}
623
		
624
		// get created relations
625
		return rels;
626
	}
627
}
628