| 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 | } |