diff --git a/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectInterpreter.java b/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectInterpreter.java index 073fb485b..59e66330a 100644 --- a/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectInterpreter.java +++ b/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectInterpreter.java @@ -69,388 +69,407 @@ import de.uka.ipd.sdq.simulation.abstractsimengine.ISimProcessListener; /** - * Visitor implementation specialized to interpret {@link AdaptationBehavior}s - * that are triggered during Simulizar runs.
+ * Visitor implementation specialized to interpret {@link AdaptationBehavior}s that are triggered + * during Simulizar runs.
* This class is comparable to the interpreter classes within Simulizar. * * @author Florian Rosenthal * - */ + */ public class TransientEffectInterpreter extends CoreSwitch { - private static final Logger LOGGER = Logger.getLogger(TransientEffectInterpreter.class); - private static final String STATE_TRANSFORMING_EXT_POINT_ID = "org.palladiosimulator.simulizar.action.stratetransformation"; - private static final String STATE_TRANSFORMING_CLASS_NAME = "class"; - - private static final ExecutionContext DEFAULT_EXECUTION_CONTEXT = ContextFactory.eINSTANCE.createExecutionContext(); - - private final SimuLizarRuntimeState state; - private final ReconfigurationProcess associatedReconfigurationProcess; - private final RoleSet roleSet; - private final ControllerCallInputVariableUsageCollection controllerCallsInputVariableUsages; - private final boolean isAsync; - - private Optional executionContext; - - private final IResourceTableManager resourceTableManager; - private final SimulatedThreadComponent.Factory simulatedThreadComponentFactory; - - /** - * Initializes a new instance of the {@link TransientEffectInterpreter} - * class with the given arguments. - * - * @param state - * The {@link SimuLizarRuntimeState} of the current Simulizar - * run. - * @param set - * The {@link RoleSet} instance which shall be used for - * interpretation. - * @param controllerCallsInputVariableUsages - * The {@link ControllerCallInputVariableUsageCollection} model - * element which contains the - * {@link ControllerCallInputVariableUsage}s. - * @param repository - * The current {@link AdaptationBehaviorRepository}. - * @param executeAsync - * A flag to indicate whether the adaptation behaviors shall be - * interpreted asynchronously in a dedicated - * {@link SimuComSimProcess}. - */ + private static final Logger LOGGER = Logger.getLogger(TransientEffectInterpreter.class); + private static final String STATE_TRANSFORMING_EXT_POINT_ID = "org.palladiosimulator.simulizar.action.stratetransformation"; + private static final String STATE_TRANSFORMING_CLASS_NAME = "class"; + + private static final ExecutionContext DEFAULT_EXECUTION_CONTEXT = ContextFactory.eINSTANCE.createExecutionContext(); + + private final SimuLizarRuntimeState state; + private final ReconfigurationProcess associatedReconfigurationProcess; + private final RoleSet roleSet; + private final ControllerCallInputVariableUsageCollection controllerCallsInputVariableUsages; + private final boolean isAsync; + + private Optional executionContext; + + private final IResourceTableManager resourceTableManager; + private final SimulatedThreadComponent.Factory simulatedThreadComponentFactory; + + /** + * Initializes a new instance of the {@link TransientEffectInterpreter} class with the given + * arguments. + * + * @param state + * The {@link SimuLizarRuntimeState} of the current Simulizar run. + * @param set + * The {@link RoleSet} instance which shall be used for interpretation. + * @param controllerCallsInputVariableUsages + * The {@link ControllerCallInputVariableUsageCollection} model element which + * contains the {@link ControllerCallInputVariableUsage}s. + * @param repository + * The current {@link AdaptationBehaviorRepository}. + * @param executeAsync + * A flag to indicate whether the adaptation behaviors shall be interpreted + * asynchronously in a dedicated {@link SimuComSimProcess}. + */ TransientEffectInterpreter(SimuLizarRuntimeState state, RoleSet set, ControllerCallInputVariableUsageCollection controllerCallsInputVariableUsages, AdaptationBehaviorRepository repository, boolean executeAsync, Optional executionContext, IResourceTableManager resourceTableManager) { - this.state = state; - this.associatedReconfigurationProcess = this.state.getReconfigurator().getReconfigurationProcess(); - this.roleSet = set; - this.isAsync = executeAsync; - this.controllerCallsInputVariableUsages = Objects.requireNonNull(controllerCallsInputVariableUsages); - this.executionContext = executionContext; - this.resourceTableManager = resourceTableManager; - this.simulatedThreadComponentFactory = state.getSimulatedThreadComponentFactory(); - } - - private AsyncInterpretationProcess createAsyncProcess(AdaptationBehavior behaviorToInterpret) { - AsyncInterpretationProcess asyncInterpretationProcess = new AsyncInterpretationProcess(this.executionContext, - behaviorToInterpret); - asyncInterpretationProcess.addProcessListener(new ISimProcessListener() { - - @Override - public void notifyTerminated(ISimProcess process) { - ExecutionContextKeeper.getInstance().removeContextProcessMapping( - asyncInterpretationProcess.getCorrespondingContext(), asyncInterpretationProcess); - } - - @Override - public void notifySuspending(ISimProcess process) { - } - - @Override - public void notifyResuming(ISimProcess process) { - - } - }); - return asyncInterpretationProcess; - } - - private SimuComSimProcess obtainExecutingProcessForContext() { - assert !this.isAsync; - - SimuComSimProcess interpreterProcess = null; - ExecutionContext context = this.executionContext.orElse(DEFAULT_EXECUTION_CONTEXT); - if (context.getId().equals(DEFAULT_EXECUTION_CONTEXT.getId())) { - interpreterProcess = this.associatedReconfigurationProcess; - } else { - interpreterProcess = ExecutionContextKeeper.getInstance().getProcessForContext(context) - .orElseThrow(() -> new RuntimeException( - "Invalid context for synchronous execution of adaptation behavior:\n" - + "Corresponding process does not exist or has already terminated!")); - } - return interpreterProcess; - } - - @Override - public TransientEffectExecutionResult caseAdaptationBehavior(AdaptationBehavior adaptationBehavior) { - TransientEffectExecutionResult result; - - if (this.isAsync) { - // spawn an async process for interpretation and return immediately - AsyncInterpretationProcess asyncProcess = createAsyncProcess(adaptationBehavior); - ExecutionContextKeeper.getInstance().addContextProcessMapping(asyncProcess.getCorrespondingContext(), - asyncProcess); - TransientEffectInterpreter.this.executionContext = - Optional.of(asyncProcess.getCorrespondingContext()); - asyncProcess.activate(); - LOGGER.debug("Scheduled process for async interpretation of adaptation behavior."); - result = new TransientEffectExecutionResult(EventResult.SUCCESS, asyncProcess.getCorrespondingContext()); - } else { - LOGGER.debug("Synchronous execution of adaptation behavior \"" + adaptationBehavior.getEntityName() + "\" is taking place."); - boolean successful = executeAdaptationSteps(adaptationBehavior.getAdaptationSteps(), - obtainExecutingProcessForContext()); - if (successful) { - this.forwardReconfigurationNotification(new AdaptationBehaviorExecutedNotification(adaptationBehavior)); - LOGGER.debug("Synchronous execution of adaptation behavior \"" + adaptationBehavior.getEntityName() + "\" successfully done."); - } else{ - LOGGER.warn("Synchronous execution of adaptation behavior \"" + adaptationBehavior.getEntityName() + "\" finished with failures."); - } - // synchronous execution: no context shall be part of the result - result = new TransientEffectExecutionResult(EventResult.fromBoolean(successful), - this.executionContext.orElse(DEFAULT_EXECUTION_CONTEXT)); - - } - return result; - } - - private Boolean executeAdaptationSteps(Collection adaptationSteps, - SimuComSimProcess executingProcess) { - assert adaptationSteps != null && executingProcess != null; - InternalSwitch executingSwitch = new InternalSwitch(executingProcess); - // no short-circuit evaluation: ensure that all actions be executed - return adaptationSteps.stream().reduce(true, (result, action) -> executingSwitch.doSwitch(action), - Boolean::logicalAnd); - } - - private void forwardReconfigurationNotification(Notification notification) { - this.associatedReconfigurationProcess.appendReconfigurationNotification(notification); - } - - private static AbstractStateTransformation getStateTransformation(String extensionId) { - Optional stateTransformingExtension = Arrays - .stream(Platform.getExtensionRegistry().getExtensionPoint(STATE_TRANSFORMING_EXT_POINT_ID) - .getExtensions()) - .filter(extension -> extension.getUniqueIdentifier().equals(extensionId)).findAny(); - IExtension extension = stateTransformingExtension.orElseThrow(() -> new IllegalStateException( - "No state transformation registered for State Transforming Step " + extensionId)); - for (IConfigurationElement element : extension.getConfigurationElements()) { - try { - return (AbstractStateTransformation) element.createExecutableExtension(STATE_TRANSFORMING_CLASS_NAME); - } catch (CoreException e) { - LOGGER.error(e.getStackTrace()); - } - } - throw new IllegalStateException( - "No state transformation registered for State Transforming Step " + extensionId); - } - - private final class InternalSwitch extends CoreSwitch { - - /** - * Stores the {@link SimuComSimProcess} that creates and starts the user - * processes for the controller scenarios ( - * {@link ResourceDemandingAction}s if necessary.
- * In case of a synchronous execution of the adaptation behavior, this - * is just the associated {@link ReconfigurationProcess}. Otherwise, - * this is the new process that has been created for the asynchronous - * execution of the adaptation behavior. - * - * @see #spawnAsyncInterpreterProcess(AdaptationBehavior) - * @see #caseResourceDemandingAction(ResourceDemandingAction) - * @see #createAndScheduleControllerScenarioRunner(ControllerMapping) - */ - private final SimuComSimProcess executingProcess; - private final TransientEffectQVTOExecutor qvtoExecutor; - private final Map> inputVariableUsagesPerControllerCall; - - private InternalSwitch(SimuComSimProcess executingProcess) { - this.executingProcess = executingProcess; - QVToModelCache availableModels = new QVToModelCache( - Objects.requireNonNull(TransientEffectInterpreter.this.state.getPCMPartitionManager())); - - this.qvtoExecutor = new TransientEffectQVTOExecutor( - TransientEffectTransformationCacheKeeper.getTransformationCacheForRuntimeState( - TransientEffectInterpreter.this.state), - availableModels.snapshot()); - this.inputVariableUsagesPerControllerCall = TransientEffectInterpreter.this.controllerCallsInputVariableUsages - .getControllerCallInputVariableUsages().stream() - .collect(groupingBy(ControllerCallInputVariableUsage::getCorrespondingControllerCall, - mapping(ControllerCallInputVariableUsage::getVariableUsage, toList()))); - - this.qvtoExecutor.addTransformationParameters(TransientEffectInterpreter.this.roleSet, - TransientEffectInterpreter.this.executionContext.orElse(DEFAULT_EXECUTION_CONTEXT)); - } - - @Override - public Boolean caseNestedAdaptationBehavior(NestedAdaptationBehavior nestedAdaptationBehavior) { - return executeAdaptationSteps(nestedAdaptationBehavior.getAdaptationSteps(), this.executingProcess); - } - - @Override - public Boolean caseGuardedTransition(GuardedTransition guardedTransition) { - this.qvtoExecutor.enableForTransformationExecution(guardedTransition); - TransientEffectQVTOExecutorUtil.validateGuardedTransition(this.qvtoExecutor, guardedTransition); - - return this.qvtoExecutor.executeGuardedTransition(guardedTransition, resourceTableManager); - } - - @Override - public Boolean caseGuardedStep(GuardedStep guardedStep) { - // find the first GuardedTransition whose condition is evaluated to - // true - Optional branchToExecute = guardedStep.getGuardedTransitions().stream() - .filter(this::caseGuardedTransition).findFirst() - .map(GuardedTransition::getNestedAdaptationBehavior); - // incorporate case that no branch is to be executed (all conditions - // failed); - // then we return false - return branchToExecute.map(this::doSwitch).orElse(false); - } - - @Override - public Boolean caseStateTransformingStep(StateTransformingStep stateTransformingStep) { - this.qvtoExecutor.enableForTransformationExecution(stateTransformingStep); - - String extensionId = stateTransformingStep.getId(); - AbstractStateTransformation transformation = TransientEffectInterpreter.getStateTransformation(extensionId); - transformation.setSimulationState(TransientEffectInterpreter.this.state); - return transformation.execute(TransientEffectInterpreter.this.roleSet); - }; - - @Override - public Boolean caseAbstractAdaptationBehavior(AbstractAdaptationBehavior abstractAdaptationBehavior) { - throw new AssertionError("AbstractAdaptationBehavior is abstract, this case should not be reached at all!"); - } - - @Override - public Boolean caseAdaptationStep(final AdaptationStep step) { - throw new AssertionError("AdaptationStep is abstract, this case should not be reached at all!"); - } - - @Override - public Boolean caseResourceDemandingStep(final ResourceDemandingStep resourceDemandingStep) { - this.qvtoExecutor.enableForTransformationExecution(resourceDemandingStep); - - // perform controller completion - Mapping mapping = executeResourceDemandingStep(resourceDemandingStep) - .orElseThrow(() -> new RuntimeException("Controller Completion transformation failed!")); - - List users = new LinkedList(); - SimuComModel model = TransientEffectInterpreter.this.state.getMainContext().getModel(); - - // consume resources - for (ControllerMapping controllerMapping : mapping.getControllerMappings()) { - ControllerCall call = controllerMapping.getMappedCall(); - List usageStartStopProbes = Collections.unmodifiableList( - Arrays.asList((Probe) new TakeCurrentSimulationTimeProbe(model.getSimulationControl()), - (Probe) new TakeCurrentSimulationTimeProbe(model.getSimulationControl()))); - OpenWorkloadUser user = new OpenWorkloadUser(model, - resourceDemandingStep.getEntityName() + " " + call.getEntityName(), - createAndScheduleControllerScenarioRunner(controllerMapping), usageStartStopProbes, resourceTableManager); - users.add(user); - user.startUserLife(); - } - // wait until all users have finished executing by passivating the - // executing process - // if this is the underlying reconfiguration process, this ensures - // that no other - // reconfigurations can take place concurrently - while (checkIfUsersRun(users)) { - this.executingProcess.passivate(); - } - return true; - } - - @Override - public Boolean caseEnactAdaptationStep(EnactAdaptationStep enactAdaptationStep) { - this.qvtoExecutor.enableForTransformationExecution(enactAdaptationStep); - - // execute adaptation - TransientEffectQVTOExecutorUtil.validateEnactAdaptationStep(this.qvtoExecutor, enactAdaptationStep); - URI adaptationStepUri = URI.createURI(enactAdaptationStep.getAdaptationStepURI()); - QvtoModelTransformation adaptationStep = this.qvtoExecutor.getTransformationByUri(adaptationStepUri).get(); - final boolean result = this.qvtoExecutor.executeTransformation(adaptationStep, resourceTableManager); - if (result && !TransientEffectInterpreter.this.isAsync) { - TransientEffectInterpreter.this.forwardReconfigurationNotification( - new AdaptationStepExecutedNotification(enactAdaptationStep)); - } - return result; - } - - private IScenarioRunner createAndScheduleControllerScenarioRunner(ControllerMapping controllerMapping) { - - ControllerCall mappedCall = controllerMapping.getMappedCall(); - Collection variableUsages = this.inputVariableUsagesPerControllerCall - .getOrDefault(mappedCall, Collections.emptyList()); - - return process -> { - LOGGER.info("Start executing the controller scenario ('" + mappedCall.getEntityName() + "')!"); - - UsageScenario usageScenario = UsagemodelFactory.eINSTANCE.createUsageScenario(); - ScenarioBehaviour behaviour = UsagemodelFactory.eINSTANCE.createScenarioBehaviour(); - usageScenario.setScenarioBehaviour_UsageScenario(behaviour); - List actions = behaviour.getActions_ScenarioBehaviour(); - Start start = UsagemodelFactory.eINSTANCE.createStart(); - EntryLevelSystemCall sysCall = UsagemodelFactory.eINSTANCE.createEntryLevelSystemCall(); - Stop stop = UsagemodelFactory.eINSTANCE.createStop(); - actions.add(start); - actions.add(sysCall); - actions.add(stop); - sysCall.setOperationSignature__EntryLevelSystemCall(mappedCall.getCalledSignature()); - sysCall.setProvidedRole_EntryLevelSystemCall(controllerMapping.getControllerRole()); - // insert the input variable usages now - sysCall.getInputParameterUsages_EntryLevelSystemCall().addAll(variableUsages); - start.setSuccessor(sysCall); - sysCall.setSuccessor(stop); - simulatedThreadComponentFactory.create(state.getMainContext(), process) - .interpreterFacade().submit(usageScenario); - // finally, reschedule the executing process (this is crucial!) - // as it is passivated in caseResourceDemandingAction if mapped - // calls are running - this.executingProcess.scheduleAt(0); - - LOGGER.info("Execution of the controller scenario ('" + mappedCall.getEntityName() + "') finished!"); - }; - } - - private boolean checkIfUsersRun(Collection users) { - return users.stream().anyMatch(u -> !u.isTerminated()); - } - - private Optional executeResourceDemandingStep(ResourceDemandingStep resourceDemandingStep) { - assert resourceDemandingStep != null; - - // TODO FIXME currently it is assumed that all components are in the - // same repository - /* - * TODO FIXME Christian 'Real' reconfigurations should be handled - * differently than stereotype applications. - */ - Repository repository = resourceDemandingStep.getControllerCalls().get(0).getComponent() - .getRepository__RepositoryComponent(); - TransientEffectQVTOExecutorUtil.validateResourceDemandingStep(this.qvtoExecutor, resourceDemandingStep); - return this.qvtoExecutor.executeControllerCompletion(repository, resourceDemandingStep.getControllerCompletionURI(), resourceTableManager); - } - } - - private final class AsyncInterpretationProcess extends SimuComSimProcess { - - private final AdaptationBehavior behaviorToInterpret; - private final ExecutionContext correspondingContext; - - private AsyncInterpretationProcess(Optional context, AdaptationBehavior behaviorToInterpret) { - super(TransientEffectInterpreter.this.state.getModel(), - "SimuComSimProcess For Async Action Interpretation", resourceTableManager); - this.correspondingContext = context.orElseGet(ContextFactory.eINSTANCE::createExecutionContext); - this.behaviorToInterpret = behaviorToInterpret; - } - - @Override - protected void internalLifeCycle() { - LOGGER.debug("Async execution of adaptation behavior \"" + this.behaviorToInterpret.getEntityName() + "\" is taking place."); - // within the async process, just proceed regularly, that is, do the - // interpretation - // as usual, that is: with the async process, everything is - // processed - // synchronously - boolean result = TransientEffectInterpreter.this.executeAdaptationSteps(this.behaviorToInterpret.getAdaptationSteps(), - this); - if (result) { - LOGGER.debug("Async execution of adaptation behavior \"" + this.behaviorToInterpret.getEntityName() + "\" successfully done."); - } else{ - LOGGER.warn("Async execution of adaptation behavior \"" + this.behaviorToInterpret.getEntityName() + "\" finished with failures."); - } - } - - private ExecutionContext getCorrespondingContext() { - return this.correspondingContext; - } - } + this.state = state; + this.associatedReconfigurationProcess = this.state.getReconfigurator() + .getReconfigurationProcess(); + this.roleSet = set; + this.isAsync = executeAsync; + this.controllerCallsInputVariableUsages = Objects.requireNonNull(controllerCallsInputVariableUsages); + this.executionContext = executionContext; + this.resourceTableManager = resourceTableManager; + this.simulatedThreadComponentFactory = state.getSimulatedThreadComponentFactory(); + } + + private AsyncInterpretationProcess createAsyncProcess(AdaptationBehavior behaviorToInterpret) { + AsyncInterpretationProcess asyncInterpretationProcess = new AsyncInterpretationProcess(this.executionContext, + behaviorToInterpret); + asyncInterpretationProcess.addProcessListener(new ISimProcessListener() { + + @Override + public void notifyTerminated(ISimProcess process) { + ExecutionContextKeeper.getInstance() + .removeContextProcessMapping(asyncInterpretationProcess.getCorrespondingContext(), + asyncInterpretationProcess); + } + + @Override + public void notifySuspending(ISimProcess process) { + } + + @Override + public void notifyResuming(ISimProcess process) { + + } + }); + return asyncInterpretationProcess; + } + + private SimuComSimProcess obtainExecutingProcessForContext() { + assert !this.isAsync; + + SimuComSimProcess interpreterProcess = null; + ExecutionContext context = this.executionContext.orElse(DEFAULT_EXECUTION_CONTEXT); + if (context.getId() + .equals(DEFAULT_EXECUTION_CONTEXT.getId())) { + interpreterProcess = this.associatedReconfigurationProcess; + } else { + interpreterProcess = ExecutionContextKeeper.getInstance() + .getProcessForContext(context) + .orElseThrow( + () -> new RuntimeException("Invalid context for synchronous execution of adaptation behavior:\n" + + "Corresponding process does not exist or has already terminated!")); + } + return interpreterProcess; + } + + @Override + public TransientEffectExecutionResult caseAdaptationBehavior(AdaptationBehavior adaptationBehavior) { + TransientEffectExecutionResult result; + + if (this.isAsync) { + // spawn an async process for interpretation and return immediately + AsyncInterpretationProcess asyncProcess = createAsyncProcess(adaptationBehavior); + ExecutionContextKeeper.getInstance() + .addContextProcessMapping(asyncProcess.getCorrespondingContext(), asyncProcess); + TransientEffectInterpreter.this.executionContext = Optional.of(asyncProcess.getCorrespondingContext()); + asyncProcess.activate(); + LOGGER.debug("Scheduled process for async interpretation of adaptation behavior."); + result = new TransientEffectExecutionResult(EventResult.SUCCESS, asyncProcess.getCorrespondingContext()); + } else { + LOGGER.debug("Synchronous execution of adaptation behavior \"" + adaptationBehavior.getEntityName() + + "\" is taking place."); + boolean successful = executeAdaptationSteps(adaptationBehavior.getAdaptationSteps(), + obtainExecutingProcessForContext()); + if (successful) { + this.forwardReconfigurationNotification(new AdaptationBehaviorExecutedNotification(adaptationBehavior)); + LOGGER.debug("Synchronous execution of adaptation behavior \"" + adaptationBehavior.getEntityName() + + "\" successfully done."); + } else { + LOGGER.warn("Synchronous execution of adaptation behavior \"" + adaptationBehavior.getEntityName() + + "\" finished with failures."); + } + // synchronous execution: no context shall be part of the result + result = new TransientEffectExecutionResult(EventResult.fromBoolean(successful), + this.executionContext.orElse(DEFAULT_EXECUTION_CONTEXT)); + + } + return result; + } + + private Boolean executeAdaptationSteps(Collection adaptationSteps, + SimuComSimProcess executingProcess) { + assert adaptationSteps != null && executingProcess != null; + InternalSwitch executingSwitch = new InternalSwitch(executingProcess); + // no short-circuit evaluation: ensure that all actions be executed + return adaptationSteps.stream() + .reduce(true, (result, action) -> executingSwitch.doSwitch(action), Boolean::logicalAnd); + } + + private void forwardReconfigurationNotification(Notification notification) { + this.associatedReconfigurationProcess.appendReconfigurationNotification(notification); + } + + private static AbstractStateTransformation getStateTransformation(String extensionId) { + Optional stateTransformingExtension = Arrays.stream(Platform.getExtensionRegistry() + .getExtensionPoint(STATE_TRANSFORMING_EXT_POINT_ID) + .getExtensions()) + .filter(extension -> extension.getUniqueIdentifier() + .equals(extensionId)) + .findAny(); + IExtension extension = stateTransformingExtension.orElseThrow(() -> new IllegalStateException( + "No state transformation registered for State Transforming Step " + extensionId)); + for (IConfigurationElement element : extension.getConfigurationElements()) { + try { + return (AbstractStateTransformation) element.createExecutableExtension(STATE_TRANSFORMING_CLASS_NAME); + } catch (CoreException e) { + LOGGER.error(e.getStackTrace()); + } + } + throw new IllegalStateException( + "No state transformation registered for State Transforming Step " + extensionId); + } + + private final class InternalSwitch extends CoreSwitch { + + /** + * Stores the {@link SimuComSimProcess} that creates and starts the user processes for the + * controller scenarios ( {@link ResourceDemandingAction}s if necessary.
+ * In case of a synchronous execution of the adaptation behavior, this is just the + * associated {@link ReconfigurationProcess}. Otherwise, this is the new process that has + * been created for the asynchronous execution of the adaptation behavior. + * + * @see #spawnAsyncInterpreterProcess(AdaptationBehavior) + * @see #caseResourceDemandingAction(ResourceDemandingAction) + * @see #createAndScheduleControllerScenarioRunner(ControllerMapping) + */ + private final SimuComSimProcess executingProcess; + private final TransientEffectQVTOExecutor qvtoExecutor; + private final Map> inputVariableUsagesPerControllerCall; + + private InternalSwitch(SimuComSimProcess executingProcess) { + this.executingProcess = executingProcess; + QVToModelCache availableModels = new QVToModelCache( + Objects.requireNonNull(TransientEffectInterpreter.this.state.getPCMPartitionManager())); + + this.qvtoExecutor = new TransientEffectQVTOExecutor(TransientEffectTransformationCacheKeeper + .getTransformationCacheForRuntimeState(TransientEffectInterpreter.this.state), + availableModels.snapshot()); + this.inputVariableUsagesPerControllerCall = TransientEffectInterpreter.this.controllerCallsInputVariableUsages + .getControllerCallInputVariableUsages() + .stream() + .collect(groupingBy(ControllerCallInputVariableUsage::getCorrespondingControllerCall, + mapping(ControllerCallInputVariableUsage::getVariableUsage, toList()))); + + this.qvtoExecutor.addTransformationParameters(TransientEffectInterpreter.this.roleSet, + TransientEffectInterpreter.this.executionContext.orElse(DEFAULT_EXECUTION_CONTEXT)); + } + + @Override + public Boolean caseNestedAdaptationBehavior(NestedAdaptationBehavior nestedAdaptationBehavior) { + return executeAdaptationSteps(nestedAdaptationBehavior.getAdaptationSteps(), this.executingProcess); + } + + @Override + public Boolean caseGuardedTransition(GuardedTransition guardedTransition) { + this.qvtoExecutor.enableForTransformationExecution(guardedTransition); + TransientEffectQVTOExecutorUtil.validateGuardedTransition(this.qvtoExecutor, guardedTransition); + + return this.qvtoExecutor.executeGuardedTransition(guardedTransition, resourceTableManager); + } + + @Override + public Boolean caseGuardedStep(GuardedStep guardedStep) { + // find the first GuardedTransition whose condition is evaluated to + // true + Optional branchToExecute = guardedStep.getGuardedTransitions() + .stream() + .filter(this::caseGuardedTransition) + .findFirst() + .map(GuardedTransition::getNestedAdaptationBehavior); + // incorporate case that no branch is to be executed (all conditions + // failed); + // then we return false + return branchToExecute.map(this::doSwitch) + .orElse(false); + } + + @Override + public Boolean caseStateTransformingStep(StateTransformingStep stateTransformingStep) { + this.qvtoExecutor.enableForTransformationExecution(stateTransformingStep); + + String extensionId = stateTransformingStep.getId(); + AbstractStateTransformation transformation = TransientEffectInterpreter.getStateTransformation(extensionId); + transformation.setSimulationState(TransientEffectInterpreter.this.state); + return transformation.execute(TransientEffectInterpreter.this.roleSet); + }; + + @Override + public Boolean caseAbstractAdaptationBehavior(AbstractAdaptationBehavior abstractAdaptationBehavior) { + throw new AssertionError("AbstractAdaptationBehavior is abstract, this case should not be reached at all!"); + } + + @Override + public Boolean caseAdaptationStep(final AdaptationStep step) { + throw new AssertionError("AdaptationStep is abstract, this case should not be reached at all!"); + } + + @Override + public Boolean caseResourceDemandingStep(final ResourceDemandingStep resourceDemandingStep) { + this.qvtoExecutor.enableForTransformationExecution(resourceDemandingStep); + + // perform controller completion + Mapping mapping = executeResourceDemandingStep(resourceDemandingStep) + .orElseThrow(() -> new RuntimeException("Controller Completion transformation failed!")); + + List users = new LinkedList<>(); + SimuComModel model = TransientEffectInterpreter.this.state.getMainContext() + .getModel(); + + // consume resources + for (ControllerMapping controllerMapping : mapping.getControllerMappings()) { + ControllerCall call = controllerMapping.getMappedCall(); + List usageStartStopProbes = Collections.unmodifiableList( + Arrays.asList((Probe) new TakeCurrentSimulationTimeProbe(model.getSimulationControl()), + (Probe) new TakeCurrentSimulationTimeProbe(model.getSimulationControl()))); + OpenWorkloadUser user = new OpenWorkloadUser(model, + resourceDemandingStep.getEntityName() + " " + call.getEntityName(), + createAndScheduleControllerScenarioRunner(controllerMapping), usageStartStopProbes, + resourceTableManager); + users.add(user); + user.startUserLife(); + } + // wait until all users have finished executing by passivating the + // executing process + // if this is the underlying reconfiguration process, this ensures + // that no other + // reconfigurations can take place concurrently + while (checkIfUsersRun(users)) { + this.executingProcess.passivate(); + } + return true; + } + + @Override + public Boolean caseEnactAdaptationStep(EnactAdaptationStep enactAdaptationStep) { + this.qvtoExecutor.enableForTransformationExecution(enactAdaptationStep); + + // execute adaptation + TransientEffectQVTOExecutorUtil.validateEnactAdaptationStep(this.qvtoExecutor, enactAdaptationStep); + URI adaptationStepUri = URI.createURI(enactAdaptationStep.getAdaptationStepURI()); + QvtoModelTransformation adaptationStep = this.qvtoExecutor.getTransformationByUri(adaptationStepUri) + .get(); + Map configParams = Collections.emptyMap(); + final boolean result = this.qvtoExecutor.executeTransformation(adaptationStep, resourceTableManager, + configParams); + if (result && !TransientEffectInterpreter.this.isAsync) { + TransientEffectInterpreter.this + .forwardReconfigurationNotification(new AdaptationStepExecutedNotification(enactAdaptationStep)); + } + return result; + } + + private IScenarioRunner createAndScheduleControllerScenarioRunner(ControllerMapping controllerMapping) { + + ControllerCall mappedCall = controllerMapping.getMappedCall(); + Collection variableUsages = this.inputVariableUsagesPerControllerCall + .getOrDefault(mappedCall, Collections.emptyList()); + + return process -> { + LOGGER.info("Start executing the controller scenario ('" + mappedCall.getEntityName() + "')!"); + + UsageScenario usageScenario = UsagemodelFactory.eINSTANCE.createUsageScenario(); + ScenarioBehaviour behaviour = UsagemodelFactory.eINSTANCE.createScenarioBehaviour(); + usageScenario.setScenarioBehaviour_UsageScenario(behaviour); + List actions = behaviour.getActions_ScenarioBehaviour(); + Start start = UsagemodelFactory.eINSTANCE.createStart(); + EntryLevelSystemCall sysCall = UsagemodelFactory.eINSTANCE.createEntryLevelSystemCall(); + Stop stop = UsagemodelFactory.eINSTANCE.createStop(); + actions.add(start); + actions.add(sysCall); + actions.add(stop); + sysCall.setOperationSignature__EntryLevelSystemCall(mappedCall.getCalledSignature()); + sysCall.setProvidedRole_EntryLevelSystemCall(controllerMapping.getControllerRole()); + // insert the input variable usages now + sysCall.getInputParameterUsages_EntryLevelSystemCall() + .addAll(variableUsages); + start.setSuccessor(sysCall); + sysCall.setSuccessor(stop); + simulatedThreadComponentFactory.create(state.getMainContext(), process) + .interpreterFacade() + .submit(usageScenario); + // finally, reschedule the executing process (this is crucial!) + // as it is passivated in caseResourceDemandingAction if mapped + // calls are running + this.executingProcess.scheduleAt(0); + + LOGGER.info("Execution of the controller scenario ('" + mappedCall.getEntityName() + "') finished!"); + }; + } + + private boolean checkIfUsersRun(Collection users) { + return users.stream() + .anyMatch(u -> !u.isTerminated()); + } + + private Optional executeResourceDemandingStep(ResourceDemandingStep resourceDemandingStep) { + assert resourceDemandingStep != null; + + // TODO FIXME currently it is assumed that all components are in the + // same repository + /* + * TODO FIXME Christian 'Real' reconfigurations should be handled differently than + * stereotype applications. + */ + Repository repository = resourceDemandingStep.getControllerCalls() + .get(0) + .getComponent() + .getRepository__RepositoryComponent(); + TransientEffectQVTOExecutorUtil.validateResourceDemandingStep(this.qvtoExecutor, resourceDemandingStep); + return this.qvtoExecutor.executeControllerCompletion(repository, + resourceDemandingStep.getControllerCompletionURI(), resourceTableManager); + } + } + + private final class AsyncInterpretationProcess extends SimuComSimProcess { + + private final AdaptationBehavior behaviorToInterpret; + private final ExecutionContext correspondingContext; + + private AsyncInterpretationProcess(Optional context, AdaptationBehavior behaviorToInterpret) { + super(TransientEffectInterpreter.this.state.getModel(), "SimuComSimProcess For Async Action Interpretation", + resourceTableManager); + this.correspondingContext = context.orElseGet(ContextFactory.eINSTANCE::createExecutionContext); + this.behaviorToInterpret = behaviorToInterpret; + } + + @Override + protected void internalLifeCycle() { + LOGGER.debug("Async execution of adaptation behavior \"" + this.behaviorToInterpret.getEntityName() + + "\" is taking place."); + // within the async process, just proceed regularly, that is, do the + // interpretation + // as usual, that is: with the async process, everything is + // processed + // synchronously + boolean result = TransientEffectInterpreter.this + .executeAdaptationSteps(this.behaviorToInterpret.getAdaptationSteps(), this); + if (result) { + LOGGER.debug("Async execution of adaptation behavior \"" + this.behaviorToInterpret.getEntityName() + + "\" successfully done."); + } else { + LOGGER.warn("Async execution of adaptation behavior \"" + this.behaviorToInterpret.getEntityName() + + "\" finished with failures."); + } + } + + private ExecutionContext getCorrespondingContext() { + return this.correspondingContext; + } + } } diff --git a/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectQVTOExecutor.java b/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectQVTOExecutor.java index fcbb741a9..49647961b 100644 --- a/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectQVTOExecutor.java +++ b/bundles/org.palladiosimulator.simulizar.action/src-man/org/palladiosimulator/simulizar/action/interpreter/TransientEffectQVTOExecutor.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -14,6 +16,7 @@ import org.palladiosimulator.pcm.repository.Repository; import org.palladiosimulator.pcm.repository.RepositoryPackage; import org.palladiosimulator.simulizar.action.context.ExecutionContext; +import org.palladiosimulator.simulizar.action.core.AdaptationStep; import org.palladiosimulator.simulizar.action.core.EnactAdaptationStep; import org.palladiosimulator.simulizar.action.core.GuardedTransition; import org.palladiosimulator.simulizar.action.core.ResourceDemandingStep; @@ -38,14 +41,15 @@ */ class TransientEffectQVTOExecutor extends AbstractQVTOExecutor { - private static final Logger LOGGER = Logger.getLogger(TransientEffectQVTOExecutor.class); - + private static final Logger LOGGER = Logger.getLogger(TransientEffectQVTOExecutor.class); + private static final EPackage MAPPING_EPACKAGE = MappingPackage.Literals.MAPPING.getEPackage(); private static final EPackage REPOSITORY_EPACKAGE = RepositoryPackage.Literals.REPOSITORY.getEPackage(); private final Collection currentPureOutParams; - - protected TransientEffectQVTOExecutor(ModelTransformationCache transformationCache, QVToModelCache availableModels) { + + protected TransientEffectQVTOExecutor(ModelTransformationCache transformationCache, + QVToModelCache availableModels) { super(transformationCache, Objects.requireNonNull(availableModels)); this.currentPureOutParams = new ArrayList<>(); @@ -57,21 +61,27 @@ Optional executeControllerCompletion(Repository controllerCompletionRep Collection cachedRepo = this.getModelsByType(REPOSITORY_EPACKAGE); this.storeModel(controllerCompletionRepository); URI controllerCompletionUri = URI.createURI(controllerCompletionPath); - QvtoModelTransformation controllerCompletion = this.getTransformationByUri(controllerCompletionUri).get(); - boolean result = this.executeTransformation(controllerCompletion, resourceTableManager); + QvtoModelTransformation controllerCompletion = this.getTransformationByUri(controllerCompletionUri) + .get(); + Map configParams = Collections.emptyMap(); + boolean result = this.executeTransformation(controllerCompletion, resourceTableManager, configParams); // restore if necessary cachedRepo.forEach(repoInCache -> this.storeModel(repoInCache)); if (result) { - return this.getModelByType(MAPPING_EPACKAGE).map(obj -> (Mapping) obj); + return this.getModelByType(MAPPING_EPACKAGE) + .map(obj -> (Mapping) obj); } return Optional.empty(); } boolean executeGuardedTransition(GuardedTransition guardedTransition, IResourceTableManager resourceTableManager) { - URI conditionUri = URI.createURI(guardedTransition.getConditionURI()); - QvtoModelTransformation condition = this.getTransformationByUri(conditionUri).get(); - ExecutionDiagnostic result = this.executeTransformationInternal(Objects.requireNonNull(condition), resourceTableManager); - return handleExecutionResultForGuardedTransition(guardedTransition, result); + URI conditionUri = URI.createURI(guardedTransition.getConditionURI()); + QvtoModelTransformation condition = this.getTransformationByUri(conditionUri) + .get(); + Map configParams = Collections.emptyMap(); + ExecutionDiagnostic result = this.executeTransformationInternal(Objects.requireNonNull(condition), + resourceTableManager, configParams); + return handleExecutionResultForGuardedTransition(guardedTransition, result); } private void storeModel(EObject model) { @@ -88,10 +98,10 @@ private void prepareTransformation(String transformationUri) { } void addTransformationParameters(RoleSet roleSet, ExecutionContext context) { - storeModel(roleSet); - storeModel(context); + storeModel(roleSet); + storeModel(context); } - + void enableForTransformationExecution(EnactAdaptationStep enactAdaptationStep) { storeModel(Objects.requireNonNull(enactAdaptationStep)); prepareTransformation(enactAdaptationStep.getAdaptationStepURI()); @@ -107,7 +117,8 @@ void enableForTransformationExecution(StateTransformingStep stateTransformingSte } void enableForTransformationExecution(GuardedTransition guardedTransition) { - prepareTransformation(Objects.requireNonNull(guardedTransition).getConditionURI()); + prepareTransformation(Objects.requireNonNull(guardedTransition) + .getConditionURI()); } Optional getTransformationByUri(URI transformationId) { @@ -120,35 +131,45 @@ Collection getModelsByType(EPackage modelType) { Optional getModelByType(EPackage modelType) { Collection modelsOfType = this.getModelsByType(Objects.requireNonNull(modelType)); - return modelsOfType.isEmpty() ? Optional.empty() : Optional.of(modelsOfType.iterator().next()); + return modelsOfType.isEmpty() ? Optional.empty() + : Optional.of(modelsOfType.iterator() + .next()); } @Override protected boolean handleExecutionResult(ExecutionDiagnostic executionResult) { boolean result = super.handleExecutionResult(executionResult); if (result) { - this.currentPureOutParams.stream().map(ModelExtent::getContents).filter(contents -> !contents.isEmpty()) - .map(contents -> contents.get(0)).forEach(getAvailableModels()::storeModel); + this.currentPureOutParams.stream() + .map(ModelExtent::getContents) + .filter(contents -> !contents.isEmpty()) + .map(contents -> contents.get(0)) + .forEach(getAvailableModels()::storeModel); } return result; } - - protected boolean handleExecutionResultForGuardedTransition(GuardedTransition guardedTransition, ExecutionDiagnostic executionResult) { - if (executionResult.getCode() == ExecutionDiagnostic.FATAL_ASSERTION) { - LOGGER.info("Guard Condition of \"" + guardedTransition.getEntityName() + "\" evaluated to false. The transition is not taken."); - return false; - } else { - return this.handleExecutionResult(executionResult); - } - + + protected boolean handleExecutionResultForGuardedTransition(GuardedTransition guardedTransition, + ExecutionDiagnostic executionResult) { + if (executionResult.getCode() == ExecutionDiagnostic.FATAL_ASSERTION) { + LOGGER.info("Guard Condition of \"" + guardedTransition.getEntityName() + + "\" evaluated to false. The transition is not taken."); + return false; + } else { + return this.handleExecutionResult(executionResult); + } + } @Override protected ModelExtent[] setupModelExtents(QvtoModelTransformation transformation) { this.currentPureOutParams.clear(); ModelExtent[] result = super.setupModelExtents(transformation); - transformation.getPureOutParameters().stream().mapToInt(TransformationParameterInformation::getParameterIndex) - .mapToObj(index -> result[index]).forEach(this.currentPureOutParams::add); + transformation.getPureOutParameters() + .stream() + .mapToInt(TransformationParameterInformation::getParameterIndex) + .mapToObj(index -> result[index]) + .forEach(this.currentPureOutParams::add); return result; } } diff --git a/bundles/org.palladiosimulator.simulizar.reconfiguration.henshin/src/org/palladiosimulator/simulizar/reconfiguration/henshin/HenshinReconfigurator.java b/bundles/org.palladiosimulator.simulizar.reconfiguration.henshin/src/org/palladiosimulator/simulizar/reconfiguration/henshin/HenshinReconfigurator.java index 0abb25b82..c4b6af78c 100644 --- a/bundles/org.palladiosimulator.simulizar.reconfiguration.henshin/src/org/palladiosimulator/simulizar/reconfiguration/henshin/HenshinReconfigurator.java +++ b/bundles/org.palladiosimulator.simulizar.reconfiguration.henshin/src/org/palladiosimulator/simulizar/reconfiguration/henshin/HenshinReconfigurator.java @@ -1,10 +1,11 @@ package org.palladiosimulator.simulizar.reconfiguration.henshin; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; -import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.henshin.interpreter.EGraph; import org.eclipse.emf.henshin.interpreter.Engine; @@ -23,109 +24,119 @@ public class HenshinReconfigurator extends AbstractReconfigurator { - /** - * Henshin reconfigurator default constructor. - */ - public HenshinReconfigurator() { - super(); - } - - /** - * This class' internal LOGGER. - */ - private static final Logger LOGGER = Logger.getLogger(HenshinReconfigurator.class); - - @Override - public void setConfiguration(final SimuLizarWorkflowConfiguration configuration) { - this.configuration = configuration; - } - - /** - * @param app - * @param resourceSet - * @param module - * @param saveResult - */ - private boolean executeReconfiguration(UnitApplication app, Module module) { - // Load the measurement model into an EGraph - LOGGER.info("Called Henshin reconfiguration engine."); - EGraph graph = new EGraphImpl(this.pcmPartitionManager.getGlobalPCMModel().getAllocation()); - - app.setEGraph(graph); - - // Set parameters for rule and execute... - app.setUnit(module.getUnit("execute")); - - if (app.execute(null)) { - LOGGER.debug("Successfully executed Henshin rule."); - return true; - } else { - LOGGER.debug("Executing Henshin rule failed."); - return false; - - } - - } - - /** - * @param app - * @param resourceSet - * @param module - */ - private boolean analyzeReconfiguration(UnitApplication app, Module module) { - - // Load the example model into an EGraph: - RuntimeMeasurementModel rmModel = this.pcmPartitionManager.findModel(RuntimeMeasurementPackage.eINSTANCE.getRuntimeMeasurementModel()); - EGraph graph = new EGraphImpl(rmModel); - app.setEGraph(graph); - - // Execute analyze step of rule - app.setUnit(module.getUnit("analyze")); - - if (app.execute(null)) { - LOGGER.debug("Found matching Henshin rule."); - return true; - } else { - LOGGER.debug("No matching Henshin rule found."); - return false; - } - } - - @Override - public boolean runCheck(EList> checks, EObject monitoredElement, IResourceTableManager resourceTableManager) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean runExecute(EList> actions, - EObject monitoredElement, IResourceTableManager resourceTableManager) { - List transformations = new ArrayList(); - LOGGER.info("Executing Story Diagram Model Transformation."); - for (ModelTransformation action : actions) { - try { - if (action instanceof HenshinModelTransformation) { - HenshinModelTransformation henshinModelTransformation = (HenshinModelTransformation) action; - transformations.add(henshinModelTransformation); - } - } catch (ClassCastException e) { - LOGGER.info("Not a Storydiagram model transformation."); - } - } - - return executeTransformations(transformations); - } - - private boolean executeTransformations(List transformations) { - Engine engine = new EngineImpl(); - UnitApplication app = new UnitApplicationImpl(engine); - boolean result = false; - for (final HenshinModelTransformation transformation : transformations) { - if (analyzeReconfiguration(app, transformation.getModelTransformation())) { - result |= executeReconfiguration(app, transformation.getModelTransformation()); - } - } - return result; - } + /** + * Henshin reconfigurator default constructor. + */ + public HenshinReconfigurator() { + super(); + } + + /** + * This class' internal LOGGER. + */ + private static final Logger LOGGER = Logger.getLogger(HenshinReconfigurator.class); + + @Override + public void setConfiguration(final SimuLizarWorkflowConfiguration configuration) { + this.configuration = configuration; + } + + /** + * @param app + * @param resourceSet + * @param module + * @param saveResult + */ + private boolean executeReconfiguration(UnitApplication app, Module module) { + // Load the measurement model into an EGraph + LOGGER.info("Called Henshin reconfiguration engine."); + EGraph graph = new EGraphImpl(this.pcmPartitionManager.getGlobalPCMModel() + .getAllocation()); + + app.setEGraph(graph); + + // Set parameters for rule and execute... + app.setUnit(module.getUnit("execute")); + + if (app.execute(null)) { + LOGGER.debug("Successfully executed Henshin rule."); + return true; + } else { + LOGGER.debug("Executing Henshin rule failed."); + return false; + + } + + } + + /** + * @param app + * @param resourceSet + * @param module + */ + private boolean analyzeReconfiguration(UnitApplication app, Module module) { + + // Load the example model into an EGraph: + RuntimeMeasurementModel rmModel = this.pcmPartitionManager + .findModel(RuntimeMeasurementPackage.eINSTANCE.getRuntimeMeasurementModel()); + EGraph graph = new EGraphImpl(rmModel); + app.setEGraph(graph); + + // Execute analyze step of rule + app.setUnit(module.getUnit("analyze")); + + if (app.execute(null)) { + LOGGER.debug("Found matching Henshin rule."); + return true; + } else { + LOGGER.debug("No matching Henshin rule found."); + return false; + } + } + + @Override + public boolean runCheck(List> checks, EObject monitoredElement, + IResourceTableManager resourceTableManager) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager) { + Map configParams = Collections.emptyMap(); + return runExecute(actions, monitoredElement, resourceTableManager, configParams); + } + + @Override + public boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager, Map configParams) { + List transformations = new ArrayList<>(); + LOGGER.info("Executing Story Diagram Model Transformation."); + for (ModelTransformation action : actions) { + try { + if (action instanceof HenshinModelTransformation) { + HenshinModelTransformation henshinModelTransformation = (HenshinModelTransformation) action; + transformations.add(henshinModelTransformation); + } + } catch (ClassCastException e) { + LOGGER.info("Not a Storydiagram model transformation."); + } + } + + return executeTransformations(transformations); + } + + private boolean executeTransformations(List transformations) { + Engine engine = new EngineImpl(); + UnitApplication app = new UnitApplicationImpl(engine); + boolean result = false; + for (final HenshinModelTransformation transformation : transformations) { + if (analyzeReconfiguration(app, transformation.getModelTransformation())) { + result |= executeReconfiguration(app, transformation.getModelTransformation()); + } + } + return result; + } } diff --git a/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/AbstractQVTOExecutor.java b/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/AbstractQVTOExecutor.java index d8756d27c..3ab8e1ec6 100644 --- a/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/AbstractQVTOExecutor.java +++ b/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/AbstractQVTOExecutor.java @@ -128,12 +128,13 @@ protected QVToModelCache getAvailableModels() { * @see #executeTransformation(TransformationData) * @see #AbstractQVTOExecutor(TransformationCache, QVToModelCache) */ - public boolean executeTransformation(URI transformationURI, IResourceTableManager resourceTableManager) { + public boolean executeTransformation(URI transformationURI, IResourceTableManager resourceTableManager, + Map configParams) { Optional data = this.transformationCache .get(Objects.requireNonNull(transformationURI)); return executeTransformation(data.orElseThrow( () -> new IllegalArgumentException("Given transformation not present in transformation cache.")), - resourceTableManager); + resourceTableManager, configParams); } /** @@ -160,18 +161,19 @@ public boolean executeTransformation(URI transformationURI, IResourceTableManage * In case {@code transformationData == null} */ public final boolean executeTransformation(QvtoModelTransformation modelTransformation, - IResourceTableManager resourceTableManager) { - ExecutionDiagnostic result = executeTransformationInternal(modelTransformation, resourceTableManager); + IResourceTableManager resourceTableManager, Map configParams) { + ExecutionDiagnostic result = executeTransformationInternal(modelTransformation, resourceTableManager, + configParams); // check the result for success return handleExecutionResult(result); } protected ExecutionDiagnostic executeTransformationInternal(QvtoModelTransformation modelTransformation, - IResourceTableManager resourceTableManager) { + IResourceTableManager resourceTableManager, Map configParams) { ModelExtent[] modelExtents = setupModelExtents(Objects.requireNonNull(modelTransformation)); - Map configParams = new HashMap<>(); + Map contextParams = new HashMap<>(configParams); configParams.put("resourceTableManager", resourceTableManager); - ExecutionContext executionContext = setupExecutionContext(configParams); + ExecutionContext executionContext = setupExecutionContext(contextParams); // now run the transformation assigned to the executor with the given // input and output and execution context ExecutionDiagnostic result = doExecution(modelTransformation, executionContext, modelExtents); @@ -239,13 +241,13 @@ protected boolean handleExecutionResult(ExecutionDiagnostic executionResult) { * @return A fully-fledged {@link ExecutionContext}. * @see #doExecution(TransformationData, ExecutionContext, ModelExtent[]) */ - protected ExecutionContext setupExecutionContext(Map configParams) { + protected ExecutionContext setupExecutionContext(Map contextParams) { // setup the execution environment details -> // configuration properties, LOGGER, monitor object etc. ExecutionContextImpl result = new ExecutionContextImpl(); result.setLog(createLog()); - for (Map.Entry configParam : configParams.entrySet()) { - result.setConfigProperty(configParam.getKey(), configParam.getValue()); + for (Map.Entry contextParam : contextParams.entrySet()) { + result.setConfigProperty(contextParam.getKey(), contextParam.getValue()); } return result; } diff --git a/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOExecutor.java b/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOExecutor.java index e2bcc1c2a..a2250d39a 100644 --- a/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOExecutor.java +++ b/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOExecutor.java @@ -1,6 +1,7 @@ package org.palladiosimulator.simulizar.reconfiguration.qvto; import java.util.List; +import java.util.Map; import org.palladiosimulator.simulizar.reconfiguration.qvto.util.ModelTransformationCache; import org.palladiosimulator.simulizar.reconfiguration.qvto.util.QVToModelCache; @@ -26,15 +27,16 @@ public class QVTOExecutor extends AbstractQVTOExecutor { * A {@link QVToModelCache} that contains all models that can serve as a * transformation parameter. */ - public QVTOExecutor(ModelTransformationCache knownTransformations, QVToModelCache knownModels) { + public QVTOExecutor(ModelTransformationCache knownTransformations, QVToModelCache knownModels) { super(knownTransformations, knownModels); } - - public boolean executeTransformations(List transformations, IResourceTableManager resourceTableManager){ - boolean result = true; - for(QvtoModelTransformation transformation : transformations){ - result &= executeTransformation(transformation, resourceTableManager); - } - return result; - } + + public boolean executeTransformations(List transformations, + IResourceTableManager resourceTableManager, Map configParams) { + boolean result = true; + for (QvtoModelTransformation transformation : transformations) { + result &= executeTransformation(transformation, resourceTableManager, configParams); + } + return result; + } } diff --git a/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOReconfigurator.java b/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOReconfigurator.java index afddbc52c..09393345b 100644 --- a/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOReconfigurator.java +++ b/bundles/org.palladiosimulator.simulizar.reconfiguration.qvto/src/org/palladiosimulator/simulizar/reconfiguration/qvto/QVTOReconfigurator.java @@ -4,11 +4,13 @@ package org.palladiosimulator.simulizar.reconfiguration.qvto; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import javax.inject.Inject; import org.apache.log4j.Logger; -import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.palladiosimulator.simulizar.reconfiguration.AbstractReconfigurator; import org.palladiosimulator.simulizar.reconfiguration.qvto.util.ModelTransformationCache; @@ -21,9 +23,8 @@ import de.uka.ipd.sdq.scheduler.resources.active.IResourceTableManager; /** - * A reconfigurator implementation which relies on QVTo to do the - * reconfiguration. The QVTo rules both check their reconfiguration precondition - * and perform the actual reconfiguration. + * A reconfigurator implementation which relies on QVTo to do the reconfiguration. The QVTo rules + * both check their reconfiguration precondition and perform the actual reconfiguration. * * @author Matthias Becker * @@ -31,55 +32,63 @@ @RuntimeExtensionScope public class QVTOReconfigurator extends AbstractReconfigurator { - /** - * This class' internal LOGGER. - */ - private static final Logger LOGGER = Logger.getLogger(QVTOReconfigurator.class); - /** - * QVTO Interpreter used internally to interpret the SDs. - */ - private QVTOExecutor qvtoExecutor; - - /** - * QVTO Reconfigurator default constructor. - */ - @Inject - public QVTOReconfigurator(SimuLizarWorkflowConfiguration configuration, - PCMPartitionManager partitionManager) { - this.configuration = configuration; - this.pcmPartitionManager = partitionManager; + /** + * This class' internal LOGGER. + */ + private static final Logger LOGGER = Logger.getLogger(QVTOReconfigurator.class); + /** + * QVTO Interpreter used internally to interpret the SDs. + */ + private QVTOExecutor qvtoExecutor; + + /** + * QVTO Reconfigurator default constructor. + */ + @Inject + public QVTOReconfigurator(SimuLizarWorkflowConfiguration configuration, PCMPartitionManager partitionManager) { + this.configuration = configuration; + this.pcmPartitionManager = partitionManager; } - - private QVTOExecutor getQVTOExecutor() { - if (this.qvtoExecutor == null) { - this.qvtoExecutor = new QVTOExecutor(new ModelTransformationCache(), new QVToModelCache(this.pcmPartitionManager)); - } - return this.qvtoExecutor; - } - @Override - public boolean runCheck(EList> checks, EObject monitoredElement, IResourceTableManager resourceTableManager) { - return this.runExecute(checks, monitoredElement, resourceTableManager); - } + private QVTOExecutor getQVTOExecutor() { + if (this.qvtoExecutor == null) { + this.qvtoExecutor = new QVTOExecutor(new ModelTransformationCache(), + new QVToModelCache(this.pcmPartitionManager)); + } + return this.qvtoExecutor; + } - @Override - public boolean runExecute(EList> actions, EObject monitoredElement - , IResourceTableManager resourceTableManager) { - LOGGER.debug("Checking reconfiguration rules due to PRM change"); + @Override + public boolean runCheck(List> checks, EObject monitoredElement, + IResourceTableManager resourceTableManager) { + return this.runExecute(checks, monitoredElement, resourceTableManager); + } - ArrayList transformations = new ArrayList(); - for (ModelTransformation action : actions) { - try { - if (action instanceof QvtoModelTransformation) { - transformations.add((QvtoModelTransformation) action); - } - } catch (ClassCastException e) { - LOGGER.debug("Not a QVTO model transformation."); - } - } - boolean result = getQVTOExecutor().executeTransformations(transformations, resourceTableManager); - LOGGER.debug(result ? "Reconfigured system by a matching rule" - : "No reconfiguration rule was executed, all conditions were false"); - return result; - } + @Override + public boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager) { + Map configParams = Collections.emptyMap(); + return runExecute(actions, monitoredElement, resourceTableManager, configParams); + } + + @Override + public boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager, Map configParams) { + LOGGER.debug("Checking reconfiguration rules due to PRM change"); + + ArrayList transformations = new ArrayList<>(); + for (ModelTransformation action : actions) { + try { + if (action instanceof QvtoModelTransformation) { + transformations.add((QvtoModelTransformation) action); + } + } catch (ClassCastException e) { + LOGGER.debug("Not a QVTO model transformation."); + } + } + boolean result = getQVTOExecutor().executeTransformations(transformations, resourceTableManager, configParams); + LOGGER.debug(result ? "Reconfigured system by a matching rule" + : "No reconfiguration rule was executed, all conditions were false"); + return result; + } } diff --git a/bundles/org.palladiosimulator.simulizar.reconfiguration.storydiagram/src/org/palladiosimulator/simulizar/reconfiguration/storydiagram/SDReconfigurator.java b/bundles/org.palladiosimulator.simulizar.reconfiguration.storydiagram/src/org/palladiosimulator/simulizar/reconfiguration/storydiagram/SDReconfigurator.java index a68332d0d..a59060a47 100644 --- a/bundles/org.palladiosimulator.simulizar.reconfiguration.storydiagram/src/org/palladiosimulator/simulizar/reconfiguration/storydiagram/SDReconfigurator.java +++ b/bundles/org.palladiosimulator.simulizar.reconfiguration.storydiagram/src/org/palladiosimulator/simulizar/reconfiguration/storydiagram/SDReconfigurator.java @@ -1,9 +1,11 @@ package org.palladiosimulator.simulizar.reconfiguration.storydiagram; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; -import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.palladiosimulator.simulizar.reconfiguration.AbstractReconfigurator; import org.palladiosimulator.simulizar.reconfigurationrule.ModelTransformation; @@ -11,86 +13,95 @@ import de.uka.ipd.sdq.scheduler.resources.active.IResourceTableManager; /** - * A reconfigurator implementation which relies on story diagrams to do the - * reconfiguration. The story diagrams both check their reconfiguration - * precondition and perform the actual reconfiguration. + * A reconfigurator implementation which relies on story diagrams to do the reconfiguration. The + * story diagrams both check their reconfiguration precondition and perform the actual + * reconfiguration. * * @author snowball * */ public class SDReconfigurator extends AbstractReconfigurator { - /** - * This class' internal LOGGER. - */ - private static final Logger LOGGER = Logger.getLogger(SDReconfigurator.class); + /** + * This class' internal LOGGER. + */ + private static final Logger LOGGER = Logger.getLogger(SDReconfigurator.class); - /** - * SD Interpreter used internally to interpret the SDs. - */ - private SDExecutor sdExecutor; + /** + * SD Interpreter used internally to interpret the SDs. + */ + private SDExecutor sdExecutor; - /** - * Story diagram reconfigurator default constructor. - */ - public SDReconfigurator() { - super(); - } + /** + * Story diagram reconfigurator default constructor. + */ + public SDReconfigurator() { + super(); + } - @Override - public boolean runCheck(EList> checks, - final EObject monitoredElement, IResourceTableManager resourceTableManager) { + @Override + public boolean runCheck(List> checks, + final EObject monitoredElement, IResourceTableManager resourceTableManager) { - ArrayList transformations = new ArrayList(); - for (ModelTransformation check : checks) { - try { - if (check instanceof SDModelTransformation) { - SDModelTransformation sdModelTransformation = (SDModelTransformation) check; - transformations.add(sdModelTransformation); - } - } catch (ClassCastException e) { - LOGGER.debug("Not a Storydiagram model transformation."); - } - } + ArrayList transformations = new ArrayList<>(); + for (ModelTransformation check : checks) { + try { + if (check instanceof SDModelTransformation) { + SDModelTransformation sdModelTransformation = (SDModelTransformation) check; + transformations.add(sdModelTransformation); + } + } catch (ClassCastException e) { + LOGGER.debug("Not a Storydiagram model transformation."); + } + } - return executeTransformations(monitoredElement, transformations); - } + return executeTransformations(monitoredElement, transformations); + } - @Override - public boolean runExecute(EList> actions, - EObject monitoredElement, IResourceTableManager resourceTableManager) { - ArrayList activities = new ArrayList(); - LOGGER.info("Executing Story Diagram Model Transformation."); - for (ModelTransformation action : actions) { - try { - if (action instanceof SDModelTransformation) { - SDModelTransformation sdModelTransformation = (SDModelTransformation) action; - activities.add(sdModelTransformation); - } - } catch (ClassCastException e) { - LOGGER.info("Not a Storydiagram model transformation."); - } - } + @Override + public boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager) { + Map configParams = Collections.emptyMap(); + return runExecute(actions, monitoredElement, resourceTableManager, configParams); + } - return executeTransformations(monitoredElement, activities); - } - - private boolean executeTransformations(final EObject monitoredElement, ArrayList transformations) { - if (!transformations.isEmpty()) { - LOGGER.info("Checking reconfiguration rules due to RuntimeMeasurement change"); - final boolean result = this.getSDExecutor().executeTransformations(transformations, monitoredElement); - LOGGER.info(result ? "Reconfigured system by a matching rule" - : "No reconfiguration rule was executed, all conditions were false"); - return result; - } else { - return false; - } - } + @Override + public boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager, Map configParams) { + ArrayList activities = new ArrayList<>(); + LOGGER.info("Executing Story Diagram Model Transformation."); + for (ModelTransformation action : actions) { + try { + if (action instanceof SDModelTransformation) { + SDModelTransformation sdModelTransformation = (SDModelTransformation) action; + activities.add(sdModelTransformation); + } + } catch (ClassCastException e) { + LOGGER.info("Not a Storydiagram model transformation."); + } + } - private SDExecutor getSDExecutor() { - if (this.sdExecutor == null) { - this.sdExecutor = new SDExecutor(this.pcmPartitionManager); - } - return this.sdExecutor; - } + return executeTransformations(monitoredElement, activities); + } + + private boolean executeTransformations(final EObject monitoredElement, + ArrayList transformations) { + if (!transformations.isEmpty()) { + LOGGER.info("Checking reconfiguration rules due to RuntimeMeasurement change"); + final boolean result = this.getSDExecutor() + .executeTransformations(transformations, monitoredElement); + LOGGER.info(result ? "Reconfigured system by a matching rule" + : "No reconfiguration rule was executed, all conditions were false"); + return result; + } else { + return false; + } + } + + private SDExecutor getSDExecutor() { + if (this.sdExecutor == null) { + this.sdExecutor = new SDExecutor(this.pcmPartitionManager); + } + return this.sdExecutor; + } } diff --git a/bundles/org.palladiosimulator.simulizar/src/org/palladiosimulator/simulizar/reconfiguration/IReconfigurationEngine.java b/bundles/org.palladiosimulator.simulizar/src/org/palladiosimulator/simulizar/reconfiguration/IReconfigurationEngine.java index e7892bdc9..823e379a4 100644 --- a/bundles/org.palladiosimulator.simulizar/src/org/palladiosimulator/simulizar/reconfiguration/IReconfigurationEngine.java +++ b/bundles/org.palladiosimulator.simulizar/src/org/palladiosimulator/simulizar/reconfiguration/IReconfigurationEngine.java @@ -1,8 +1,10 @@ package org.palladiosimulator.simulizar.reconfiguration; +import java.util.List; +import java.util.Map; + import javax.inject.Inject; -import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.palladiosimulator.simulizar.di.extension.Extension; import org.palladiosimulator.simulizar.reconfigurationrule.ModelTransformation; @@ -19,46 +21,51 @@ */ public interface IReconfigurationEngine extends Extension { - public static int RECONFIGURATION_CHECK_SUCCEEDED = 0; - public static int RECONFIGURATION_CHECK_FAILED = 1; - public static int RECONFIGURATION_CHECK_NOT_APPLICABLE_BY_ENGINE = 2; - public static int RECONFIGURATION_EXECUTION_SUCCEEDED = 3; - public static int RECONFIGURATION_EXECUTION_FAILED = 4; - public static int RECONFIGURATION_EXECUTION_NOT_APPLICABLE_BY_ENGINE = 5; + public static int RECONFIGURATION_CHECK_SUCCEEDED = 0; + public static int RECONFIGURATION_CHECK_FAILED = 1; + public static int RECONFIGURATION_CHECK_NOT_APPLICABLE_BY_ENGINE = 2; + public static int RECONFIGURATION_EXECUTION_SUCCEEDED = 3; + public static int RECONFIGURATION_EXECUTION_FAILED = 4; + public static int RECONFIGURATION_EXECUTION_NOT_APPLICABLE_BY_ENGINE = 5; + + /** + * Trigger a condition check of the model@runtime. Engines should check whether they should + * reconfigure. + * + * @param + * + * @param monitoredElement + * PCM model element for which a new sensor measurement arrived. + * @return true if the check was positive/matched, false if it was + * negative/did not match + */ + boolean runCheck(List> checks, EObject monitoredElement, + IResourceTableManager resourceTableManager); + + /** + * Trigger a reconfiguration of the model@runtime. This method should only be called if the + * prior check was positive, i.e., engines should only do the reconfiguration if the prior check + * was positive. + * + * @param monitoredElement + * PCM model element for which a new sensor measurement arrived. + * @return true if the reconfiguration was executed, false if it was + * not executed or did not succeed. + */ + boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager); + + boolean runExecute(List> actions, EObject monitoredElement, + IResourceTableManager resourceTableManager, Map configParams); - /** - * Trigger a condition check of the model@runtime. Engines should check - * whether they should reconfigure. - * - * @param - * - * @param monitoredElement - * PCM model element for which a new sensor measurement arrived. - * @return true if the check was positive/matched, - * false if it was negative/did not match - */ - public boolean runCheck(EList> checks, EObject monitoredElement, IResourceTableManager resourceTableManager); + @Inject + default void setConfiguration(final SimuLizarWorkflowConfiguration configuration) { + // This needs to be an empty default implementations for dagger to recognize it properly + } - /** - * Trigger a reconfiguration of the model@runtime. This method should only - * be called if the prior check was positive, i.e., engines should only do - * the reconfiguration if the prior check was positive. - * - * @param monitoredElement - * PCM model element for which a new sensor measurement arrived. - * @return true if the reconfiguration was executed, - * false if it was not executed or did not succeed. - */ - public boolean runExecute(EList> actions, EObject monitoredElement, IResourceTableManager resourceTableManager); - - @Inject - default void setConfiguration(final SimuLizarWorkflowConfiguration configuration) { - // This needs to be an empty default implementations for dagger to recognize it properly - } - - @Inject - default void setPCMPartitionManager(final PCMPartitionManager pcmPartitionManager) { - // This needs to be an empty default implementations for dagger to recognize it properly - } + @Inject + default void setPCMPartitionManager(final PCMPartitionManager pcmPartitionManager) { + // This needs to be an empty default implementations for dagger to recognize it properly + } }