blob: 57e79c3fb6d509fcd6c4d8b0f856782300dea987 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014-2016 Akos Horvath, Abel Hegedus, Zoltan Ujhelyi, Peter Lunk, Istvan David, IncQuery Labs Ltd.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-v20.html.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra
import com.google.common.base.Stopwatch
import java.util.concurrent.TimeUnit
import org.apache.log4j.Logger
import org.eclipse.viatra.examples.cps.traceability.CPSToDeployment
import org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra.patterns.CpsXformM2M
import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine
import org.eclipse.viatra.transformation.evm.api.Scheduler.ISchedulerFactory
import org.eclipse.viatra.transformation.runtime.emf.transformation.eventdriven.EventDrivenTransformation
import static org.eclipse.viatra.query.runtime.matchers.util.Preconditions.*
import org.eclipse.viatra.transformation.debug.configuration.TransformationDebuggerConfiguration
import org.eclipse.viatra.transformation.evm.specific.resolver.InvertedDisappearancePriorityConflictResolver
import org.eclipse.viatra.transformation.runtime.emf.modelmanipulation.IModelManipulations
import org.eclipse.viatra.examples.cps.deployment.DeploymentPackage
import org.eclipse.viatra.examples.cps.traceability.TraceabilityPackage
import org.eclipse.viatra.transformation.runtime.emf.rules.eventdriven.EventDrivenTransformationRuleFactory
import org.eclipse.viatra.transformation.evm.specific.crud.CRUDActivationStateEnum
import org.eclipse.viatra.examples.cps.deployment.BehaviorTransition
import org.eclipse.viatra.examples.cps.deployment.DeploymentApplication
import org.eclipse.viatra.transformation.evm.specific.Lifecycles
import org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra.patterns.TriggerPair
import org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra.patterns.Transition
import org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra.patterns.State
import org.eclipse.viatra.examples.cps.deployment.DeploymentBehavior
import org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra.patterns.StateMachine
import org.eclipse.viatra.examples.cps.deployment.DeploymentHost
import org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra.patterns.ApplicationInstance
import org.eclipse.viatra.examples.cps.xform.m2m.incr.viatra.patterns.HostInstance
import org.eclipse.viatra.examples.cps.deployment.BehaviorState
import org.eclipse.viatra.transformation.runtime.emf.modelmanipulation.SimpleModelManipulations
class CPS2DeploymentTransformationViatra {
extension Logger logger = Logger.getLogger("cps.xform.m2m.incr.viatra")
extension CpsXformM2M cpsXformM2M = CpsXformM2M.instance
extension IModelManipulations manipulation
extension DeploymentPackage depPackage = DeploymentPackage::eINSTANCE
extension TraceabilityPackage trPackage = TraceabilityPackage::eINSTANCE
extension EventDrivenTransformationRuleFactory ruleFactory = new EventDrivenTransformationRuleFactory
CPSToDeployment cps2dep
ViatraQueryEngine engine
EventDrivenTransformation transform
ISchedulerFactory factory;
var initialized = false;
def initialize(CPSToDeployment cps2dep, ViatraQueryEngine engine) {
initialize(cps2dep, engine, false, null)
}
def initialize(CPSToDeployment cps2dep, ViatraQueryEngine engine, boolean isDebuggable, String debugName) {
checkArgument(cps2dep !== null, "Mapping cannot be null!")
checkArgument(cps2dep.cps !== null, "CPS not defined in mapping!")
checkArgument(cps2dep.deployment !== null, "Deployment not defined in mapping!")
checkArgument(engine !== null, "Engine cannot be null!")
if (!initialized) {
this.cps2dep = cps2dep
this.engine = engine
debug("Preparing queries on engine.")
var watch = Stopwatch.createStarted
prepare(engine)
manipulation = new SimpleModelManipulations(engine)
info('''Prepared queries on engine («watch.elapsed(TimeUnit.MILLISECONDS)» ms)''')
info("Preparing transformation rules.")
watch = Stopwatch.createStarted
createTransformation(isDebuggable, debugName)
info('''Prepared transformation rules («watch.elapsed(TimeUnit.MILLISECONDS)» ms)''')
initialized = true
}
}
def execute() {
debug('''Executing transformation on: Cyber-physical system: «cps2dep.cps.identifier»''')
if(factory === null){
transform.executionSchema.startUnscheduledExecution
}
}
def setScheduler(ISchedulerFactory factory){
this.factory = factory
}
private def createTransformation(boolean isDebuggable, String debugName) {
val fixedPriorityResolver = new InvertedDisappearancePriorityConflictResolver
fixedPriorityResolver.setPriority(hostRule.ruleSpecification, 1)
fixedPriorityResolver.setPriority(applicationRule.ruleSpecification, 2)
fixedPriorityResolver.setPriority(stateMachineRule.ruleSpecification, 3)
fixedPriorityResolver.setPriority(stateRule.ruleSpecification, 4)
fixedPriorityResolver.setPriority(transitionRule.ruleSpecification, 5)
fixedPriorityResolver.setPriority(triggerRule.ruleSpecification, 6)
val builder = EventDrivenTransformation.forEngine(engine)
.setConflictResolver(fixedPriorityResolver)
.addRule(hostRule)
.addRule(applicationRule)
.addRule(stateMachineRule)
.addRule(stateRule)
.addRule(transitionRule)
.addRule(triggerRule)
if (factory !== null) {
builder.schedulerFactory = factory
}
if (isDebuggable) {
val debuggerConfig = new TransformationDebuggerConfiguration(debugName ?:
"CPS2DeploymentTransformationViatra")
builder.addAdapterConfiguration(debuggerConfig)
}
transform = builder.build
}
def dispose() {
if (transform !== null) {
transform.executionSchema.dispose
}
transform = null
return
}
val hostRule = createRule(HostInstance.instance).name("HostRule").action(
CRUDActivationStateEnum.CREATED) [
debug('''Mapping host with IP: «hostInstance.nodeIp»''')
val deploymentHost = cps2dep.deployment.createChild(deployment_Hosts, deploymentHost)
deploymentHost.set(deploymentHost_Ip, hostInstance.nodeIp)
val hostTrace = cps2dep.createChild(CPSToDeployment_Traces, CPS2DeploymentTrace)
hostTrace.addTo(CPS2DeploymentTrace_CpsElements, hostInstance)
hostTrace.addTo(CPS2DeploymentTrace_DeploymentElements, deploymentHost)
].action(CRUDActivationStateEnum.UPDATED) [
// Optional.get should be always work here
val depHost = engine.cps2depTrace.getOneArbitraryMatch(cps2dep, null, hostInstance, null).get.depElement as DeploymentHost
debug('''Updating mapped host with IP: «depHost.ip»''')
depHost.set(deploymentHost_Ip, hostInstance.nodeIp)
debug('''Updated mapped host with IP: «depHost.ip»''')
].action(CRUDActivationStateEnum.DELETED) [
engine.cps2depTrace.getOneArbitraryMatch(cps2dep, null, hostInstance, null).ifPresent[traceMatch |
logger.debug('''Removing host with IP: «hostInstance.nodeIp»''')
cps2dep.deployment.remove(deployment_Hosts, traceMatch.depElement)
cps2dep.remove(CPSToDeployment_Traces, traceMatch.trace)
logger.debug('''Removed host with IP: «hostInstance.nodeIp»''')
]
].addLifeCycle(Lifecycles.getDefault(true, true))
.build
val applicationRule = createRule(ApplicationInstance.instance).name("ApplicationRule").action(
CRUDActivationStateEnum.CREATED) [
val depHost = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance.allocatedTo).
filter(DeploymentHost).head
debug('''Mapping application with ID: «appInstance.identifier»''')
val deploymentApplication = depHost.createChild(deploymentHost_Applications, deploymentApplication)
deploymentApplication.set(deploymentApplication_Id, appInstance.identifier)
val hostTrace = cps2dep.createChild(CPSToDeployment_Traces, CPS2DeploymentTrace)
hostTrace.addTo(CPS2DeploymentTrace_CpsElements, appInstance)
hostTrace.addTo(CPS2DeploymentTrace_DeploymentElements, deploymentApplication)
debug('''Mapped application with ID: «appInstance.identifier»''')
].action(CRUDActivationStateEnum.UPDATED) [
val depApp = engine.cps2depTrace.getOneArbitraryMatch(cps2dep, null, appInstance, null).get.depElement as DeploymentApplication
if (depApp.id != appInstance.identifier)
depApp.set(deploymentApplication_Id, appInstance.identifier)
].action(CRUDActivationStateEnum.DELETED) [
val trace = engine.cps2depTrace.getAllValuesOftrace(null, appInstance, null).head
val depApp = trace.deploymentElements.head as DeploymentApplication
engine.allocatedDeploymentApplication.getAllValuesOfdepHost(depApp).head.remove(deploymentHost_Applications, depApp)
cps2dep.remove(CPSToDeployment_Traces, trace)
].addLifeCycle(Lifecycles.getDefault(true, true))
.build
val stateMachineRule = createRule(StateMachine.instance).name("StateMachineRule").action(
CRUDActivationStateEnum.CREATED) [
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).filter(
DeploymentApplication).head
debug('''Mapping state machine with ID: «stateMachine.identifier»''')
val behavior = depApp.createChild(deploymentApplication_Behavior, deploymentBehavior) as DeploymentBehavior
behavior.set(deploymentElement_Description, stateMachine.identifier)
depApp.set(deploymentApplication_Behavior, behavior)
val traces = engine.cps2depTrace.getAllValuesOftrace(null, stateMachine, null)
if (traces.empty) {
trace('''Creating new trace for state machine''')
val trace = cps2dep.createChild(CPSToDeployment_Traces, CPS2DeploymentTrace)
trace.addTo(CPS2DeploymentTrace_CpsElements, stateMachine)
trace.addTo(CPS2DeploymentTrace_DeploymentElements, behavior)
} else {
trace('''Adding new behavior to existing trace''')
traces.head.addTo(CPS2DeploymentTrace_DeploymentElements, behavior)
}
debug('''Mapped state machine with ID: «stateMachine.identifier»''')
].action(CRUDActivationStateEnum.UPDATED) [
val smId = stateMachine.identifier
debug('''Updating mapped state machine with ID: «smId»''')
val depSMs = engine.cps2depTrace.getAllValuesOfdepElement(null, null, stateMachine).filter(
DeploymentBehavior)
depSMs.forEach [
if (description != smId) {
trace('''ID changed to «smId»''')
set(deploymentElement_Description, smId)
}
]
debug('''Updated mapped state machine with ID: «smId»''')
].action(CRUDActivationStateEnum.DELETED) [
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).head as DeploymentApplication;
val depBehavior = depApp.behavior
val smId = depBehavior.description
logger.debug('''Removing state machine with ID: «smId»''')
depApp.set(deploymentApplication_Behavior, null)
val smTrace = engine.cps2depTrace.getAllValuesOftrace(null, stateMachine, null).head
smTrace.remove(CPS2DeploymentTrace_DeploymentElements, depBehavior)
if (smTrace.deploymentElements.empty) {
trace('''Removing empty trace''')
cps2dep.remove(CPSToDeployment_Traces, smTrace)
}
logger.debug('''Removed state machine with ID: «smId»''')
].addLifeCycle(Lifecycles.getDefault(true, true))
.build
val stateRule = createRule(State.instance).name("StateRule").action(
CRUDActivationStateEnum.CREATED) [
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).head as DeploymentApplication
debug('''Mapping state with ID: «state.identifier»''')
val depState = depApp.behavior.createChild(deploymentBehavior_States, behaviorState)
depState.set(deploymentElement_Description, state.identifier)
if (stateMachine.initial == state) {
depApp.behavior.set(deploymentBehavior_Current, depState)
}
val traces = engine.cps2depTrace.getAllValuesOftrace(null, state, null)
if (traces.empty) {
trace('''Creating new trace for state ''')
val trace = cps2dep.createChild(CPSToDeployment_Traces, CPS2DeploymentTrace)
trace.addTo(CPS2DeploymentTrace_CpsElements, state)
trace.addTo(CPS2DeploymentTrace_DeploymentElements, depState)
} else {
trace('''Adding new state to existing trace''')
traces.head.addTo(CPS2DeploymentTrace_DeploymentElements, depState)
}
debug('''Mapped state with ID: «state.identifier»''')
].action(CRUDActivationStateEnum.UPDATED) [
debug('''Updating mapped state with ID: «state.identifier»''')
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).filter(
DeploymentApplication).head
val depState = engine.cps2depTrace.getAllValuesOfdepElement(null, null, state).filter(BehaviorState).
findFirst[depApp.behavior.states.contains(it)]
val depBehavior = depApp.behavior
if (depState.description != state.identifier) {
trace('''ID changed to «state.identifier»''')
depState.set(deploymentElement_Description, state.identifier)
}
if (state == stateMachine.initial) {
if (depBehavior.current != depState) {
trace('''Current state changed to «state.identifier»''')
depBehavior.set(deploymentBehavior_Current, depState)
}
}
debug('''Updated mapped state with ID: «state.identifier»''')
].action(CRUDActivationStateEnum.DELETED) [
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).head as DeploymentApplication
val depBehavior = depApp.behavior
val depState = engine.cps2depTrace.getAllValuesOfdepElement(null, null, state).filter(BehaviorState).
findFirst[depApp.behavior.states.contains(it)];
val stateId = depState.description
logger.debug('''Removing state with ID: «stateId»''')
if (depBehavior !== null) {
depBehavior.remove(deploymentBehavior_States, depState)
if (depBehavior.current == depState) {
depBehavior.set(deploymentBehavior_Current, null)
}
}
val smTrace = engine.cps2depTrace.getAllValuesOftrace(null, state, null).head
smTrace.remove(CPS2DeploymentTrace_DeploymentElements, depState)
if (smTrace.deploymentElements.empty) {
trace('''Removing empty trace''')
cps2dep.remove(CPSToDeployment_Traces, smTrace)
}
logger.debug('''Removed state with ID: «stateId»''')
].addLifeCycle(Lifecycles.getDefault(true, true))
.build
val transitionRule = createRule(Transition.instance).name("TransitionRule").action(
CRUDActivationStateEnum.CREATED) [
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).filter(
DeploymentApplication).head
val transition = transition
val transitionId = transition.identifier
debug('''Mapping transition with ID: «transitionId»''')
val depTransition = depApp.behavior.createChild(deploymentBehavior_Transitions, behaviorTransition)
depTransition.set(deploymentElement_Description, transitionId)
val tempDepSources = engine.cps2depTrace.getAllValuesOfdepElement(null, null, srcState);
val depSource = depApp.behavior.states.findFirst[tempDepSources.contains(it)]
depSource.addTo(behaviorState_Outgoing, depTransition)
val tempDepTargets = engine.cps2depTrace.getAllValuesOfdepElement(null, null, transition.targetState);
val depTarget = depApp.behavior.states.findFirst[tempDepTargets.contains(it)]
depTransition.set(behaviorTransition_To, depTarget)
val traces = engine.cps2depTrace.getAllValuesOftrace(null, transition, null)
if (traces.empty) {
trace('''Creating new trace for transition ''')
val trace = cps2dep.createChild(CPSToDeployment_Traces, CPS2DeploymentTrace)
trace.addTo(CPS2DeploymentTrace_CpsElements, transition)
trace.addTo(CPS2DeploymentTrace_DeploymentElements, depTransition)
} else {
trace('''Adding new transition to existing trace''')
traces.head.addTo(CPS2DeploymentTrace_DeploymentElements, depTransition)
}
debug('''Mapped transition with ID: «transitionId»''')
].action(CRUDActivationStateEnum.UPDATED) [
val transition = transition
val trId = transition.identifier
debug('''Updating mapped transition with ID: «trId»''')
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).filter(
DeploymentApplication).head
val depTransitions = engine.cps2depTrace.getAllValuesOfdepElement(null, null, transition).filter(
BehaviorTransition).toSet
val depTransition = depApp.behavior.transitions.findFirst[depTransitions.contains(it)]
val oldDesc = depTransition.description
if (oldDesc != trId) {
trace('''ID changed to «oldDesc»''')
depTransition.set(deploymentElement_Description, trId)
}
val tempDepSources = engine.cps2depTrace.getAllValuesOfdepElement(null, null, srcState)
val depSource = depApp.behavior.states.findFirst[tempDepSources.contains(it)]
val tempDepTargets = engine.cps2depTrace.getAllValuesOfdepElement(null, null, transition.targetState);
val depTarget = depApp.behavior.states.findFirst[tempDepTargets.contains(it)]
if (!depSource.outgoing.contains(depTransition)) {
trace('''Source state changed to «depSource.description»''')
depSource.addTo(behaviorState_Outgoing, depTransition)
}
if (depTransition.to != depTarget) {
trace('''Target state changed to «depTarget.description»''')
depTransition.set(behaviorTransition_To, depTarget)
}
debug('''Updated mapped transition with ID: «trId»''')
].action(CRUDActivationStateEnum.DELETED) [
val transition = transition
val depApp = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstance).filter(
DeploymentApplication).head
val depTransitions = engine.cps2depTrace.getAllValuesOfdepElement(null, null, transition).filter(
BehaviorTransition).toSet
val depTransition = engine.depBehaviorsStateAndTransitions.
getAllValuesOfdepTransition(depApp.behavior, null).findFirst[depTransitions.contains(it)]
val trId = depTransition.description
logger.debug('''Removing transition with ID: «trId»''')
depTransition.set(behaviorTransition_To, null)
val tempDepSources = engine.cps2depTrace.getAllValuesOfdepElement(null, null, srcState)
val depSource = depApp.behavior.states.findFirst[tempDepSources.contains(it)]
depSource?.remove(behaviorState_Outgoing, depTransition)
depApp.behavior.remove(deploymentBehavior_Transitions, depTransition)
val smTrace = engine.cps2depTrace.getAllValuesOftrace(null, transition, null).head
smTrace.remove(CPS2DeploymentTrace_DeploymentElements, depTransition)
if (smTrace.deploymentElements.empty) {
trace('''Removing empty trace''')
cps2dep.remove(CPSToDeployment_Traces, smTrace)
}
logger.debug('''Removed transition with ID: «trId»''')
].addLifeCycle(Lifecycles.getDefault(true, true))
.build
val triggerRule = createRule(TriggerPair.instance).name("TriggerRule").action(
CRUDActivationStateEnum.CREATED) [
val depAppTrigger = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstanceTrigger).
filter(DeploymentApplication).head
val depAppTarget = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstanceTarget).
filter(DeploymentApplication).head
val sendTr = engine.cps2depTrace.getAllValuesOfdepElement(null, null, cpsTrigger).filter(
BehaviorTransition).findFirst[depAppTrigger.behavior.transitions.contains(it)]
val waitTr = engine.cps2depTrace.getAllValuesOfdepElement(null, null, cpsTarget).filter(
BehaviorTransition).findFirst[depAppTarget.behavior.transitions.contains(it)]
debug('''Mapping trigger between «sendTr.description» and «waitTr.description»''')
if (!sendTr.trigger.contains(waitTr)) {
trace('''Adding new trigger''')
sendTr.addTo(behaviorTransition_Trigger, waitTr)
}
debug('''Mapped trigger between «sendTr.description» and «waitTr.description»''')
].action(CRUDActivationStateEnum.DELETED) [
val depAppTrigger = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstanceTrigger).
filter(DeploymentApplication).head
val depAppTarget = engine.cps2depTrace.getAllValuesOfdepElement(null, null, appInstanceTarget).
filter(DeploymentApplication).head
val sendTr = engine.cps2depTrace.getAllValuesOfdepElement(null, null, cpsTrigger).filter(
BehaviorTransition).findFirst[depAppTrigger.behavior.transitions.contains(it)]
val waitTr = engine.cps2depTrace.getAllValuesOfdepElement(null, null, cpsTarget).filter(
BehaviorTransition).findFirst[depAppTarget.behavior.transitions.contains(it)]
debug('''Removing trigger between «sendTr.description» and «waitTr.description»''')
if (sendTr.trigger.contains(waitTr)) {
trace('''Removing existing trigger''')
sendTr.remove(behaviorTransition_Trigger, waitTr)
}
debug('''Removed trigger between «sendTr.description» and «waitTr.description»''')
].addLifeCycle(Lifecycles.getDefault(true, true))
.build
}