blob: fa08de2680a20c5aa1871b45da68ba2930cb58ff [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017, 2021 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Ansgar Radermacher - Initial API and implementation
* Shuai Li (CEA LIST) <shuai.li@cea.fr> - Bug 530251
* Ported from C++ code - Bug 568883
*
*******************************************************************************/
package org.eclipse.papyrus.designer.transformation.languages.java.library.statemachine
import java.util.ArrayList
import java.util.HashMap
import java.util.LinkedHashMap
import java.util.List
import java.util.Map
import java.util.concurrent.Semaphore
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.papyrus.designer.languages.common.base.ElementUtils
import org.eclipse.papyrus.designer.languages.common.base.StdUriConstants
import org.eclipse.papyrus.designer.languages.common.profile.Codegen.NoCodeGen
import org.eclipse.papyrus.designer.languages.java.library.JavaLibUriConstants
import org.eclipse.papyrus.designer.languages.java.profile.JavaProfileResource
import org.eclipse.papyrus.designer.languages.java.profile.PapyrusJava.Import
import org.eclipse.papyrus.designer.transformation.core.transformations.LazyCopier
import org.eclipse.papyrus.designer.transformation.core.transformations.TransformationContext
import org.eclipse.papyrus.designer.transformation.profile.Transformation.DerivedElement
import org.eclipse.papyrus.designer.transformation.vsl.ParseVSL
import org.eclipse.papyrus.uml.tools.utils.PackageUtil
import org.eclipse.uml2.uml.AnyReceiveEvent
import org.eclipse.uml2.uml.Behavior
import org.eclipse.uml2.uml.CallEvent
import org.eclipse.uml2.uml.ChangeEvent
import org.eclipse.uml2.uml.Class
import org.eclipse.uml2.uml.Enumeration
import org.eclipse.uml2.uml.Event
import org.eclipse.uml2.uml.FinalState
import org.eclipse.uml2.uml.Interface
import org.eclipse.uml2.uml.LiteralInteger
import org.eclipse.uml2.uml.OpaqueBehavior
import org.eclipse.uml2.uml.OpaqueExpression
import org.eclipse.uml2.uml.Operation
import org.eclipse.uml2.uml.Package
import org.eclipse.uml2.uml.ParameterDirectionKind
import org.eclipse.uml2.uml.Profile
import org.eclipse.uml2.uml.Property
import org.eclipse.uml2.uml.Pseudostate
import org.eclipse.uml2.uml.PseudostateKind
import org.eclipse.uml2.uml.Region
import org.eclipse.uml2.uml.SignalEvent
import org.eclipse.uml2.uml.State
import org.eclipse.uml2.uml.StateMachine
import org.eclipse.uml2.uml.TimeEvent
import org.eclipse.uml2.uml.Transition
import org.eclipse.uml2.uml.Trigger
import org.eclipse.uml2.uml.Type
import org.eclipse.uml2.uml.UMLPackage
import org.eclipse.uml2.uml.Vertex
import org.eclipse.uml2.uml.profile.standard.Create
import org.eclipse.uml2.uml.util.UMLUtil
import static org.eclipse.papyrus.designer.transformation.library.statemachine.SMCodeGeneratorConstants.*
import static extension org.eclipse.papyrus.designer.transformation.library.statemachine.TransformationUtil.*
import static extension org.eclipse.papyrus.designer.transformation.library.statemachine.SMCommon.*
import static extension org.eclipse.papyrus.designer.transformation.library.xtend.BehaviorUtil.*
import static extension org.eclipse.papyrus.uml.tools.utils.StereotypeUtil.*
import static org.eclipse.papyrus.designer.transformation.languages.java.library.statemachine.SMJavaCodeGeneratorConstants.*
import org.eclipse.papyrus.designer.transformation.library.statemachine.TransformationUtil
import org.eclipse.papyrus.designer.languages.java.profile.PapyrusJava.External
import org.eclipse.uml2.uml.NamedElement
import org.eclipse.papyrus.designer.languages.common.base.StringConstants
/**
* Java variant of main SM transformation
*/
class SM2ClassesTransformationCore {
protected extension CDefinitions cdefs;
public int MAX_NUMBER_ORTHOGONAL_REGIONS = 1
StateMachine sm
public Type boolType
public Type threadFuncEnum;
Type state_t;
public Class superContext
List<Transition> transitions = new ArrayList
List<OpaqueBehavior> actions = new ArrayList
public Region topRegion
public List<State> states = new ArrayList
List<Vertex> vertexes = new ArrayList
public LazyCopier copier
String langID = "JAVA"
public Semaphore sema = new Semaphore(1);
public boolean generateActionLog = false
boolean createDoActivity = true
public Type voidType
Enumeration stateIdEnum
public Type intType
public Type charType
public Type stringType
Enumeration eventIdEnum
public Type sockAddrInType;
public static Package umlPrimitiveLibrary
public static Package javaLibrary
public List<TimeEvent> timeEvents = new ArrayList
public List<ChangeEvent> changeEvents = new ArrayList
public List<CallEvent> callEvents = new ArrayList
List<SignalEvent> signalEvents = new ArrayList
List<AnyReceiveEvent> anyEvents = new ArrayList
List<Pseudostate> junctions = new ArrayList
public ConcurrencyGenerator concurrency
public EventTransformation eventTransform
public PseudostateGenerator pseudostateGenerator
public MonitoringTransformation monitoringTransformation;
public List<Behavior> doActivityList = new ArrayList
public Package smPack
List<Region> regions = new ArrayList
public List<Transition> parallelTransitions = new ArrayList
public Map<State, List<TimeEvent>> states2TimeEvents = new HashMap
Type threadStructType
Type event_t
new(LazyCopier copier, StateMachine sm, Class tmClass) {
this.copier = copier
this.superContext = tmClass
// perClassPackage = copier.target.createNestedPackage("PerClass_" + mContainerClass.name)
// perClassPackage = copier.target
this.sm = sm
val ResourceSet resourceSet = targetPacket.eResource.resourceSet
this.cdefs = new CDefinitions(superContext)
umlPrimitiveLibrary = ElementUtils.loadPackage(StdUriConstants.UML_PRIM_TYPES_URI, resourceSet)
javaLibrary = ElementUtils.loadPackage(JavaLibUriConstants.LIBRARY_PATH_URI, resourceSet)
boolType = umlPrimitiveLibrary.getOwnedType("Boolean")
voidType = umlPrimitiveLibrary.getOwnedType("Object")
intType = umlPrimitiveLibrary.getOwnedType("Integer")
stringType = umlPrimitiveLibrary.getOwnedType("String")
charType = javaLibrary.getOwnedType("char")
}
def setSmPack(Package smPack) {
this.smPack = smPack
}
def getThreadStructType() {
return threadStructType
}
def setThreadStructType(Type threadStructType) {
this.threadStructType = threadStructType;
}
def setState_t(Type state_t) {
this.state_t = state_t;
}
def setEvent_t(Type event_t) {
this.event_t = event_t;
}
def getRoot() {
TransformationContext.current.copier.source
}
def getTargetPacket() {
copier.target;
}
def getExternalPackage(Package parentPack) {
if (parentPack.getNestedPackage("external") === null) {
var createdPack = parentPack.createNestedPackage("external")
createdPack.apply(NoCodeGen)
}
return parentPack.getNestedPackage("external")
}
def createIntConstant(String name, int defaultValue) {
val constant = superContext.createOwnedAttribute(name, intType)
constant.isStatic = true
constant.isLeaf = true
val defaultValueUML = constant.createDefaultValue(null, null,
UMLPackage.eINSTANCE.literalInteger) as LiteralInteger
defaultValueUML.value = defaultValue;
}
// each state class has a super context and ancestor context
def transform() {
val targetPack = getTargetPacket;
// copier = new SM2ClassCopier(mContainerClass.model, targetPack, false, true, mContainerClass, superContext, sm)
val ResourceSet resourceSet = targetPack.eResource.resourceSet
// PackageUtil.loadPackage(CppUriConstants.ANSIC_LIB, resourceSet)
val Package profile = ElementUtils.loadPackage(StdUriConstants.UML_STD_PROFILE_URI, resourceSet)
if (profile instanceof Profile) {
PackageUtil.applyProfile(targetPack, profile as Profile, true)
}
val Package javaProfile = PackageUtil.loadPackage(JavaProfileResource.PROFILE_PATH_URI, resourceSet)
if (javaProfile instanceof Profile) {
PackageUtil.applyProfile(targetPack, javaProfile as Profile, true)
}
topRegion = sm.regions.head
concurrency = new ConcurrencyGenerator(this)
eventTransform = new EventTransformation(this)
pseudostateGenerator = new PseudostateGenerator(this)
monitoringTransformation = new MonitoringTransformation(this);
var eventMap = topRegion.allEvents
eventMap.forEach [ e, k |
if (e instanceof TimeEvent) {
timeEvents.add(e)
} else if (e instanceof CallEvent) {
callEvents.add(e)
} else if (e instanceof SignalEvent) {
signalEvents.add(e)
} else if (e instanceof ChangeEvent) {
changeEvents.add(e)
} else if (e instanceof AnyReceiveEvent) {
anyEvents.add(e)
}
]
// create state-id enumg
eventIdEnum = superContext.createNestedClassifier(EVENT_ID, UMLPackage.Literals.ENUMERATION) as Enumeration
// don't use class enumerations (rely on conversion to int)
createIntConstant(TIME_EVENT_LOWER_BOUND, 0);
timeEvents.forEach [
eventIdEnum.createOwnedLiteral(it.eventID)
]
changeEvents.forEach [
eventIdEnum.createOwnedLiteral(it.eventID)
]
createIntConstant(CHANGE_EVENT_LOWER_BOUND, timeEvents.size)
var teIndex = superContext.createOwnedOperation(TE_INDEX, null, null)
teIndex.isStatic = true
teIndex.isLeaf = true
teIndex.createOwnedParameter('id', intType)
superContext.createOpaqueBehavior(teIndex, '''return id - «TIME_EVENT_LOWER_BOUND»;''')
val retType = teIndex.createOwnedParameter('ret', intType)
retType.direction = ParameterDirectionKind.RETURN_LITERAL
superContext.createOwnedAttribute("currentEvent", event_t)
appendImport('''
import statemachineJava.EventPriority_t;
import statemachineJava.EventType_t;
''')
// SM Monitoring
// monitoringTransformation.appendInclude
signalEvents.forEach [
eventIdEnum.createOwnedLiteral(it.eventID)
]
callEvents.forEach [
eventIdEnum.createOwnedLiteral(it.eventID)
]
anyEvents.forEach [
eventIdEnum.createOwnedLiteral(it.eventID)
]
eventIdEnum.createOwnedLiteral(COMPLETION_EVENT.toUpperCase + "_ID")
topRegion.allActionsTransitionsStates
states.filter[it.orthogonal].forEach [
if (it.regions.size > MAX_NUMBER_ORTHOGONAL_REGIONS) {
MAX_NUMBER_ORTHOGONAL_REGIONS = it.regions.size
}
]
states.forEach [
val triggers = new ArrayList<Trigger>
it.outgoings.forEach [
triggers.addAll(it.triggers)
]
val events = triggers.map[it.event]
val timeEvents = events.filter(TimeEvent).toList
states2TimeEvents.put(it, timeEvents)
]
vertexes.filter(Pseudostate).forEach [
if (it.kind == PseudostateKind.JUNCTION_LITERAL) {
junctions.add(it)
}
]
// for each junction, create a class variable
junctions.forEach [
superContext.createOwnedAttribute(it.name, intType)
]
// create state ID enumeration
// val stateIdEnum = targetPack.createOwnedEnumeration("StateIDEnum") as Enumeration
stateIdEnum = superContext.createNestedClassifier("StateIDEnum", UMLPackage.Literals.ENUMERATION) as Enumeration
// TODO
// stateStruct.createDependency(stateIdEnum)
// don't use class enumerations (rely on conversion to unsigned int)
// val stateIdEnumStyle = StereotypeUtil.applyApp(stateIdEnum, EnumStyle)
// stateIdEnumStyle.classEnum = false;
// SM Monitoring
monitoringTransformation.createMonitorAttributes
// create state struct
createStateStruct()
// var stateArrayAttr = superContext.createOwnedAttribute(STATE_ARRAY_ATTRIBUTE, state_t)
// StereotypeUtil.apply(stateArrayAttr, Array)
// StereotypeUtil.apply(stateArrayAttr, Ptr)
// UMLUtil.getStereotypeApplication(stateArrayAttr, Array).definition = '''[«states.size»]'''
// create root active state ID
// TODO
superContext.createOwnedAttribute(ACTIVE_ROOT_STATE_ID, stateIdEnum)
superContext.createOwnedAttribute("dispatchStruct", threadStructType)
// TODO: the State_t class has an SM attribute typed with an external class that needs to be adapted to the current class.
// This could/should be avoided in the future
val smAttr = (threadStructType as Class).getOwnedAttribute("sm", null)
val smType = smAttr.type
smType.setName(superContext.getName())
val extSM = UMLUtil.getStereotypeApplication(smType, External)
extSM.name = superContext.qualifiedName.replace(NamedElement.SEPARATOR, StringConstants.DOT);
val teGetter = superContext.createOwnedOperation("getTEIndex", null, null);
teGetter.createOwnedParameter("id", intType);
teGetter.createOwnedParameter("ret", intType).setDirection(ParameterDirectionKind.RETURN_LITERAL)
teGetter.set(langID, '''return «superContext.name.toUpperCase»_TE_INDEX(id);''')
val smMax = superContext.createOwnedOperation("getStateMax", null, null);
smMax.createOwnedParameter("ret", intType).setDirection(ParameterDirectionKind.RETURN_LITERAL)
smMax.set(langID, "return StateIDEnum.STATE_MAX.ordinal();")
var state = superContext.createOwnedAttribute("states", state_t)
state.upper = states.size
createOpaqueExpressionDefaultValue(state, "state", "new State_t[StateIDEnum.STATE_MAX.ordinal()];")
var threadStructs = superContext.createOwnedAttribute("threadStructs", threadStructType)
threadStructs.upper = states.size
createOpaqueExpressionDefaultValue(threadStructs, "threadStructs",
"new StructForThread_t[StateIDEnum.STATE_MAX.ordinal()];")
var flags = superContext.createOwnedAttribute("flags", boolType)
flags.upper = states.size
createOpaqueExpressionDefaultValue(flags, "flags", "new boolean[StateIDEnum.STATE_MAX.ordinal()];")
var timeEventFlags = superContext.createOwnedAttribute("timeEventFlags", boolType)
timeEventFlags.upper = states.size
createOpaqueExpressionDefaultValue(timeEventFlags, "timeEventFlags",
"new boolean[StateIDEnum.STATE_MAX.ordinal()];")
var timeEventThreadStructs = superContext.createOwnedAttribute("timeEventThreadStructs", threadStructType)
timeEventThreadStructs.upper = states.size
createOpaqueExpressionDefaultValue(timeEventThreadStructs, "timeEventThreadStructs",
"new StructForThread_t[2];")
var semaphore = ElementUtils.getQualifiedElementFromRS(superContext, SEMAPHORE_QNAME) as Type
var sem = superContext.createOwnedAttribute("sem", semaphore)
createOpaqueExpressionDefaultValue(sem, "sem", "new Semaphore(1);")
var queue = ElementUtils.getQualifiedElementFromRS(superContext,
"statemachineJava::extern::PriorityBlockingQueue<Event_t>") as Type
var eventQueue = superContext.createOwnedAttribute("eventQueue", queue)
createOpaqueExpressionDefaultValue(eventQueue, "eventQueue", "new PriorityBlockingQueue<Event_t>();")
createRegionMethods
val startCode = '''startBehavior();'''
if (LifeCycleUtil.supportsLifeCycle(superContext)) {
// class implements life-cycle interface => add "startBehavior" call to activation function
LifeCycleUtil.addUnimplemented(superContext)
var activateOp = superContext.getOperation(LifeCycleUtil.M_ACTIVATE, null, null)
activateOp.appendBody(startCode)
} else {
// add startBehavior to all constructor
val constructors = superContext.ownedOperations.filter [
it.isApplied(Create) && it.name == superContext.name
]
if (constructors.empty) {
// create constructor
var ctor = superContext.createOwnedOperation(superContext.name, null, null)
ctor.apply(Create)
superContext.createOpaqueBehavior(ctor, '''
«FOR s : states»
«IF s.entry.isBehaviorExist»
«s.name + "_" + ENTRY_NAME»= new «s.name + "_" + ENTRY_NAME»();
«ENDIF»
«IF s.exit.isBehaviorExist»
«s.name + "_" + EXIT_NAME»= new «s.name + "_" + EXIT_NAME»();
«ENDIF»
«IF s.doActivity.isBehaviorExist»
«s.name + "_" + DO_ACTIVITY_NAME»= new «s.name + "_" + DO_ACTIVITY_NAME»();
«ENDIF»
«ENDFOR»
entry_dft = new Entry_dft();
doActivity_dft = new DoActivity_dft();
exit_dft = new Exit_dft();
startBehavior();
''')
} else {
constructors.forEach [
it.appendBody(startCode)
]
}
}
monitoringTransformation.createConstructor
monitoringTransformation.createDestructor
var startBehavior = superContext.createOwnedOperation("startBehavior", null, null)
superContext.createOpaqueBehavior(startBehavior, '''
«SYSTEM_STATE_ATTR» = statemachineJava.SystemStateEnum_t.IDLE;
// initialize all threads, the threads wait until the associated flag is set
for (int i = 0; i < (int) StateIDEnum.STATE_MAX.ordinal(); i++) {
states[i] = new State_t(this);
}
«FOR s : states»
«IF s.entry.isBehaviorExist»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()].«ENTRY_NAME» = «s.name + "_" + ENTRY_NAME»;
«ENDIF»
«IF s.exit.isBehaviorExist»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()].«EXIT_NAME» = «s.name + "_" + EXIT_NAME»;
«ENDIF»
«IF s.doActivity.isBehaviorExist»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()].«DO_ACTIVITY_NAME» = «s.name + "_" + DO_ACTIVITY_NAME»;
«ENDIF»
«ENDFOR»
for(int i = 0; i < (int) StateIDEnum.«STATE_MAX».ordinal(); i++) {
if («STATE_ARRAY_ATTRIBUTE»[i].«DO_ACTIVITY_NAME» != doActivity_dft) {
StructForThread_t threadstructs = new StructForThread_t(this, ThreadFunctions.TF_DO_ACTIVITY, i,sem);
threadStructs[i] = threadstructs;
threadStructs[i].start();
}
}
«IF timeEvents.size > 0»
for(int i = «TIME_EVENT_LOWER_BOUND»; i < «timeEvents.size»; i++) {
timeEventThreadStructs[i] = new StructForThread_t(this, ThreadFunctions.TF_TIME_EVENT,i,sem );
}
«FOR e:timeEvents»
«var duration = ParseVSL.getMsDurationFromVSL((e.when.expr as OpaqueExpression).bodies.get(0))»
«THREAD_STRUCTS_FOR_TIMEEVENT»[«TE_INDEX»(EventId_t.«e.eventID».ordinal())].duration = «duration»;
«ENDFOR»
for(int i = «TIME_EVENT_LOWER_BOUND»; i < «timeEvents.size»; i++) {
timeEventThreadStructs[i].start();
while (timeEventFlags[«TE_INDEX»(i)]) {
}
}
dispatchStruct = new StructForThread_t(this, 0, ThreadFunctions.TF_STATE_MACHINE_TYPE);
dispatchStruct.start();
«ENDIF»
«IF !orthogonalRegions.empty»
«FOR r:orthogonalRegions»
«REGION_TABLE»[«r.regionMacroId»] = &«superContext.name»::«r.regionMethodName»;
«REGION_TABLE_EXIT»[«r.regionMacroId»] = &«superContext.name»::«r.regionMethodExitName»;
«ENDFOR»
«ENDIF»
«IF !parallelTransitions.empty»
«FOR t:parallelTransitions»
«PARALLEL_TRANSITION_TABLE»[«concurrency.parallelTransitionId(t)»] = &«superContext.name»::«concurrency.parallelTransitionMethodName(t)»;
«ENDFOR»
«ENDIF»
«IF changeEvents.size > 0»
// threads for changeEvent
for(int i = «CHANGE_EVENT_LOWER_BOUND»; i < «CHANGE_EVENT_LOWER_BOUND» + «changeEvents.size»; i++) {
«THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)].id = i;
«THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)].ptr = this;
«THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)].func_type = «THREAD_FUNC_CHANGEEVENT_TYPE»;
«FORK_NAME»(&«THREADS_CHANGE_EVENT»[«CHE_INDEX»(i)], NULL, &«superContext.name»::«THREAD_FUNC_WRAPPER», &«THREAD_STRUCTS_FOR_CHANGEEVENT»[«CHE_INDEX»(i)]);
}
«ENDIF»
// initialize root active state
// execute initial effect
«getRegionMethodName(topRegion)»(«topRegion.initialMacroName»);
''')
var stopBehavior = superContext.createOwnedOperation("stop", null, null)
superContext.createOpaqueBehavior(stopBehavior, '''
«SYSTEM_STATE_ATTR» = statemachineJava.SystemStateEnum_t.IDLE;
dispatchStruct.interrupt();
for (int i = «TIME_EVENT_LOWER_BOUND»; i < «timeEvents.size»; i++) {
timeEventThreadStructs[i].interrupt();
}
for (int i = 0; i < (int) StateIDEnum.«STATE_MAX».ordinal(); i++) {
if («STATE_ARRAY_ATTRIBUTE»[i].«DO_ACTIVITY_NAME» != doActivity_dft) {
threadStructs[i].interrupt();
}
}
''')
superContext.createOwnedAttribute("dispatchFlag", boolType)
eventMap.forEach [ e, trans |
eventTransform.createEventMethod(e, trans)
]
val autoTrans = new ArrayList<Transition>
transitions.forEach [
if (it.source instanceof State && it.triggers.map[it.event].size == 0) {
autoTrans.add(it)
}
]
eventTransform.createEventMethod(COMPLETION_EVENT, autoTrans)
// create entry/exit/doactivity of each state
states.forEach [
stateIdEnum.createOwnedLiteral(it.name.toUpperCase + "_ID")
val runnable = ElementUtils.getQualifiedElementFromRS(superContext,
RUNNABLE_QNAME) as Interface
if (it.entry.isBehaviorExist) {
val entry = superContext.createNestedClassifier(it.name + "_" + ENTRY_NAME,
UMLPackage.eINSTANCE.getClass_) as Class
entry.createInterfaceRealization(null, runnable)
val entry_run = entry.createOwnedOperation("run", null, null)
var opaque = entry.createOpaqueBehavior(entry_run, (it.entry as OpaqueBehavior).bodies.head)
opaque.languages.add(langID)
superContext.createOwnedAttribute(it.name + "_" + ENTRY_NAME, entry)
}
if (it.exit.isBehaviorExist) {
val exit = superContext.createNestedClassifier(it.name + "_" + EXIT_NAME,
UMLPackage.eINSTANCE.getClass_) as Class
exit.createInterfaceRealization(null, runnable)
val exit_run = exit.createOwnedOperation("run", null, null)
var opaque = exit.createOpaqueBehavior(exit_run, (it.exit as OpaqueBehavior).bodies.head)
opaque.languages.add(langID)
superContext.createOwnedAttribute(it.name + "_" + EXIT_NAME, exit)
}
if (it.doActivity.isBehaviorExist) {
doActivityList.add(it.doActivity)
val doActivity = superContext.createNestedClassifier(it.name + "_" + DO_ACTIVITY_NAME,
UMLPackage.eINSTANCE.getClass_) as Class
doActivity.createInterfaceRealization(null, runnable)
val doActivity_run = doActivity.createOwnedOperation("run", null, null)
var opaque = doActivity.createOpaqueBehavior(doActivity_run,
(it.doActivity as OpaqueBehavior).bodies.head)
opaque.languages.add(langID)
superContext.createOwnedAttribute(it.name + "_" + DO_ACTIVITY_NAME, doActivity)
} else {
// var doActivity = superContext.createOwnedOperation(it.name + "_" + DO_ACTIVITY_NAME, null, null)
// var callCompletionEvent = ''''''
// if (!it.composite) {
// //callCompletionEvent = '''process«COMPLETION_EVENT»();'''
// }
// var opaque = superContext.createOpaqueBehavior(doActivity, callCompletionEvent)
// opaque.languages.add(langID)
}
]
stateIdEnum.createOwnedLiteral(STATE_MAX)
concurrency.createThreadBasedParallelism
smPack.getOwnedType("Event_t")
// StereotypeUtil.apply(superContext.createOwnedAttribute("currentEvent", eventClass),);
var eventDispatch = superContext.createOwnedOperation(EVENT_DISPATCH, null, null)
superContext.createOpaqueBehavior(eventDispatch, '''
boolean popDeferred = false;
while (!Thread.currentThread().isInterrupted()) {
// run-to-completion: need to have a mutex here
try {
currentEvent = «EVENT_QUEUE».take();
} catch (InterruptedException e) {
// interruption, exit loop
break;
}
dispatchFlag = true;
if (currentEvent != null) {
int eventID = currentEvent.getEventID();
«FOR e : eventMap.keySet.filter[!(it instanceof CallEvent)]»
if (eventID == EventId_t.«e.eventID».ordinal()) {
«IF e instanceof SignalEvent && (e as SignalEvent).signal !== null»
if (currentEvent != NULL) {
««« TODO no memcpy on Java
memcpy(&sig_«e.eventID», currentEvent->data, sizeof();
process«e.eventName»(sig_«e.eventID»);
}
«ELSE»
process«e.eventName»();
«ENDIF»
}
«ENDFOR»
if (eventID == EventId_t.COMPLETIONEVENT_ID.ordinal()) {
processCompletionEvent();
}
}
if («SYSTEM_STATE_ATTR» == SystemStateEnum_t.EVENT_DEFERRED) {
// «EVENT_QUEUE».saveDeferred(*currentEvent);
}
popDeferred = («SYSTEM_STATE_ATTR» != SystemStateEnum_t.EVENT_DEFERRED);
// «SYSTEM_STATE_ATTR» = SystemStateEnum_t.IDLE;
}
''')
concurrency.createConcurrencyForTransitions
/*superContext.createOwnedAttribute("dispatchThread", ptTypes.pthread)
* superContext.createOwnedAttribute("dispatchStruct", concurrency.threadStructType)
* superContext.createOwnedAttribute(RUN_TO_COMPLETION_MUTEX, ptTypes.pthreadMutex)
* superContext.createOwnedAttribute(RUN_TO_COMPLETION_COND, ptTypes.pthreadCond)
*/
createChangeEvents
}
def appendImport(String appended) {
val import = superContext.applyApp(Import)
import.manualImports = '''
«import.manualImports»
«appended»'''
}
private def createChangeEvents() {
new ChangeEventTransformation(this).createChangeEvents
}
def String generateChangeState(State s) {
if (s.container == topRegion) {
return '''«ACTIVE_ROOT_STATE_ID» = StateIDEnum.«s.name.toUpperCase»_ID;'''
}
var rIndex = s.container.state.regions.indexOf(s.container)
return '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.container.state.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«rIndex»] = «s.name.toUpperCase»_ID;'''
}
def String generateExitingSubStates(State parent, boolean exitParent) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«IF parent.orthogonal»
//exiting concurrent state «parent.name»
«FOR r:parent.regions»
«concurrency.generateForkCall(r, false, "0")»
«ENDFOR»
«FOR r:parent.regions»
«concurrency.generateJoinCall(r, false)»
«ENDFOR»
«ELSEIF parent.composite»
«parent.regions.head.regionMethodExitName»();
«ELSE»
«ENDIF»
«IF exitParent»
«IF parent.doActivity.isBehaviorExist»
//signal to exit the doActivity of «parent.name»
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false);
«ENDIF»
«parent.generateActivateTimeEvent("false")»
«IF parent.exit.isBehaviorExist»
//exit action of «parent.name»
«getFptrCall(pAttr, EXIT_NAME)»;
«ENDIF»
«ENDIF»'''
}
def generateActivateTimeEvent(State s, String trueOrFalse) '''
«IF states2TimeEvents.get(s) !== null»
«FOR te : states2TimeEvents.get(s)»
«SET_FLAG»(«TE_INDEX»(EventId_t.«te.eventID».ordinal()), «THREAD_FUNC_TIMEEVENT_TYPE», «trueOrFalse»);
«ENDFOR»
«ENDIF»
'''
@Deprecated
def String generateExitingSubStatesWithTransition(State parent, boolean exitParent, Transition t) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«IF parent.orthogonal»
«FOR r:parent.regions»
«FOR s:r.subvertices.filter(State).filter[!(it instanceof FinalState) && it.composite] SEPARATOR ' else '»
if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] == &«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()]) {
«generateExitingSubStates(s, true)»
}
«ENDFOR»
if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] != NULL) {
«FOR sub:r.subvertices.filter(State).filter[!(it instanceof FinalState)] SEPARATOR ' else '»
if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] == &«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«sub.name.toUpperCase»_ID.ordinal()]) {
«SET_FLAG»(StateIdEnum.«sub.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false);
}
«ENDFOR»
«getFptrCall(STATE_ARRAY_ATTRIBUTE+"[StateIDEnum."+parent.name.toUpperCase+"_ID.ordinal()]."+ACTIVE_SUB_STATES+"["+parent.regions.indexOf(r)+"]", EXIT_NAME)»;
}
«STATE_ARRAY_ATTRIBUTE»[StateIdEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = NULL;
«ENDFOR»
«ELSEIF parent.composite»
«FOR s:parent.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState) && it.composite] SEPARATOR ' else '»
if («STATE_ARRAY_ATTRIBUTE»[StateIdEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] == «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«s.name.toUpperCase»_ID.ordinal()]) {
«generateExitingSubStates(s, true)»
}
«ENDFOR»
if («STATE_ARRAY_ATTRIBUTE»[StateIdEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] != NULL) {
«FOR sub:parent.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState)] SEPARATOR ' else '»
if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] == «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«sub.name.toUpperCase»_ID.ordinal()]) {
«SET_FLAG»(StateIDEnum.«sub.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false);
}
«ENDFOR»
«getFptrCall(STATE_ARRAY_ATTRIBUTE+"[StateIDEnum"+parent.name.toUpperCase+"_ID.ordinal()]."+ACTIVE_SUB_STATES+"[0]", EXIT_NAME)»;
}
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = NULL;
«ELSE»
«ENDIF»
«IF exitParent»
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», false);
«getFptrCall(pAttr, EXIT_NAME)»;
«ENDIF»
«TransformationUtil.getTransitionEffect(t)»'''
}
@Deprecated
def String generateEnteringSubStates(State parent, boolean enterParent) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«IF enterParent»
«generateChangeState(parent)»
«getFptrCall(pAttr, ENTRY_NAME)»;
// start activity of «parent.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«ENDIF»
«IF parent.orthogonal»
«FOR r:parent.regions»
«IF TransformationUtil.findInitialState(r) !== null»
«TransformationUtil.getInitialEffect(r)»
«generateEnteringSubStates(TransformationUtil.findInitialState(r), true)»
«ENDIF»
«ENDFOR»
«ELSEIF parent.composite»
«IF TransformationUtil.findInitialState(parent.regions.head) !== null»
«TransformationUtil.getInitialEffect(parent.regions.head)»
«generateEnteringSubStates(TransformationUtil.findInitialState(parent.regions.head), true)»
«ENDIF»
«ELSE»
«ENDIF»'''
}
@Deprecated
def String generateEnteringSubStates(State parent, State child, boolean enterParent, boolean gotoSubstate) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«IF enterParent»
«generateChangeState(parent)»
«getFptrCall(pAttr, ENTRY_NAME)»;
// start activity of «parent.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«ENDIF»
«IF parent.orthogonal»
«FOR r:parent.regions»
«IF child.container == r»
«IF gotoSubstate»
«generateEnteringSubStates(child, true)»
«ENDIF»
«ELSEIF TransformationUtil.findInitialState(r) !== null»
«TransformationUtil.getInitialEffect(r)»
«generateEnteringSubStates(TransformationUtil.findInitialState(r), true)»
«ENDIF»
«ENDFOR»
«ELSEIF parent.composite»
//«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = &«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«child.name.toUpperCase»_ID.ordinal()];
«generateEnteringSubStates(child, true)»
«ELSE»
«ENDIF»'''
}
@Deprecated
def String generateEnteringTransitiveSubStates(State parent, State child) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«generateChangeState(parent)»
«getFptrCall(pAttr, ENTRY_NAME)»;
// start activity of «parent.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«IF parent.orthogonal»
«FOR r:parent.regions»
«IF child.container == r»
«generateEnteringSubStates(child, true)»
«ELSEIF TransformationUtil.transitiveSubStates(r).contains(child)»
«var nextParent = r.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head»
«generateEnteringTransitiveSubStates(nextParent, child)»
«ELSEIF TransformationUtil.findInitialState(r) !== null»
«TransformationUtil.getInitialEffect(r)»
«generateEnteringSubStates(TransformationUtil.findInitialState(r), true)»
«ENDIF»
«ENDFOR»
«ELSEIF parent.composite»
«IF child.container.state == parent»
«generateEnteringSubStates(parent, child, false, false)»
«ELSE»
«var nextParent = parent.regions.head.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head»
«generateEnteringTransitiveSubStates(nextParent, child)»
«ENDIF»
«ELSE»
«ENDIF»'''
}
@Deprecated
def String generateEnteringTransitiveSubStates(State parent, State child, boolean enterParent, boolean gotoChild) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«IF enterParent»
«generateChangeState(parent)»
«getFptrCall(pAttr, ENTRY_NAME)»;
// start activity of «parent.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«ENDIF»
«IF parent.orthogonal»
«FOR r:parent.regions»
«IF child.container == r»
«IF gotoChild»
«generateEnteringSubStates(child, true)»
«ENDIF»
«ELSEIF TransformationUtil.transitiveSubStates(r).contains(child)»
«var nextParent = r.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head»
«generateEnteringTransitiveSubStates(nextParent, child)»
«ELSEIF TransformationUtil.findInitialState(r) !== null»
«TransformationUtil.getInitialEffect(r)»
«generateEnteringSubStates(TransformationUtil.findInitialState(r), true)»
«ENDIF»
«ENDFOR»
«ELSEIF parent.composite»
«IF child.container.state == parent»
«IF gotoChild»
«generateEnteringSubStates(parent, child, enterParent, false)»
«ENDIF»
«ELSE»
«var nextParent = parent.regions.head.subvertices.filter(State).filter[TransformationUtil.transitiveSubStates(it).contains(child)].head»
«generateEnteringTransitiveSubStates(nextParent, child)»
«ENDIF»
«ELSE»
«ENDIF»'''
}
private def transitiveSubStates(Region r) {
return TransformationUtil.transitiveSubStates(r)
}
private def transitiveSubStates(State s) {
return TransformationUtil.transitiveSubStates(s)
}
@Deprecated
def String generateEnteringSpecial(State parent, Pseudostate child) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(),]'''
return '''
«generateChangeState(parent)»
«getFptrCall(pAttr, ENTRY_NAME)»;
// start activity of «parent.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«IF parent.orthogonal»
«FOR r:parent.regions»
«IF child.container == r»
«pseudostateGenerator.generatePseudo(child)»
«ELSEIF r.transitiveSubStates.contains(child)»
«var nextParent = r.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(),].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «nextParent.name.toUpperCase»_ID;
«generateEnteringSpecial(nextParent, child)»
«ELSEIF TransformationUtil.findInitialState(r) !== null»
«TransformationUtil.getInitialEffect(r)»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «TransformationUtil.findInitialState(r).name.toUpperCase»_ID;
«generateEnteringSubStates(TransformationUtil.findInitialState(r), true)»
«ENDIF»
«ENDFOR»
«ELSEIF parent.composite»
«IF child.container.state == parent»
«pseudostateGenerator.generatePseudo(child)»
«ELSE»
«var nextParent = parent.regions.head.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = «nextParent.name.toUpperCase»_ID;
«generateEnteringSpecial(nextParent, child)»
«ENDIF»
«ELSE»
«ENDIF»'''
}
@Deprecated
def String generateEnteringSpecial(State parent, Pseudostate child, Transition t) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«generateChangeState(parent)»
«TransformationUtil.getTransitionEffect(t)»
«getFptrCall(pAttr, ENTRY_NAME)»;
// start activity of «parent.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«IF parent.orthogonal»
«FOR r:parent.regions»
«IF child.container == r»
«pseudostateGenerator.generatePseudo(child)»
«ELSEIF r.transitiveSubStates.contains(child)»
«var nextParent = r.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «nextParent.name.toUpperCase»_ID;
«generateEnteringSpecial(nextParent, child)»
«ELSEIF TransformationUtil.findInitialState(r) !== null»
«TransformationUtil.getInitialEffect(r)»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«parent.regions.indexOf(r)»] = «TransformationUtil.findInitialState(r).name.toUpperCase»_ID;
«generateEnteringSubStates(TransformationUtil.findInitialState(r), true)»
«ENDIF»
«ENDFOR»
«ELSEIF parent.composite»
«IF child.container.state == parent»
«pseudostateGenerator.generatePseudo(child)»
«ELSE»
«var nextParent = parent.regions.head.subvertices.filter(State).filter[it.transitiveSubStates.contains(child)].head»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0] = «nextParent.name.toUpperCase»_ID;
«generateEnteringSpecial(nextParent, child)»
«ENDIF»
«ELSE»
«ENDIF»'''
}
def String generateCompletionCall(State state) {
var callCompletionEvent = ''''''
var composite = state.container.state
if (composite === null) {
callCompletionEvent = ''''''
} else {
callCompletionEvent = '''
if («FOR r : composite.regions SEPARATOR ' && '»(«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«composite.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«composite.regions.indexOf(r)»] == «STATE_MAX»)«ENDFOR») {
«EVENT_QUEUE».push(statemachine::EventPriority_t::PRIORITY_1, NULL, COMPLETIONEVENT_ID, statemachine::COMPLETION_EVENT, «composite.name.toUpperCase»_ID);
}'''
}
return callCompletionEvent
}
def TransitionGraph calculateTransitionGraphs(State s, Transition t) {
var ret = new TransitionGraph
ret.P.add(t.target as Pseudostate)
ret.T.add(t)
ret.S.add(s)
var target = t.target as Pseudostate
if (target.kind == PseudostateKind.JOIN_LITERAL) {
var ins = target.incomings.filter[it.source.container.state == s.container.state].toList
ret.S.addAll(ins.map[it.source].filter(State))
ret.T.addAll(ins)
}
var nexts = t.target.findTrans
ret.T.addAll(nexts)
var H = nexts.map[t.target].filter(Pseudostate).filter [
it.kind == PseudostateKind.DEEP_HISTORY_LITERAL || it.kind == PseudostateKind.SHALLOW_HISTORY_LITERAL
]
ret.P.addAll(H)
ret.P.addAll(nexts.map[it.source].filter(Pseudostate))
ret.L.addAll(nexts.map[it.target].filter(State))
return ret
}
private def createOpaqueExpressionDefaultValue(Property container, String name) {
var opaque = container.defaultValue as OpaqueExpression
if (opaque === null) {
opaque = container.createDefaultValue(name, null, UMLPackage.Literals.OPAQUE_EXPRESSION) as OpaqueExpression
opaque.languages.add(langID)
}
return opaque
}
def createOpaqueExpressionDefaultValue(Property container, String name, String body) {
var opaque = container.createOpaqueExpressionDefaultValue(name)
if (opaque.bodies.size > 0) {
opaque.bodies.set(0, body)
} else {
opaque.languages.add(langID)
opaque.bodies.add(body)
}
return opaque
}
// get transitive parent states
def List<State> getTransitiveParentStates(Vertex s) {
var ret = new ArrayList<State>
var parent = s.container.state
while (parent !== null) {
ret.add(parent)
parent = parent.container.state
}
return ret
}
/*
def generateDelegation(State s, List<Transition> transitions) {
return '''
«IF checkTransitiveSubStatesAcceptEvent(s, transitions)»
«IF s.orthogonal»
«ELSE»
«ENDIF»
«ENDIF»'''
}
*/
// create State_t struct
def createStateStruct() {
val runnable = ElementUtils.getQualifiedElementFromRS(superContext,
RUNNABLE_QNAME) as Interface
val entry_dft = superContext.createNestedClassifier("Entry_dft", UMLPackage.eINSTANCE.getClass_) as Class
entry_dft.createInterfaceRealization(null, runnable)
val entry_run = entry_dft.createOwnedOperation("run", null, null)
entry_dft.createOpaqueBehavior(entry_run, '')
val doActivity_dft = superContext.createNestedClassifier("DoActivity_dft",
UMLPackage.eINSTANCE.getClass_) as Class
doActivity_dft.createInterfaceRealization(null, runnable)
val doActivity_run = doActivity_dft.createOwnedOperation("run", null, null)
doActivity_dft.createOpaqueBehavior(doActivity_run, '')
val exit_dft = superContext.createNestedClassifier("Exit_dft", UMLPackage.eINSTANCE.getClass_) as Class
exit_dft.createInterfaceRealization(null, runnable)
val exit_run = exit_dft.createOwnedOperation("run", null, null)
exit_dft.createOpaqueBehavior(exit_run, '')
superContext.createOwnedAttribute("entry_dft", entry_dft)
superContext.createOwnedAttribute("doActivity_dft", doActivity_dft)
superContext.createOwnedAttribute("exit_dft", exit_dft)
}
def getFptrCall(String attr, String fptrName) {
return '''«attr».«fptrName».run()'''
}
private def Map<Event, List<Transition>> getAllEvents(Region region) {
val Map<Event, List<Transition>> ret = new LinkedHashMap
var subVertices = region.subvertices
var transitions = region.transitions
transitions.forEach [
for (trigger : it.triggers) {
if (trigger.event !== null) {
if (!ret.containsKey(trigger.event)) {
ret.put(trigger.event, new ArrayList)
}
if (!ret.get(trigger.event).contains(it)) {
ret.get(trigger.event).add(it)
}
}
}
]
subVertices.filter(typeof(State)).forEach [
for (subRe : it.regions) {
var m = subRe.allEvents
for (e : m.entrySet) {
if (!ret.containsKey(e.key)) {
ret.put(e.key, e.value)
} else {
ret.get(e.key).addAll(e.value)
}
}
}
]
return ret
}
private def void getAllActionsTransitionsStates(Region region) {
if (!regions.contains(region)) {
regions.add(region)
}
transitions.addAll(region.transitions.filter[it.source !== null && it.target !== null])
transitions.filter[!parallelTransitions.contains(it)].forEach [
if (it.source instanceof Pseudostate) {
if ((it.source as Pseudostate).kind == PseudostateKind.FORK_LITERAL && it.effect !== null) {
parallelTransitions.add(it)
}
}
if (it.target instanceof Pseudostate) {
if ((it.target as Pseudostate).kind == PseudostateKind.JOIN_LITERAL && it.effect !== null) {
parallelTransitions.add(it)
}
}
]
for (s : region.subvertices) {
vertexes.add(s)
if (s instanceof State) {
if (!(s instanceof FinalState)) {
states.add(s)
}
if (s.entry !== null && s.entry instanceof OpaqueBehavior) {
actions.add(s.entry as OpaqueBehavior)
}
if (s.exit !== null && s.exit instanceof OpaqueBehavior) {
actions.add(s.exit as OpaqueBehavior)
}
if (createDoActivity && s.doActivity !== null && s.doActivity instanceof OpaqueBehavior) {
actions.add(s.doActivity as OpaqueBehavior)
}
s.regions.forEach [
it.getAllActionsTransitionsStates
]
}
}
}
public List<Region> orthogonalRegions = new ArrayList
/**
* create methods for regions
*/
private def createRegionMethods() {
// regions.remove(topRegion)
for (var i = 0; i < regions.size; i++) {
createIntConstant(regions.get(i).regionMacroName, i)
regions.get(i).createRegionMethod
createRegionMethodExit(regions.get(i))
if (regions.get(i).state !== null && regions.get(i).state.orthogonal) {
orthogonalRegions.add(regions.get(i))
}
}
for (var i = 0; i < orthogonalRegions.size; i++) {
createIntConstant(orthogonalRegions.get(i).regionMacroId, i)
}
}
def getRegionMacroId(Region r) {
return '''REGION_ID_«r.state.name.toUpperCase»_«r.name.toUpperCase»'''
}
def getRegionMethodName(Region r) {
if (r == topRegion) {
return '''«r.stateMachine.name»_«r.name»_Enter'''
}
return '''«r.state.name»_«r.name»_Enter'''
}
def getRegionMacroName(Region r) {
if (r == topRegion) {
return '''«r.stateMachine.name.toUpperCase»_«r.name.toUpperCase»'''
}
return '''«r.state.name.toUpperCase»_«r.name.toUpperCase»'''
}
def getVertexMacroName(Vertex v) {
if (v.container == topRegion) {
return '''«topRegion.stateMachine.name.toUpperCase»_«v.container.name.toUpperCase»_«v.name.toUpperCase»'''
}
return '''«v.container.state.name.toUpperCase»_«v.container.name.toUpperCase»_«v.name.toUpperCase»'''
}
def getInitialMacroName(Region r) {
if (r == topRegion) {
return '''«r.stateMachine.name.toUpperCase»_«r.name.toUpperCase»_DEFAULT'''
}
return '''«r.state.name.toUpperCase»_«r.name.toUpperCase»_DEFAULT'''
}
private def getSubVertexes(State state) {
val ret = new ArrayList<Vertex>
state.regions.forEach [
ret.addAll(it.subvertices)
]
return ret
}
private def void createRegionMethod(Region r) {
var endVertexs = new ArrayList<Vertex>
// state2TransSubVertices maps from a sub-state sub of r to its sub-vertices (of sub) which
// have incoming transitions outgoing from a vertex which is not a transitive sub-vertex of r
var Map<State, List<Vertex>> state2TransSubVertices = new HashMap
// looking for vertexes having transitions incoming from vertexes which are not direct or indirect sub-vertex of r
for (v : r.subvertices) {
val incomings = v.incomings.filter [
it.container != v.container ||
(it.source instanceof State && (it.source as State).subVertexes.contains(it.target))
]
val sources = incomings.map[it.source]
if (sources.size > 0) {
if (!endVertexs.contains(v)) {
endVertexs.add(v)
}
}
// looking for vertex
if (v instanceof State) {
val subvertices = new ArrayList<Vertex>
v.regions.forEach[subvertices.addAll(it.allSubVertexes)]
for (subV : subvertices) {
var sourcesOfIncomings = subV.incomings.map[it.source]
// sourcesOutSideOfR is a list of vertices having transitions targeting subV
var sourcesOutSideOfR = sourcesOfIncomings.filter[!subvertices.contains(it)]
if (sourcesOutSideOfR.size > 0) {
if (!state2TransSubVertices.containsKey(v)) {
state2TransSubVertices.put(v, new ArrayList)
}
state2TransSubVertices.get(v).add(subV)
}
}
}
}
var switchBody = ''''''
var body = ''''''
var macros = ''''''
// create macros for vertexes which are used to differentiate ways entering the region/state
if (TransformationUtil.firstPseudoState(r, PseudostateKind.INITIAL_LITERAL) !== null) {
var initialP = TransformationUtil.firstPseudoState(r, PseudostateKind.INITIAL_LITERAL)
var initialState = initialP.outgoings.head.target as State
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«initialState.name.toUpperCase»_ID.ordinal()]'''
createIntConstant(r.initialMacroName, 0)
body += '''
case «r.initialMacroName»:
«TransformationUtil.getTransitionEffect(initialP.outgoings.head)»
«generateChangeState(initialState)»
«IF initialState.entry.isBehaviorExist»
«getFptrCall(pAttr, ENTRY_NAME)»;
// starting the counters for time events
«ENDIF»
«initialState.generateActivateTimeEvent("true")»
«IF initialState.doActivity.isBehaviorExist || initialState.hasTriggerlessTransition»
// start activity of «initialState.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«initialState.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«ENDIF»
«IF initialState.composite»
«IF initialState.orthogonal»
//TODO: fork region funtions
«FOR subRegion: initialState.regions»
//«subRegion.regionMethodName»(«subRegion.initialMacroName»);
«concurrency.generateForkCall(subRegion, true, subRegion.initialMacroName)»
«ENDFOR»
//TODO: join region functions
«FOR subRegion: initialState.regions»
//«subRegion.regionMethodName»(«subRegion.initialMacroName»);
«concurrency.generateJoinCall(subRegion, true)»
«ENDFOR»
«ELSE»
«initialState.regions.head.regionMethodName»(«initialState.regions.head.initialMacroName»);
«ENDIF»
«ENDIF»
//TODO: set systemState to EVENT_CONSUMED
break;'''
}
for (var i = 0; i < endVertexs.size; i++) {
createIntConstant(endVertexs.get(i).vertexMacroName, i+1)
}
if (!superContext.isApplied(Import)) {
superContext.apply(Import)
}
/*
* var header = UMLUtil.getStereotypeApplication(superContext, Include).header
* UMLUtil.getStereotypeApplication(superContext, Include).header = '''
* «header»
«macros»''' */
var regionMethod = superContext.createOwnedOperation(r.regionMethodName, null, null)
regionMethod.createOwnedParameter(ENTER_MODE_PARAM, intType)
for (v : endVertexs) {
if (v instanceof State) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«v.name.toUpperCase»_ID.ordinal()]'''
body = '''
«body»
case «v.vertexMacroName»:
«generateChangeState(v)»
«IF v.entry.isBehaviorExist»
«getFptrCall(pAttr, ENTRY_NAME)»;
«ENDIF»
//starting the counters for time events
«v.generateActivateTimeEvent("true")»
«IF v.doActivity.isBehaviorExist || v.hasTriggerlessTransition»
// start activity of «v.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«v.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«ENDIF»
«IF v.composite»
«IF v.orthogonal»
//TODO: fork region funtions
«FOR subRegion: v.regions»
//«subRegion.regionMethodName»(«subRegion.initialMacroName»);
«concurrency.generateForkCall(subRegion, true, subRegion.initialMacroName)»
«ENDFOR»
//TODO: join region functions
«FOR subRegion: v.regions»
//«subRegion.regionMethodName»(«subRegion.initialMacroName»);
«concurrency.generateJoinCall(subRegion, true)»
«ENDFOR»
«ELSE»
«v.regions.head.regionMethodName»(«v.regions.head.initialMacroName»);
«ENDIF»
«ENDIF»
//TODO: set systemState to EVENT_CONSUMED
break;'''
} else {
body = '''
«body»
case «v.vertexMacroName»:
«pseudostateGenerator.generatePseudo(v as Pseudostate)»
//TODO: set systemState to EVENT_CONSUMED
break;'''
}
}
if (r != topRegion) {
for (e : state2TransSubVertices.entrySet) {
var state = e.key
for (transitiveSubVertex : e.value) {
body = '''
«body»
case «transitiveSubVertex.vertexMacroName»:
«generateEnteringOnSubVertex(state, transitiveSubVertex)»
break;'''
}
}
}
switchBody = '''
switch(«ENTER_MODE_PARAM») {
«body»
}
'''
superContext.createOpaqueBehavior(regionMethod, switchBody)
}
def generateEnteringOnSubVertex(State parent, Vertex subVertex) {
var pAttr = '''«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()]'''
return '''
«generateChangeState(parent)»
«IF parent.entry.isBehaviorExist»
«getFptrCall(pAttr, ENTRY_NAME)»;
«ENDIF»
//starting the counters for time events
«parent.generateActivateTimeEvent("true")»
«IF parent.doActivity.isBehaviorExist || parent.hasTriggerlessTransition»
// start activity of «parent.name» by calling setFlag
«SET_FLAG»(StateIDEnum.«parent.name.toUpperCase»_ID.ordinal(), «THREAD_FUNC_DOACTIVITY_TYPE», true);
«ENDIF»
«IF parent.composite && parent != subVertex»
«IF parent.orthogonal»
«var toJoinList = new ArrayList<Region>»
«FOR r:parent.regions»
«IF subVertex !== null»
«IF subVertex.container == r»
«toJoinList.add(r)»
//«getRegionMethodName(r)»(«subVertex.vertexMacroName»);
«concurrency.generateForkCall(r, true, subVertex.vertexMacroName)»
«ELSEIF r.allSubVertexes.contains(subVertex)»
«toJoinList.add(r)»
//«getRegionMethodName(r)»(«subVertex.vertexMacroName»);
«concurrency.generateForkCall(r, true, subVertex.vertexMacroName)»
«ELSEIF TransformationUtil.findInitialState(r) !== null»
«toJoinList.add(r)»
//«getRegionMethodName(r)»(«r.initialMacroName»);
«concurrency.generateForkCall(r, true, r.initialMacroName)»
«ENDIF»
«ELSEIF subVertex !== null && subVertex.container === null»
«IF subVertex.eContainer == parent»
«toJoinList.add(r)»
«concurrency.generateForkCall(r, true, subVertex.vertexMacroName)»
«ELSE»
«toJoinList.add(r)»
«concurrency.generateForkCall(r, true, subVertex.vertexMacroName)»
«ENDIF»
«ELSE»
«IF TransformationUtil.findInitialState(r) !== null»
«toJoinList.add(r)»
//«getRegionMethodName(r)»(«r.initialMacroName»);
«concurrency.generateForkCall(r, true, r.initialMacroName)»
«ENDIF»
«ENDIF»
«ENDFOR»
«FOR r:toJoinList»
«concurrency.generateJoinCall(r, true)»
«ENDFOR»
«ELSEIF parent.composite»
«IF subVertex !== null»
«IF subVertex.container === null && subVertex.eContainer instanceof State»
«getRegionMethodName(parent.regions.head)»(«subVertex.vertexMacroName»);
«ELSEIF subVertex.container.state == parent»
«getRegionMethodName(parent.regions.head)»(«subVertex.vertexMacroName»);
«ELSE»
«var containingRegion = parent.regions.filter[it.allSubVertexes.contains(subVertex)].head»
«getRegionMethodName(containingRegion)»(«subVertex.vertexMacroName»);
«ENDIF»
«ELSE»
«getRegionMethodName(parent.regions.head)»(«parent.regions.head.initialMacroName»);
«ENDIF»
«ELSE»
«ENDIF»
«ELSEIF parent.composite && parent == subVertex»
«IF parent.orthogonal»
«var toJoinList = new ArrayList<Region>»
«FOR r:parent.regions»
«IF TransformationUtil.findInitialState(r) !== null»
«toJoinList.add(r)»
//«getRegionMethodName(r)»(«r.initialMacroName»);
«concurrency.generateForkCall(r, true, r.initialMacroName)»
«ENDIF»
«ENDFOR»
«FOR r:toJoinList»
«concurrency.generateJoinCall(r, true)»
«ENDFOR»
«ELSE»
«IF TransformationUtil.findInitialState(parent.regions.head) !== null»
«getRegionMethodName(parent.regions.head)»(«parent.regions.head.initialMacroName»);
«ENDIF»
«ENDIF»
«ENDIF»'''
}
private def createRegionMethodExit(Region r) {
if (r.state === null || !r.state.composite) {
return
}
// TODO: save states for history
var parent = r.state
var body = '''
//exiting region «r.name»
«var regionIndex = r.state.regions.indexOf(r)»
«FOR s : r.subvertices.filter(State).filter[!(it instanceof FinalState) && it.composite] SEPARATOR ' else '»
if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»] == «s.name.toUpperCase»_ID) {
«IF s.orthogonal»
«FOR subRegion:s.regions»
«concurrency.generateForkCall(subRegion, false, "0")»
«ENDFOR»
«FOR subRegion:s.regions»
«concurrency.generateJoinCall(subRegion, false)»
«ENDFOR»
«ELSE»
«getRegionMethodExitName(s.regions.head)»();
«ENDIF»
}
«ENDFOR»
if («STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»] != «STATE_MAX») {
//signal to exit the doActivity of sub-state of «parent.name»
«SET_FLAG»(«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0], «THREAD_FUNC_DOACTIVITY_TYPE», false);
«FOR sub : r.subvertices.filter(State) SEPARATOR ' else '»
«IF states2TimeEvents.get(sub) !== null»
if («sub.name.toUpperCase»_ID == «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»]) {
«sub.generateActivateTimeEvent("false")»
}
«ENDIF»
«ENDFOR»
//exit action of sub-state of «parent.name»
(this->*«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«STATE_ARRAY_ATTRIBUTE»[«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[0]].«EXIT_NAME»)();
«IF TransformationUtil.isSavehistory(topRegion, r)»
//save history region «r.name» of state «parent.name»
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«PREVIOUS_STATES»[«regionIndex»] = «STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»];
«ENDIF»
//set active sub-state of «parent.name» to «STATE_MAX» meaning NULL
«STATE_ARRAY_ATTRIBUTE»[StateIDEnum.«parent.name.toUpperCase»_ID.ordinal()].«ACTIVE_SUB_STATES»[«regionIndex»] = «STATE_MAX»;
}'''
var exitOp = superContext.createOwnedOperation(r.regionMethodExitName, null, null)
superContext.createOpaqueBehavior(exitOp, body)
}
private def getRegionMethodExitName(Region r) {
if (r == topRegion) {
return '''«r.stateMachine.name»_«r.name»_Exit'''
}
return '''«r.state.name»_«r.name»_Exit'''
}
def List<Vertex> allSubVertexes(Region r) {
val ret = new ArrayList<Vertex>
ret.addAll(r.subvertices)
r.subvertices.filter(State).forEach [
it.regions.forEach [
ret.addAll(it.allSubVertexes)
]
]
return ret
}
private def createOpaqueBehavior(Class container, Operation op) {
var opaque = op.methods.filter(typeof(OpaqueBehavior)).head
if (opaque === null) {
opaque = container.createClassifierBehavior(op.name, UMLPackage.Literals.OPAQUE_BEHAVIOR) as OpaqueBehavior
op.methods.add(opaque)
opaque.languages.add(langID)
}
return opaque
}
def createOpaqueBehavior(Class container, Operation op, String body) {
var opaque = container.createOpaqueBehavior(op)
if (opaque.bodies.size > 0) {
opaque.bodies.set(0, body)
} else {
opaque.languages.add(langID)
opaque.bodies.add(body)
}
return opaque
}
def createDerivedOperation(Class clz, Operation source) {
var name = source.name
var derivedOp = clz.createOwnedOperation(name, null, null)
// OperationUtils.syncOperation(source, derivedOp)
derivedOp.name = name
derivedOp.apply(DerivedElement)
UMLUtil.getStereotypeApplication(derivedOp, DerivedElement).source = source
derivedOp.setVirtual
derivedOp
}
def copyParameters(Operation source, Operation target, boolean isCopyReturn) {
var name = target.name
// OperationUtils.syncOperation(source, target)
if (!isCopyReturn) {
var ret = target.ownedParameters.filter[it.direction == ParameterDirectionKind.RETURN_LITERAL]
target.ownedParameters.removeAll(ret)
}
for (stt : target.stereotypeApplications) {
target.apply(stt.class)
}
target.name = name
}
private def setVirtual(Operation op) {
// StereotypeUtil.apply(op, Virtual)
}
def getGuard(Transition t) {
return (t.guard.specification as OpaqueExpression).bodies.head
}
}