1 | /** |
2 | * |
3 | */ |
4 | package de.fzi.se.accuracy.transformation; |
5 | |
6 | import java.util.ArrayList; |
7 | import java.util.List; |
8 | |
9 | import org.apache.log4j.Logger; |
10 | |
11 | import de.fzi.se.accuracy.issues.AccuracyIssueFactory; |
12 | import de.fzi.se.accuracy.jobs.TransformPCMForAccuracyInfluenceAnalysisJob; |
13 | import de.fzi.se.quality.QualityFactory; |
14 | import de.fzi.se.quality.QualityRepository; |
15 | import de.fzi.se.quality.qualityannotation.ExactlyAsSpecifiedPrecision; |
16 | import de.fzi.se.quality.qualityannotation.PCMRECategory; |
17 | import de.fzi.se.quality.qualityannotation.PCMRERequestCategory; |
18 | import de.fzi.se.quality.qualityannotation.PCMServiceSpecification; |
19 | import de.fzi.se.quality.qualityannotation.QualityAnnotation; |
20 | import de.fzi.se.quality.qualityannotation.QualityAnnotationFactory; |
21 | import de.fzi.se.quality.qualityannotation.REPrecision; |
22 | import de.fzi.se.quality.qualityannotation.RequiredElement; |
23 | import de.fzi.se.quality.util.EMFHelper; |
24 | import de.fzi.se.quality.util.QualityAnnotationLookup; |
25 | import de.uka.ipd.sdq.errorhandling.SeverityAndIssue; |
26 | import de.uka.ipd.sdq.errorhandling.SeverityEnum; |
27 | import de.uka.ipd.sdq.pcm.seff.AbstractAction; |
28 | import de.uka.ipd.sdq.pcm.seff.AbstractBranchTransition; |
29 | import de.uka.ipd.sdq.pcm.seff.AbstractInternalControlFlowAction; |
30 | import de.uka.ipd.sdq.pcm.seff.AbstractLoopAction; |
31 | import de.uka.ipd.sdq.pcm.seff.BranchAction; |
32 | import de.uka.ipd.sdq.pcm.seff.ExternalCallAction; |
33 | import de.uka.ipd.sdq.pcm.seff.ForkAction; |
34 | import de.uka.ipd.sdq.pcm.seff.InternalCallAction; |
35 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingBehaviour; |
36 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingInternalBehaviour; |
37 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingSEFF; |
38 | import de.uka.ipd.sdq.pcm.seff.ServiceEffectSpecification; |
39 | import de.uka.ipd.sdq.pcm.seff.StartAction; |
40 | import de.uka.ipd.sdq.pcm.seff.seff_performance.InfrastructureCall; |
41 | import de.uka.ipd.sdq.pcm.seff.seff_performance.ParametricResourceDemand; |
42 | import de.uka.ipd.sdq.pcm.seff.seff_performance.ResourceCall; |
43 | import de.uka.ipd.sdq.pcm.seff.util.SeffSwitch; |
44 | import de.uka.ipd.sdq.workflow.pcm.blackboard.PCMResourceSetPartition; |
45 | import de.uka.ipd.sdq.workflow.pcm.runconfig.AccuracyInfluenceAnalysisState; |
46 | |
47 | /** |
48 | * Abstract strategy implementing the transformation of given SEFFs for states |
49 | * in {@link AccuracyInfluenceAnalysisState}. Start the transformation by |
50 | * invoking {@link #doSwitch(org.eclipse.emf.ecore.EObject)} with a parameter of |
51 | * type {@link ServiceEffectSpecification}. Subclasses must provide an |
52 | * implementation for the abstract methods. Overwriting methods defined in this |
53 | * class is discouraged and may lead to unexpected behavior. |
54 | * |
55 | * @author groenda |
56 | */ |
57 | public abstract class AbstractAccuracyInfluenceSEFFTransformationStrategy extends |
58 | SeffSwitch<Boolean> { |
59 | /** Logger for this class. */ |
60 | private static final Logger logger = Logger |
61 | .getLogger(AbstractAccuracyInfluenceSEFFTransformationStrategy.class); |
62 | |
63 | /** List of available quality annotations. */ |
64 | private final List<QualityAnnotation> availableQualityAnnotations; |
65 | /** |
66 | * Lookup-Helper for the quality annotation corresponding to the currently |
67 | * processed SEFF. |
68 | */ |
69 | private QualityAnnotationLookup correspondingQualityLookup; |
70 | |
71 | /** List of warning and errors. */ |
72 | private final List<SeverityAndIssue> issues; |
73 | |
74 | /**Create a new instance. |
75 | * @param pcmPartition Partition containing quality annotations. |
76 | */ |
77 | public AbstractAccuracyInfluenceSEFFTransformationStrategy( |
78 | final PCMResourceSetPartition pcmPartition) { |
79 | this.availableQualityAnnotations = getQualityAnnotations(pcmPartition); |
80 | correspondingQualityLookup = null; |
81 | issues = new ArrayList<SeverityAndIssue>(); |
82 | } |
83 | |
84 | /** |
85 | * @return Gets the list of warning and errors. |
86 | */ |
87 | public List<SeverityAndIssue> getIssues() { |
88 | return issues; |
89 | } |
90 | |
91 | // START SECTION SUB-BEHAVIOR |
92 | @Override |
93 | public Boolean caseResourceDemandingSEFF(ResourceDemandingSEFF object) { |
94 | // determine accuracy |
95 | QualityAnnotation correspondingQuality = getQualityAnnotation(object, |
96 | availableQualityAnnotations); |
97 | if (correspondingQuality == null) { |
98 | issues.add(AccuracyIssueFactory.createMissingQualityAnnotationIssue(object)); |
99 | correspondingQuality = createQualityExactlyAsSpecifiedPrecision(); |
100 | } else if (correspondingQuality.isValid() == false) { |
101 | issues.add(AccuracyIssueFactory.createInvalidQualityAnnotationIssue(object)); |
102 | correspondingQuality = createQualityExactlyAsSpecifiedPrecision(); |
103 | } |
104 | correspondingQualityLookup = new QualityAnnotationLookup( |
105 | correspondingQuality); |
106 | // process resource demanding internal behaviors |
107 | for (ResourceDemandingInternalBehaviour rdib : object |
108 | .getResourceDemandingInternalBehaviours()) { |
109 | doSwitch(rdib); |
110 | } |
111 | // process self |
112 | return caseResourceDemandingBehaviour(object); |
113 | } |
114 | |
115 | /**Creates a quality annotation with default REPrecisions for all categories of {@link ExactlyAsSpecifiedPrecision}. |
116 | * @return Quality annotation. |
117 | */ |
118 | private QualityAnnotation createQualityExactlyAsSpecifiedPrecision() { |
119 | QualityAnnotation correspondingQuality; |
120 | // assume ExatlyAsSpecifiedPrecision |
121 | correspondingQuality = QualityAnnotationFactory.eINSTANCE.createQualityAnnotation(); |
122 | correspondingQuality.setIsValid(true); |
123 | correspondingQuality.getStipulatedREPrecisions().add(createREPrecisionExactlyAsSpecified(PCMRERequestCategory.COMPONENT)); |
124 | correspondingQuality.getStipulatedREPrecisions().add(createREPrecisionExactlyAsSpecified(PCMRERequestCategory.COMPONENT_INTERNAL)); |
125 | correspondingQuality.getStipulatedREPrecisions().add(createREPrecisionExactlyAsSpecified(PCMRERequestCategory.INFRASTRUCTURE)); |
126 | correspondingQuality.getStipulatedREPrecisions().add(createREPrecisionExactlyAsSpecified(PCMRERequestCategory.RESOURCE)); |
127 | correspondingQuality.getStipulatedREPrecisions().add(createREPrecisionExactlyAsSpecified(PCMRERequestCategory.RESOURCE_DEMAND)); |
128 | return correspondingQuality; |
129 | } |
130 | |
131 | /**Creates a required element with default precision for a given category with {@link ExactlyAsSpecifiedPrecision}. |
132 | * @param category Category. |
133 | * @return Required element. |
134 | */ |
135 | private RequiredElement createREPrecisionExactlyAsSpecified( |
136 | PCMRERequestCategory category) { |
137 | PCMRECategory re = QualityAnnotationFactory.eINSTANCE.createPCMRECategory(); |
138 | re.setCategory(category); |
139 | REPrecision precision = QualityAnnotationFactory.eINSTANCE.createREPrecision(); |
140 | precision.setDefaultPrecisionNumberOfCalls(QualityAnnotationFactory.eINSTANCE.createExactlyAsSpecifiedPrecision()); |
141 | if (category == PCMRERequestCategory.RESOURCE_DEMAND) { |
142 | // Resource demand does not have any parameters |
143 | precision.setDefaultPrecisionCallParameter(QualityAnnotationFactory.eINSTANCE.createNoPrecision()); |
144 | } else { |
145 | precision.setDefaultPrecisionCallParameter(QualityAnnotationFactory.eINSTANCE.createExactlyAsSpecifiedPrecision()); |
146 | } |
147 | re.setPrecision(precision); |
148 | return re; |
149 | } |
150 | |
151 | @Override |
152 | public Boolean caseResourceDemandingBehaviour( |
153 | ResourceDemandingBehaviour object) { |
154 | List<AbstractAction> steps = object.getSteps_Behaviour(); |
155 | StartAction start = EMFHelper.getFirstObjectByType(steps, |
156 | StartAction.class); |
157 | doSwitch(start); |
158 | return true; |
159 | } |
160 | |
161 | @Override |
162 | public Boolean caseBranchAction(BranchAction object) { |
163 | for (AbstractBranchTransition abt : object.getBranches_Branch()) { |
164 | doSwitch(abt.getBranchBehaviour_BranchTransition()); |
165 | } |
166 | // continue processing |
167 | return caseAbstractInternalControlFlowAction(object); |
168 | } |
169 | |
170 | @Override |
171 | public Boolean caseAbstractLoopAction(AbstractLoopAction object) { |
172 | doSwitch(object.getBodyBehaviour_Loop()); |
173 | // continue processing with caseAbstractAction |
174 | return caseAbstractAction(object); |
175 | } |
176 | |
177 | @Override |
178 | public Boolean caseForkAction(ForkAction object) { |
179 | doSwitch(object.getResourceDemandingBehaviour_AbstractAction()); |
180 | // continue processing |
181 | return caseAbstractInternalControlFlowAction(object); |
182 | } |
183 | |
184 | // Note: RecoveryBlockActions and RecoveryBlockAlternativeBehaviour are part |
185 | // of seff_reliability and not handled. |
186 | // END SECTION SUB-BEHAVIOR |
187 | |
188 | @Override |
189 | public Boolean caseServiceEffectSpecification( |
190 | ServiceEffectSpecification object) { |
191 | correspondingQualityLookup = null; |
192 | String msg = "The provided ServiceEffectSpecification type " + object + " is not supported by the implementation."; |
193 | logger.error(msg); |
194 | issues.add(new SeverityAndIssue(SeverityEnum.ERROR, msg, object)); |
195 | return true; |
196 | } |
197 | |
198 | /** |
199 | * @return Returns all quality annotations in the PCM partition. |
200 | */ |
201 | public List<QualityAnnotation> getQualityAnnotations( |
202 | final PCMResourceSetPartition pcmPartition) { |
203 | List<QualityAnnotation> qualityAnnotations = new ArrayList<QualityAnnotation>(); |
204 | List<QualityRepository> qualityRepos = pcmPartition |
205 | .getElement(QualityFactory.eINSTANCE |
206 | .createQualityRepository()); |
207 | for (QualityRepository qualityRepository : qualityRepos) { |
208 | TransformPCMForAccuracyInfluenceAnalysisJob.addElementsToList( |
209 | qualityAnnotations, EMFHelper.getObjectsByType(qualityRepository.getQualityStatements(), QualityAnnotation.class)); |
210 | } |
211 | return qualityAnnotations; |
212 | } |
213 | |
214 | /** |
215 | * Gets the quality annotation for a given RDSEFF from a list of |
216 | * annotations. |
217 | * |
218 | * @param rdseff |
219 | * The RDSEFF. |
220 | * @param qas |
221 | * The list of annotations. |
222 | * @return The quality annotation or {@code null} if none was found. |
223 | */ |
224 | public QualityAnnotation getQualityAnnotation( |
225 | final ResourceDemandingSEFF rdseff, |
226 | final List<QualityAnnotation> qas) { |
227 | int found = 0; |
228 | QualityAnnotation returnedAnnotation = null; |
229 | for (QualityAnnotation qualityAnnotation : qas) { |
230 | if (qualityAnnotation.getForServiceSpecification() instanceof PCMServiceSpecification) { |
231 | if (((PCMServiceSpecification) qualityAnnotation |
232 | .getForServiceSpecification()) |
233 | .getResourceDemandingSEFF() == rdseff) { |
234 | found++; |
235 | returnedAnnotation = qualityAnnotation; |
236 | } |
237 | } |
238 | } |
239 | if (found > 1) { |
240 | String msg = "There was more than one quality annotation for the RDSEFF with id " |
241 | + rdseff.getId() |
242 | + "in basic component " |
243 | + rdseff.getBasicComponent_ServiceEffectSpecification() |
244 | .getEntityName() |
245 | + " with id " |
246 | + rdseff.getBasicComponent_ServiceEffectSpecification() |
247 | .getId() |
248 | + ". The correct one could not be identified. The annotation with id " + returnedAnnotation.getId() + " is used."; |
249 | logger.warn(msg); |
250 | issues.add(new SeverityAndIssue(SeverityEnum.WARNING, msg, rdseff)); |
251 | } |
252 | return returnedAnnotation; |
253 | } |
254 | |
255 | @Override |
256 | public Boolean caseAbstractAction(AbstractAction object) { |
257 | // process successor relation of actions |
258 | if (object.getSuccessor_AbstractAction() != null) { |
259 | return doSwitch(object.getSuccessor_AbstractAction()); |
260 | } else { |
261 | return true; |
262 | } |
263 | } |
264 | |
265 | // START SECTION MODIFICATION |
266 | |
267 | @Override |
268 | public Boolean caseAbstractInternalControlFlowAction( |
269 | AbstractInternalControlFlowAction object) { |
270 | // handle infrastructure calls |
271 | REPrecision precision; |
272 | for (InfrastructureCall infrastructureCall : object |
273 | .getInfrastructureCall__Action()) { |
274 | precision = correspondingQualityLookup.getPCMREPrecision( |
275 | infrastructureCall |
276 | .getSignature__InfrastructureCall(), |
277 | infrastructureCall |
278 | .getRequiredRole__InfrastructureCall()); |
279 | ensurePrecisionExists(precision); |
280 | modifyInfrastructureCall(infrastructureCall, precision); |
281 | } |
282 | // handle explicit resource calls |
283 | for (ResourceCall resourceCall : object.getResourceCall__Action()) { |
284 | precision = correspondingQualityLookup |
285 | .getPCMREPrecision(resourceCall |
286 | .getSignature__ResourceCall(), resourceCall |
287 | .getResourceRequiredRole__ResourceCall()); |
288 | ensurePrecisionExists(precision); |
289 | modifyResourceCall(resourceCall, precision); |
290 | } |
291 | // handle implicit resource calls |
292 | for (ParametricResourceDemand demand : object |
293 | .getResourceDemand_Action()) { |
294 | precision = correspondingQualityLookup |
295 | .getPCMREPrecisionCategoryResourceDemand(); |
296 | ensurePrecisionExists(precision); |
297 | modifyResourceDemand(demand, precision); |
298 | } |
299 | // continue processing with caseAbstractAction |
300 | return caseAbstractAction(object); |
301 | } |
302 | |
303 | @Override |
304 | public Boolean caseExternalCallAction(ExternalCallAction object) { |
305 | REPrecision precision = correspondingQualityLookup |
306 | .getPCMREPrecision(object.getCalledService_ExternalService(), |
307 | object.getRole_ExternalService()); |
308 | ensurePrecisionExists(precision); |
309 | modifyComponentExternalCall(object, precision); |
310 | // continue processing |
311 | return caseAbstractAction(object); |
312 | } |
313 | |
314 | @Override |
315 | public Boolean caseInternalCallAction(InternalCallAction object) { |
316 | REPrecision precision = correspondingQualityLookup |
317 | .getPCMREPrecisionCategoryComponentInternal(); |
318 | ensurePrecisionExists(precision); |
319 | modifyComponentInternalCall(object, precision); |
320 | // continue processing |
321 | return caseAbstractInternalControlFlowAction(object); |
322 | } |
323 | |
324 | /**Ensures that a precision exists. |
325 | * @param precision The precision. |
326 | */ |
327 | private void ensurePrecisionExists(REPrecision precision) { |
328 | if (precision == null) { |
329 | String msg = "Could not determine a precision for the SEFF. Make sure a quality annotation exists for each SEFF of the system and that a precision is provided at least for each category."; |
330 | logger.error(msg); |
331 | throw new IllegalArgumentException(msg); |
332 | } |
333 | } |
334 | |
335 | // END SECTION MODIFICATION |
336 | |
337 | /** |
338 | * Implementation of modification strategy for infrastructure calls. |
339 | * |
340 | * @param call |
341 | * Infrastructure call. |
342 | * @param precision |
343 | * Stated accuracy. |
344 | */ |
345 | protected abstract void modifyInfrastructureCall(InfrastructureCall call, |
346 | REPrecision precision); |
347 | |
348 | /** |
349 | * Implementation of modification strategy for resource calls. |
350 | * |
351 | * @param call |
352 | * Infrastructure call. |
353 | * @param precision |
354 | * Stated accuracy. |
355 | */ |
356 | protected abstract void modifyResourceCall(ResourceCall call, |
357 | REPrecision precision); |
358 | |
359 | /** |
360 | * Implementation of modification strategy for (implicit) resource demands. |
361 | * |
362 | * @param call |
363 | * Infrastructure call. |
364 | * @param precision |
365 | * Stated accuracy. |
366 | */ |
367 | protected abstract void modifyResourceDemand( |
368 | ParametricResourceDemand demand, REPrecision precision); |
369 | |
370 | /** |
371 | * Implementation of modification strategy for (implicit) resource demands. |
372 | * |
373 | * @param call |
374 | * Infrastructure call. |
375 | * @param precision |
376 | * Stated accuracy. |
377 | */ |
378 | protected abstract void modifyComponentInternalCall( |
379 | InternalCallAction call, REPrecision precision); |
380 | |
381 | /** |
382 | * Implementation of modification strategy for (implicit) resource demands. |
383 | * |
384 | * @param call |
385 | * Infrastructure call. |
386 | * @param precision |
387 | * Stated accuracy. |
388 | */ |
389 | protected abstract void modifyComponentExternalCall( |
390 | ExternalCallAction call, REPrecision precision); |
391 | } |