blob: 624197b30d40b478b0a2947078265ddf1ee2dfc3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014-2016 IncQuery Labs Ltd.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Akos Horvath, Abel Hegedus, Marton Bur, Zoltan Ujhelyi - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra.examples.cps.xform.m2t.distributed
import com.google.common.base.Joiner
import com.google.common.collect.Lists
import java.util.HashMap
import org.eclipse.viatra.examples.cps.deployment.BehaviorState
import org.eclipse.viatra.examples.cps.deployment.BehaviorTransition
import org.eclipse.viatra.examples.cps.deployment.Deployment
import org.eclipse.viatra.examples.cps.deployment.DeploymentApplication
import org.eclipse.viatra.examples.cps.deployment.DeploymentBehavior
import org.eclipse.viatra.examples.cps.deployment.DeploymentHost
import org.eclipse.viatra.examples.cps.deployment.common.WaitTransition
import org.eclipse.viatra.examples.cps.xform.m2t.exceptions.CPSGeneratorException
import org.eclipse.viatra.examples.cps.xform.m2t.util.FormatterUtil
import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine
import org.eclipse.jdt.core.ToolFactory
import org.eclipse.jdt.core.formatter.CodeFormatter
class Generator {
extension FormatterUtil helper = new FormatterUtil
val String PROJECT_NAME
val ViatraQueryEngine engine
val CodeFormatter formatter
new(String projectName, ViatraQueryEngine engine){
PROJECT_NAME = projectName
this.engine = engine
this.formatter = ToolFactory.createCodeFormatter(null);
}
def generateHostCode(DeploymentHost host) '''
package «PROJECT_NAME».hosts;
import org.eclipse.viatra.examples.cps.m2t.proto.distributed.general.applications.Application;
import org.eclipse.viatra.examples.cps.m2t.proto.distributed.general.communicationlayer.CommunicationNetwork;
import org.eclipse.viatra.examples.cps.m2t.proto.distributed.general.hosts.BaseHost;
import com.google.common.collect.Lists;
«FOR app : host.applications»
import «PROJECT_NAME».applications.«app.id.purifyAndToUpperCamel»Application;
«ENDFOR»
public class Host«host.ip.purifyAndToUpperCamel» extends BaseHost {
public Host«host.ip.purifyAndToUpperCamel»(CommunicationNetwork network) {
super(network);
// Add Applications of Host
applications = Lists.<Application>newArrayList(
«Joiner.on(',').join(host.calculateAppListForHost)»
);
}
}
'''
def calculateAppListForHost(DeploymentHost host){
val list = Lists.<CharSequence>newArrayList;
for(app : host.applications){
list.add('''new «app.id.purifyAndToUpperCamel»Application(this)''')
}
list
}
def generateApplicationCode(DeploymentApplication app)'''
«val behavior = "Behavior"+app.id.purifyAndToUpperCamel»
«val appClassName = app.id.purifyAndToUpperCamel + "Application"»
package «PROJECT_NAME».applications;
import org.eclipse.viatra.examples.cps.m2t.proto.distributed.general.applications.BaseApplication;
import org.eclipse.viatra.examples.cps.m2t.proto.distributed.general.hosts.Host;
import «PROJECT_NAME».hosts.statemachines.«behavior»;
public class «appClassName» extends BaseApplication<«behavior»> {
// Set ApplicationID
protected static final String APP_ID = "«app.id»";
public «appClassName»(Host host) {
super(host);
«IF app?.behavior?.current !== null»
// Set initial State
currentState = «behavior».«app.behavior.current.description.purifyAndToUpperCamel»;
«ENDIF»
}
@Override
public String getAppID() {
return APP_ID;
}
}
'''
def generateBehaviorCode(DeploymentBehavior behavior)'''
«val app = behavior.eContainer as DeploymentApplication»
«val behaviorClassName = "Behavior"+app.id.purifyAndToUpperCamel»
package «PROJECT_NAME».hosts.statemachines;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.viatra.examples.cps.m2t.proto.distributed.general.applications.Application;
import org.eclipse.viatra.examples.cps.m2t.proto.distributed.general.applications.statemachines.State;
import com.google.common.collect.Lists;
public enum «behaviorClassName» implements State<«behaviorClassName»> {
///////////
// States
«Joiner.on(',').join(behavior.calculateStateCodeListFor(behaviorClassName))»;
private static Logger logger = Logger.getLogger("cps.proto.distributed.state");
/////////////////
// General part
@Override
abstract public List<State<«behaviorClassName»>> possibleNextStates(Application app);
@Override
public «behaviorClassName» stepTo(«behaviorClassName» nextState, Application app){
if(possibleNextStates(app).contains(nextState)){
logger.info("Step from " + this.name() + " to " + nextState.name());
return nextState;
}else{
logger.info("!!! Warning: Unable to step from " + this.name() + " to " + nextState.name()
+ " because the target state is not possible state.");
}
return this;
}
}
'''
def calculateStateCodeListFor(DeploymentBehavior behavior, String behaviorClassName){
val list = Lists.<CharSequence>newArrayList
for(state : behavior.states){
list.add(generateState(state, behaviorClassName))
}
list
}
def generateState(BehaviorState state, String behaviorClassName) '''
«state.description.purifyAndToUpperCamel» {
@Override
public List<State<«behaviorClassName»>> possibleNextStates(Application app) {
List<State<«behaviorClassName»>> possibleStates = Lists.newArrayList();
// Add Neutral Transitions
«FOR trgState : state.calculateNeutralStateTransition»
possibleStates.add(«trgState.description.purifyAndToUpperCamel»);
«ENDFOR»
// Add Send Transitions
«FOR transition : state.calculateSendStateTransition»
possibleStates.add(«transition.to.description.purifyAndToUpperCamel»);
«ENDFOR»
// Add Wait Transitions
«val map = state.calculateWaitStateTransition»
«FOR trgTransition : map.keySet»
if(app.hasMessageFor("«trgTransition.description.purifyAndToUpperCamel»")){
possibleStates.add(«map.get(trgTransition).description.purifyAndToUpperCamel»);
}
«ENDFOR»
return possibleStates;
}
«IF state.hasSendTrigger»
@Override
public «behaviorClassName» stepTo(«behaviorClassName» nextState, Application app) {
// Send triggers
«FOR transition : state.calculateSendStateTransition»
if(nextState == «transition.to.description.purifyAndToUpperCamel»){
app.sendTrigger(«state.calculateSendTriggerParameters(transition)»);
return super.stepTo(nextState, app);
}
«ENDFOR»
// Other cases (wait, neutral)
return super.stepTo(nextState, app);
}
«ENDIF»
}
'''
def String calculateSendTriggerParameters(BehaviorState srcState, BehaviorTransition transition){
//"152.66.102.5", "IBM System Storage", "ISSReceiving"
if(transition !== null){
'''"«transition.trigger.head.host.ip»", "«transition.trigger.head.app.id»", "«transition.trigger.head.name»"'''
}else{
throw new CPSGeneratorException("#Error: Cannot find transition from " + srcState.name + " to " + transition.to.name)
}
}
def DeploymentApplication app(BehaviorTransition transition){
val app = transition?.eContainer?.eContainer
if(app !== null && app instanceof DeploymentApplication){
return app as DeploymentApplication
}
throw new CPSGeneratorException("#Error: Cannot find Application of the Transition (" + transition.name + ")")
}
def DeploymentHost host(BehaviorTransition transition){
val app = transition?.eContainer?.eContainer?.eContainer
if(app !== null && app instanceof DeploymentHost){
return app as DeploymentHost
}
throw new CPSGeneratorException("#Error: Cannot find Host of the Transition (" + transition.name + ")")
}
def DeploymentApplication app(BehaviorState state){
val app = state?.eContainer?.eContainer
if(app !== null && app instanceof DeploymentApplication){
return app as DeploymentApplication
}
throw new CPSGeneratorException("#Error: Cannot find Application of the State (" + state.name + ")")
}
def DeploymentHost host(BehaviorState state){
val host = state?.eContainer?.eContainer?.eContainer
if(host !== null && host instanceof DeploymentHost){
return host as DeploymentHost
}
throw new CPSGeneratorException("#Error: Cannot find Host of the State (" + state.name + ")")
}
def String name(BehaviorState state){
state.description.purifyAndToUpperCamel
}
def String name(BehaviorTransition transition){
transition.description.purifyAndToUpperCamel
}
def boolean hasSendTrigger(BehaviorState srcState){
return srcState.outgoing.exists[ transition | !transition.trigger.empty]
}
def Iterable<BehaviorTransition> calculateSendStateTransition(BehaviorState srcState){
srcState.outgoing.filter[transition |
return !transition.trigger.empty
]
}
def calculateWaitStateTransition(BehaviorState srcState){
val waitTransitions = srcState.outgoing.filter[transition |
return transition.trigger.empty && transition.hasIncomingTrigger
]
val map = new HashMap<BehaviorTransition, BehaviorState>
waitTransitions.forEach[waitTrans |
map.put(waitTrans, waitTrans.to)
]
return map
}
def Iterable<BehaviorState> calculateNeutralStateTransition(BehaviorState srcState){
// TODO optimize
// val incomingTrigger = IncQueryBaseFactory.getInstance.createNavigationHelper(srcState.eResource.resourceSet, true, Logger.getLogger("cps.codegenerator"))
srcState.outgoing.filter[transition |
// val reverse = incomingTrigger.getInverseReferences(transition, ImmutableList.of(DeploymentPackage.Literals.BEHAVIOR_TRANSITION__TRIGGER))
return transition.trigger.empty && !transition.hasIncomingTrigger
].map[transition | transition.to]
}
def boolean hasIncomingTrigger(BehaviorTransition transition){
WaitTransition.Matcher.on(engine).hasMatch(transition, null);
}
def CharSequence generateDeploymentCode(Deployment deployment) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
}