package generators;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import code.ast.Annotation;
import code.ast.Block;
import code.ast.CompilationUnit;
import code.ast.FieldDeclaration;
import code.ast.ImportDeclaration;
import code.ast.MethodDeclaration;
import code.ast.TypeDeclaration;
import code.ast.VariableDeclaration;
import models.Edge;
import models.Node;
import models.algebra.Expression;
import models.algebra.Field;
import models.algebra.Parameter;
import models.algebra.Position;
import models.algebra.Symbol;
import models.algebra.Term;
import models.algebra.Type;
import models.algebra.Variable;
import models.dataConstraintModel.Channel;
import models.dataConstraintModel.ChannelMember;
import models.dataConstraintModel.DataConstraintModel;
import models.dataConstraintModel.ResourceHierarchy;
import models.dataConstraintModel.ResourcePath;
import models.dataConstraintModel.Selector;
import models.dataFlowModel.DataTransferModel;
import models.dataFlowModel.DataTransferChannel;
import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor;
import models.dataFlowModel.PushPullAttribute;
import models.dataFlowModel.PushPullValue;
import models.dataFlowModel.ChannelNode;
import models.dataFlowModel.DataFlowEdge;
import models.dataFlowModel.DataFlowGraph;
import models.dataFlowModel.ResourceNode;
import models.dataFlowModel.StoreAttribute;
/**
* Generator for plain Java prototypes
*
* @author Nitta
*
*/
public class JavaCodeGenerator {
public static final Type typeVoid = new Type("Void", "void");
private static String defaultMainTypeName = "Main";
static String mainTypeName = defaultMainTypeName;
public static String getMainTypeName() {
return mainTypeName;
}
public static void setMainTypeName(String mainTypeName) {
JavaCodeGenerator.mainTypeName = mainTypeName;
}
public static void resetMainTypeName() {
JavaCodeGenerator.mainTypeName = defaultMainTypeName;
}
public static String getComponentName(ResourceHierarchy res) {
String name = res.getResourceName();
if (res.getNumParameters() > 0) {
if (name.length() > 3 && name.endsWith("ies")) {
name = name.substring(0, name.length() - 3) + "y";
} else if (name.length() > 1 && name.endsWith("s")) {
name = name.substring(0, name.length() - 1);
} else {
name += "Element";
}
}
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
public static String toVariableName(String name) {
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
public static Type getImplStateType(ResourceHierarchy res) {
Set<ResourceHierarchy> children = res.getChildren();
if (children == null || children.size() == 0) {
// leaf resource.
return res.getResourceStateType();
} else {
ResourceHierarchy child = children.iterator().next();
if (children.size() == 1 && child.getNumParameters() > 0) {
// map or list.
if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType())) {
// list.
if (generatesComponent(child)) {
return new Type("List", "ArrayList<>", "List<" + getComponentName(child) + ">", DataConstraintModel.typeList);
} else {
return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getInterfaceTypeName() + ">", DataConstraintModel.typeList);
}
} else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType())) {
// map.
if (generatesComponent(child)) {
return new Type("Map", "HashMap<>", "Map<String, " + getComponentName(child) + ">", DataConstraintModel.typeMap);
} else {
return new Type("Map", "HashMap<>", "Map<String, " + getImplStateType(child).getInterfaceTypeName() + ">", DataConstraintModel.typeMap);
}
}
return null;
} else {
// class
return res.getResourceStateType();
}
}
}
public static boolean generatesComponent(ResourceHierarchy res) {
if (res.getParent() == null) return true;
if (res.getChildren() == null || res.getChildren().size() == 0) return false;
if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false;
return true;
// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0);
}
static public ArrayList<CompilationUnit> doGenerate(DataFlowGraph graph, DataTransferModel model) {
ArrayList<CompilationUnit> codes = new ArrayList<>();
Map<ResourceHierarchy, TypeDeclaration> resourceComponents = new HashMap<>();
Map<ResourceHierarchy, MethodDeclaration> resourceConstructors = new HashMap<>();
List<Map.Entry<ResourceHierarchy, MethodDeclaration>> getters = new ArrayList<>();
Map<ResourceHierarchy, Map<String, MethodDeclaration>> updates = new HashMap<>();
Map<ResourceHierarchy, Map<String, MethodDeclaration>> inputs = new HashMap<>();
List<Map.Entry<ResourceHierarchy, FieldDeclaration>> fields = new ArrayList<>();
Map<ResourceHierarchy, Set<ResourceHierarchy>> descendantGetters = new HashMap<>();
List<Map.Entry<ResourceHierarchy, VariableDeclaration>> constructorParams = new ArrayList<>();
Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph = getDependedRootComponentGraph(model);
ArrayList<ResourceNode> resources = determineResourceOrder(graph, dependedRootComponentGraph);
TypeDeclaration mainComponent = new TypeDeclaration(mainTypeName);
CompilationUnit mainCU = new CompilationUnit(mainComponent);
mainCU.addImport(new ImportDeclaration("java.util.*"));
codes.add(mainCU);
// Declare the constructor of the main type.
MethodDeclaration mainConstructor = new MethodDeclaration(mainTypeName, true);
mainComponent.addMethod(mainConstructor);
// For each resource node.
for (ResourceNode resourceNode: resources) {
TypeDeclaration component = null;
Set<ResourceHierarchy> depends = new HashSet<>();
Set<ResourcePath> refs = new HashSet<>();
if (generatesComponent(resourceNode.getResourceHierarchy())) {
boolean f = false;
String resourceName = getComponentName(resourceNode.getResourceHierarchy());
component = resourceComponents.get(resourceNode.getResourceHierarchy());
if (component == null) {
// Add compilation unit for each resource.
component = new TypeDeclaration(resourceName);
resourceComponents.put(resourceNode.getResourceHierarchy(), component);
CompilationUnit cu = new CompilationUnit(component);
cu.addImport(new ImportDeclaration("java.util.*"));
codes.add(cu);
// Declare the field to refer to each resource in the main type.
if (resourceNode.getResourceHierarchy().getParent() == null) {
// For a root resource
String fieldInitializer = "new " + resourceName + "(";
for (Edge resToCh: resourceNode.getOutEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) {
for (Edge chToRes: re.getDestination().getOutEdges()) {
ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy();
String resName = getComponentName(dstRes);
depends.add(dstRes);
fieldInitializer += toVariableName(resName) + ",";
f = true;
}
}
}
for (Edge chToRes : resourceNode.getInEdges()) {
for (Edge resToCh: chToRes.getSource().getInEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
ResourceHierarchy srcRes = ((ResourceNode) re.getSource()).getResourceHierarchy();
String resName = getComponentName(srcRes);
if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) {
depends.add(srcRes);
fieldInitializer += toVariableName(resName) + ",";
f = true;
} else {
ChannelNode cn = (ChannelNode) re.getDestination();
if (cn.getIndegree() > 1
|| (cn.getIndegree() == 1 && cn.getChannel().getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) {
// Declare a field to cache the state of the source resource in the type of the destination resource.
ResourceHierarchy cacheRes = ((ResourceNode) re.getSource()).getResourceHierarchy();
component.addField(new FieldDeclaration(
cacheRes.getResourceStateType(), cacheRes.getResourceName(), getInitializer(cacheRes)));
}
}
}
}
for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) {
for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) {
if (resourceNode.getResourceHierarchy().equals(dependingRes)) {
// Declare a field to refer to outside resources.
depends.add(dependedRes);
String resName = getComponentName(dependedRes);
fieldInitializer += toVariableName(resName) + ",";
f = true;
}
}
}
for (Channel ch : model.getChannels()) {
DataTransferChannel c = (DataTransferChannel) ch;
if (resourceNode.getOutSideResource(c) != null) {
for (ResourcePath res: c.getReferenceResources()) {
if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) {
refs.add(res);
String refResName = res.getLeafResourceName();
fieldInitializer += toVariableName(refResName) + ",";
f = true;
}
}
}
}
if (f) fieldInitializer = fieldInitializer.substring(0, fieldInitializer.length() - 1);
fieldInitializer += ")";
FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), resourceNode.getResourceName());
mainComponent.addField(field);
Block mainConstructorBody = mainConstructor.getBody();
if (mainConstructorBody == null) {
mainConstructorBody = new Block();
mainConstructor.setBody(mainConstructorBody);
}
mainConstructorBody.addStatement(resourceNode.getResourceName() + " = " + fieldInitializer + ";");
}
// Declare the field to store the state in the type of each resource.
if (((StoreAttribute) resourceNode.getAttribute()).isStored()) {
ResourceHierarchy res = resourceNode.getResourceHierarchy();
Set<ResourceHierarchy> children = res.getChildren();
if (children == null || children.size() == 0) {
// leaf resource.
Type fieldType = getImplStateType(res);
component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res)));
} else {
ResourceHierarchy child = children.iterator().next();
if (children.size() == 1 && child.getNumParameters() > 0) {
// map or list.
component.addField(new FieldDeclaration(getImplStateType(res), "value", getInitializer(res)));
} else {
// class
for (ResourceHierarchy c: children) {
String childTypeName = getComponentName(c);
Type childType = null;
if (generatesComponent(c)) {
// The child has a component.
childType = new Type(childTypeName, childTypeName);
String fieldName = toVariableName(childTypeName);
component.addField(new FieldDeclaration(childType, fieldName, "new " + childTypeName + "()"));
}
}
}
}
}
// Declare the getter method to obtain the resource state in this component.
MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(resourceNode.getResourceHierarchy()));
component.addMethod(stateGetter);
// Declare the accessor method in the main type to call the getter method.
declareAccessorMethodInMainComponent(resourceNode, mainComponent);
}
if (component != null) {
// Declare the getter methods in this resource to obtain descendant resources.
Set<ResourceHierarchy> descendants = descendantGetters.get(resourceNode.getResourceHierarchy());
if (descendants == null) {
descendants = new HashSet<>();
descendantGetters.put(resourceNode.getResourceHierarchy(), descendants);
}
for (ResourceNode child: resourceNode.getChildren()) {
// A descendant of the child may generate a component.
List<VariableDeclaration> params = new ArrayList<>();
int v = 1;
ResourceNode descendant = child;
Set<ResourceNode> childNodes;
do {
Expression param = descendant.getPrimaryResourcePath().getLastParam();
if (param != null) {
if (param instanceof Variable) {
Variable var = (Variable) param;
params.add(new VariableDeclaration(var.getType(), var.getName()));
} else if (param instanceof Term) {
Term var = (Term) param;
params.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
if (generatesComponent(descendant.getResourceHierarchy())) {
// If the descendant generates a component.
if (!descendants.contains(descendant.getResourceHierarchy())) {
descendants.add(descendant.getResourceHierarchy());
String descendantCompName = getComponentName(descendant.getResourceHierarchy());
Type descendantType = new Type(descendantCompName, descendantCompName);
MethodDeclaration descendantGetter = null;
if (params.size() == 0) {
descendantGetter = new MethodDeclaration("get" + descendantCompName, descendantType);
} else {
descendantGetter = new MethodDeclaration("get" + descendantCompName, false, descendantType, params);
}
component.addMethod(descendantGetter);
}
break;
}
childNodes = descendant.getChildren();
} while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null);
}
}
}
// Declare the state field in the parent component.
if (component == null) {
// Declare reference fields for push/pull data transfer.
boolean noPullTransfer = true;
for (Edge chToRes : resourceNode.getInEdges()) {
for (Edge resToCh: chToRes.getSource().getInEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel();
ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch);
// Check if the input resource is outside of the channel scope.
boolean outsideInputResource = false;
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (cm.getResource().equals(srcRes) && cm.isOutside()) {
outsideInputResource = true; // Regarded as pull transfer.
break;
}
}
// Check if the output resource is outside of the channel scope.
boolean outsideOutputResource = false;
for (ChannelMember cm: ch.getOutputChannelMembers()) {
if (resourceNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) {
outsideOutputResource = true; // Regarded as push transfer.
break;
}
}
if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) {
noPullTransfer = false;
}
}
}
// Declare the state field in the parent component.
ResourceHierarchy res = resourceNode.getResourceHierarchy();
if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) {
String resName = getComponentName(res);
FieldDeclaration stateField = new FieldDeclaration(res.getResourceStateType(), toVariableName(resName));
fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateField));
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), new VariableDeclaration(res.getResourceStateType(), toVariableName(resName))));
}
}
// Declare the getter method to obtain the resource state in an ancestor component.
if (component == null) {
// No component is created for this resource.
ResourceNode ancestorNode = resourceNode;
Stack<ResourceNode> ancestors = new Stack<>();
do {
ancestors.push(ancestorNode);
ancestorNode = ancestorNode.getParent();
} while (!generatesComponent(ancestorNode.getResourceHierarchy()));
List<VariableDeclaration> getterParams = new ArrayList<>();
int v = 1;
while (ancestors.size() > 0) {
ResourceNode curAncestor = ancestors.pop();
Expression param = curAncestor.getPrimaryResourcePath().getLastParam();
if (param instanceof Variable) {
Variable var = (Variable) param;
getterParams.add(new VariableDeclaration(var.getType(), var.getName()));
} else if (param instanceof Term) {
Term var = (Term) param;
getterParams.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
String getterName = "get" + getComponentName(resourceNode.getResourceHierarchy());
boolean bExists = false;
for (Map.Entry<ResourceHierarchy, MethodDeclaration> entry: getters) {
ResourceHierarchy r = entry.getKey();
MethodDeclaration m = entry.getValue();
if (r == ancestorNode.getResourceHierarchy() && m.getName().equals(getterName)
&& (m.getParameters() == null ? 0 : m.getParameters().size()) == getterParams.size()) {
bExists = true;
break;
}
}
if (!bExists) {
Type resType = getImplStateType(resourceNode.getResourceHierarchy());
MethodDeclaration stateGetter = null;
if (getterParams.size() == 0) {
stateGetter = new MethodDeclaration(getterName, resType);
} else {
stateGetter = new MethodDeclaration(getterName, false, resType, getterParams);
}
getters.add(new AbstractMap.SimpleEntry<>(ancestorNode.getResourceHierarchy(), stateGetter));
// Declare the accessor method in the main type to call the getter method.
declareAccessorMethodInMainComponent(resourceNode, mainComponent);
}
}
// Declare reference fields for push data transfer.
for (Edge resToCh : resourceNode.getOutEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel();
// Check if the input resource is outside of the channel scope.
boolean outsideInputResource = false;
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (resourceNode.getOutSideResources().contains(cm.getResource()) && cm.isOutside()) {
outsideInputResource = true; // Regarded as pull transfer.
break;
}
}
for (Edge chToRes: re.getDestination().getOutEdges()) {
ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy();
// Check if the output resource is outside of the channel scope.
boolean outsideOutputResource = false;
for (ChannelMember cm: ch.getOutputChannelMembers()) {
if (((ResourceNode) chToRes.getDestination()).getInSideResources().contains(cm.getResource()) && cm.isOutside()) {
outsideOutputResource = true; // Regarded as push transfer.
break;
}
}
if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) {
// Declare a field to refer to the destination resource of push transfer.
if (!generatesComponent(dstRes)) {
dstRes = dstRes.getParent();
}
String dstResName = getComponentName(dstRes);
depends.add(dstRes);
FieldDeclaration dstRefField = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName));
VariableDeclaration dstRefVar = new VariableDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName));
if (component != null) {
// A component is created for this resource.
if (resourceNode.getResourceHierarchy() != dstRes) {
component.addField(dstRefField);
if (!outsideOutputResource) {
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRefVar));
}
}
} else {
// No component is created for this resource.
if (resourceNode.getParent().getResourceHierarchy() != dstRes) {
fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefField));
if (!outsideOutputResource) {
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefVar));
}
}
}
if (outsideOutputResource) {
// When the reference to the destination resource can vary.
if (dstRes.getParent() != null) {
// Reference to root resource.
ResourceHierarchy dstRootRes = dstRes.getRoot();
String dstRootResName = getComponentName(dstRootRes);
FieldDeclaration dstRootRefField = new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName));
VariableDeclaration dstRootRefVar = new VariableDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName));
if (component != null) {
// A component is created for this resource.
component.addField(dstRootRefField);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRootRefVar));
} else {
// No component is created for this resource.
fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefField));
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefVar));
}
}
}
}
}
}
// Declare update methods for push data transfer and reference fields for pull data transfer.
for (Edge chToRes : resourceNode.getInEdges()) {
for (Edge resToCh: chToRes.getSource().getInEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel();
ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch);
// Check if the input resource is outside of the channel scope.
boolean outsideInputResource = false;
for (ChannelMember cm: ch.getInputChannelMembers()) {
if (cm.getResource().equals(srcRes) && cm.isOutside()) {
outsideInputResource = true; // Regarded as pull transfer.
break;
}
}
// Check if the output resource is outside of the channel scope.
boolean outsideOutputResource = false;
ChannelMember out = null;
for (ChannelMember cm: ch.getOutputChannelMembers()) {
if (resourceNode.getInSideResources().contains(cm.getResource())) {
out = cm;
if (cm.isOutside()) {
outsideOutputResource = true; // Regarded as push transfer.
break;
}
}
}
String srcResName = getComponentName(srcRes.getResourceHierarchy());
ResourcePath srcRes2 = srcRes;
String srcResName2 = srcResName;
if (!generatesComponent(srcRes.getResourceHierarchy())) {
srcRes2 = srcRes.getParent();
srcResName2 = getComponentName(srcRes2.getResourceHierarchy());
}
if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) {
// Declare a field to refer to the source resource of pull transfer.
depends.add(srcRes2.getResourceHierarchy());
FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName2, srcResName2), toVariableName(srcResName2));
VariableDeclaration srcRefVar = new VariableDeclaration(new Type(srcResName2, srcResName2), toVariableName(srcResName2));
if (component != null) {
// A component is created for this resource.
if (resourceNode.getResourceHierarchy() != srcRes2.getResourceHierarchy()) {
component.addField(srcRefField);
if (!outsideInputResource) {
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRefVar));
}
}
} else {
// No component is created for this resource.
if (resourceNode.getParent().getResourceHierarchy() != srcRes2.getResourceHierarchy()) {
fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField));
if (!outsideInputResource) {
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefVar));
}
}
}
if (outsideInputResource) {
// When the reference to the source resource can vary.
if (srcRes2.getParent() != null) {
// Reference to its root resource.
ResourcePath srcRootRes = srcRes2.getRoot();
String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy());
FieldDeclaration srcRootRefField = new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName));
VariableDeclaration srcRootRefVar = new VariableDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName));
if (component != null) {
// A component is created for this resource.
component.addField(srcRootRefField);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRootRefVar));
} else {
// No component is created for this resource.
fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefField));
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefVar));
}
}
}
} else {
// Declare an update method in the type of the destination resource.
ArrayList<VariableDeclaration> params = new ArrayList<>();
int v = 1;
for (Expression exp: out.getResource().getPathParams()) {
if (exp instanceof Variable) {
Variable pathVar = (Variable) exp;
String varName = "self" + (v > 1 ? v : "");
// String varName = pathVar.getName();
VariableDeclaration pathParam = new VariableDeclaration(pathVar.getType(), varName);
params.add(pathParam); // A path parameter to identify the self resource.
}
v++;
}
for (Selector selector: ch.getAllSelectors()) {
if (selector.getExpression() instanceof Variable) {
Variable selVar = (Variable) selector.getExpression();
VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName());
params.add(chParam); // A channel parameter to specify the context of the collaboration.
}
}
params.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getLeafResourceName())); // The state of the source resource to carry the data-flow.
for (ResourcePath ref: ch.getReferenceResources()) {
if (!ref.equals(resourceNode.getInSideResource(ch))) {
params.add(new VariableDeclaration(ref.getResourceStateType(), ref.getLeafResourceName()));
}
}
MethodDeclaration update = null;
if (component != null) {
// A component is created for this resource.
update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, params);
component.addMethod(update);
} else {
// No component is created for this resource.
String resourceName = getComponentName(resourceNode.getResourceHierarchy());
String updateMethodName = "update" + resourceName + "From" + srcResName;
Map<String, MethodDeclaration> nameToMethod = updates.get(resourceNode.getParent().getResourceHierarchy());
if (nameToMethod == null) {
nameToMethod = new HashMap<>();
updates.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod);
}
if (nameToMethod.get(updateMethodName) == null) {
update = new MethodDeclaration(updateMethodName, false, typeVoid, params);
nameToMethod.put(updateMethodName, update);
}
}
}
}
}
// Declare a field to refer to outside resources.
if (resourceNode.getParent() == null) {
for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) {
for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) {
if (resourceNode.getResourceHierarchy().equals(dependingRes)) {
// Declare a field to refer to outside resources.
depends.add(dependedRes);
String resName = getComponentName(dependedRes);
FieldDeclaration refField = new FieldDeclaration(new Type(resName, resName), toVariableName(resName));
VariableDeclaration refVar = new VariableDeclaration(new Type(resName, resName), toVariableName(resName));
if (component != null) {
// A component is created for this resource.
component.addField(refField);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refVar));
} else {
// No component is created for this resource.
fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refField));
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refVar));
}
}
}
}
}
// Declare a field to refer to the reference resource.
for (Channel ch : model.getChannels()) {
DataTransferChannel c = (DataTransferChannel) ch;
if (resourceNode.getOutSideResource(c) != null) {
for (ResourcePath res: c.getReferenceResources()) {
if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) {
refs.add(res);
String refResName = getComponentName(res.getResourceHierarchy());
FieldDeclaration refResField = new FieldDeclaration(new Type(refResName, refResName), res.getLeafResourceName());
VariableDeclaration refResVar = new VariableDeclaration(new Type(refResName, refResName), res.getLeafResourceName());
if (component != null) {
// A component is created for this resource.
component.addField(refResField);
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refResVar));
} else {
// No component is created for this resource.
fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResField));
constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResVar));
}
}
}
}
}
// Declare the input method in this component and the main component.
for (Channel ch : model.getInputChannels()) {
for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) {
if (resourceNode.getInSideResources().contains(cm.getResource())) {
Expression message = cm.getStateTransition().getMessageExpression();
if (message instanceof Term) {
// In each resource.
ArrayList<VariableDeclaration> resInputParams = new ArrayList<>();
ArrayList<VariableDeclaration> mainInputParams = new ArrayList<>();
// The path parameters are not to be passed to the input method of each resource (resInputParams)
// because they are always equal to either channel selectors or message parameters.
// Channel parameters to specify the context of the collaboration.
int v = 1;
for (Selector selector: ch.getSelectors()) {
if (selector.getExpression() instanceof Variable) {
Variable selVar = (Variable) selector.getExpression();
resInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName()));
mainInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName()));
} else if (selector.getExpression() instanceof Term) {
Term var = (Term) selector.getExpression();
resInputParams.add(new VariableDeclaration(var.getType(), "v" + v));
mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
if (ch.getParent() != null) {
for (Selector selector: ch.getParent().getAllSelectors()) {
if (selector.getExpression() instanceof Variable) {
Variable selVar = (Variable) selector.getExpression();
mainInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName()));
} else if (selector.getExpression() instanceof Term) {
Term var = (Term) selector.getExpression();
mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
}
// Message parameters to carry the data-flows.
for (Map.Entry<Position, Variable> varEnt: message.getVariables().entrySet()) {
Variable var = varEnt.getValue();
String refVarName = null;
for (ChannelMember refCm: ((DataTransferChannel) ch).getReferenceChannelMembers()) {
Expression varExp = refCm.getStateTransition().getMessageExpression().getSubTerm(varEnt.getKey());
if (varExp != null && varExp instanceof Variable) {
if (refCm.getStateTransition().getCurStateExpression().contains(varExp)) {
refVarName = refCm.getResource().getLeafResourceName();
break;
}
}
}
if (refVarName != null) {
// var has come from a reference resource.
resInputParams.add(new VariableDeclaration(var.getType(), refVarName));
} else {
// var has not come from a reference resource.
resInputParams.add(new VariableDeclaration(var.getType(), var.getName()));
boolean bExists = false;
for (VariableDeclaration mainParam: mainInputParams) {
if (mainParam.getName().equals(var.getName()) ) {
bExists = true;
break;
}
}
if (!bExists) {
mainInputParams.add(new VariableDeclaration(var.getType(), var.getName()));
}
}
}
String inputMethodName = ((Term) message).getSymbol().getImplName();
if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) {
inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy());
}
MethodDeclaration input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams);
if (component != null) {
// A component is created for this resource.
component.addMethod(input);
} else {
// No component is created for this resource.
Map<String, MethodDeclaration> nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy());
if (nameToMethod == null) {
nameToMethod = new HashMap<>();
inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod);
}
if (nameToMethod.get(inputMethodName) == null) {
nameToMethod.put(inputMethodName, input);
}
}
// In the main type.
String messageSymbol = ((Term) message).getSymbol().getImplName();
input = getMethod(mainComponent, messageSymbol, mainInputParams);
if (input == null) {
input = new MethodDeclaration(messageSymbol, false, typeVoid, mainInputParams);
mainComponent.addMethod(input);
} else {
// Add type to a parameter without type.
for (VariableDeclaration param: input.getParameters()) {
if (param.getType() == null) {
for (VariableDeclaration p: mainInputParams) {
if (param.getName().equals(p.getName()) && p.getType() != null) {
param.setType(p.getType());
}
}
}
}
}
} else if (message instanceof Variable) {
// In each resource.
ArrayList<VariableDeclaration> resInputParams = new ArrayList<>();
ArrayList<VariableDeclaration> mainInputParams = new ArrayList<>();
int v = 1;
if (cm.getResource().getLastParam() != null) {
Expression param = cm.getResource().getLastParam();
if (param instanceof Variable) {
Variable var = (Variable) param;
resInputParams.add(new VariableDeclaration(var.getType(), var.getName()));
mainInputParams.add(new VariableDeclaration(var.getType(), var.getName()));
} else if (param instanceof Term) {
Term var = (Term) param;
resInputParams.add(new VariableDeclaration(var.getType(), "v" + v));
mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
if (cm.getResource().getParent() != null) {
for (Expression param: cm.getResource().getParent().getPathParams()) {
if (param instanceof Variable) {
Variable var = (Variable) param;
mainInputParams.add(new VariableDeclaration(var.getType(), var.getName()));
} else if (param instanceof Term) {
Term var = (Term) param;
mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
}
String inputMethodName = ((Variable) message).getName();
if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) {
inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy());
}
MethodDeclaration input = null;
if (resInputParams.size() > 0) {
input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams);
} else {
input = new MethodDeclaration(inputMethodName, false, typeVoid, null);
}
if (component != null) {
// A component is created for this resource.
component.addMethod(input);
} else {
// No component is created for this resource.
Map<String, MethodDeclaration> nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy());
if (nameToMethod == null) {
nameToMethod = new HashMap<>();
inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod);
}
if (nameToMethod.get(inputMethodName) == null) {
nameToMethod.put(inputMethodName, input);
}
}
// In the main type.
String messageSymbol = ((Variable) message).getName();
input = getMethod(mainComponent, messageSymbol, mainInputParams);
if (input == null) {
if (mainInputParams.size() > 0) {
input = new MethodDeclaration(messageSymbol, false, typeVoid, mainInputParams);
} else {
input = new MethodDeclaration(messageSymbol, false, typeVoid, null);
}
mainComponent.addMethod(input);
}
}
}
}
}
}
// Add leaf getter methods to the parent components.
for (Map.Entry<ResourceHierarchy, MethodDeclaration> entry: getters) {
resourceComponents.get(entry.getKey()).addMethod(entry.getValue());
}
// Add leaf update methods to the parent components.
for (Map.Entry<ResourceHierarchy, Map<String, MethodDeclaration>> entry: updates.entrySet()) {
for (MethodDeclaration update: entry.getValue().values()) {
resourceComponents.get(entry.getKey()).addMethod(update);
}
}
// Add leaf input methods to the parent components.
for (Map.Entry<ResourceHierarchy, Map<String, MethodDeclaration>> entry: inputs.entrySet()) {
for (MethodDeclaration input: entry.getValue().values()) {
resourceComponents.get(entry.getKey()).addMethod(input);
}
}
// Add leaf reference fields to the parent components.
for (Map.Entry<ResourceHierarchy, FieldDeclaration> entry: fields) {
boolean existsField = false;
for (FieldDeclaration field: resourceComponents.get(entry.getKey()).getFields()) {
if (field.getName().equals(entry.getValue().getName())) {
existsField = true;
break;
}
}
if (!existsField) {
resourceComponents.get(entry.getKey()).addField(entry.getValue());
}
}
// Add constructor parameters to the ancestor components.
for (ResourceNode root: graph.getRootResourceNodes()) {
addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams);
}
// Declare the Pair class.
boolean isCreatedPair = false;
for (ResourceNode rn : resources) {
if (isCreatedPair) continue;
if (rn.getResourceStateType() != null && model.getType("Pair").isAncestorOf(rn.getResourceStateType())) {
TypeDeclaration type = new TypeDeclaration("Pair<T>");
type.addField(new FieldDeclaration(new Type("Double", "T"), "left"));
type.addField(new FieldDeclaration(new Type("Double", "T"), "right"));
MethodDeclaration constructor = new MethodDeclaration("Pair", true);
constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "left"));
constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "right"));
Block block = new Block();
block.addStatement("this.left = left;");
block.addStatement("this.right = right;");
constructor.setBody(block);
type.addMethod(constructor);
for(FieldDeclaration field : type.getFields()) {
MethodDeclaration getter = new MethodDeclaration(
"get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1),
new Type("Double","T"));
getter.setBody(new Block());
getter.getBody().addStatement("return " + field.getName() + ";");
type.addMethod(getter);
}
CompilationUnit cu = new CompilationUnit(type);
cu.addImport(new ImportDeclaration("java.util.*"));
codes.add(cu);
isCreatedPair = true;
}
}
// HashSet<String> tmps = new HashSet<>();
// HashSet<String> cont = new HashSet<>();
// for (MethodDeclaration method : mainType.getMethods()) {
// if (!tmps.contains(method.getName()))
// tmps.add(method.getName());
// else
// cont.add(method.getName());
// }
// for (MethodDeclaration method : mainType.getMethods()) {
// if (cont.contains(method.getName())) {
// method.setName(method.getName() + method.getParameters().get(0).getName().substring(0, 1).toUpperCase()
// + method.getParameters().get(0).getName().substring(1));
// }
// }
return codes;
}
private static Map<ResourceHierarchy, Set<ResourceHierarchy>> getDependedRootComponentGraph(DataTransferModel model) {
Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedComponentGraph = new HashMap<>();
for (Channel ch: model.getChannels()) {
DataTransferChannel dtCh = (DataTransferChannel) ch;
Set<ResourceHierarchy> inRes = new HashSet<>();
Set<ResourceHierarchy> outRes = new HashSet<>();
for (ChannelMember cm: dtCh.getChannelMembers()) {
if (cm.isOutside()) {
outRes.add(cm.getResource().getResourceHierarchy());
} else {
inRes.add(cm.getResource().getResourceHierarchy());
}
}
if (outRes.size() > 0 && inRes.size() > 0) {
for (ResourceHierarchy out: outRes) {
for (ResourceHierarchy in: inRes) {
Set<ResourceHierarchy> dependings = dependedComponentGraph.get(out.getRoot());
if (dependings == null) {
dependings = new HashSet<>();
dependedComponentGraph.put(out.getRoot(), dependings);
}
dependings.add(in.getRoot());
}
}
}
}
return dependedComponentGraph;
}
static private ArrayList<ResourceNode> determineResourceOrder(DataFlowGraph graph, Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph) {
ArrayList<ResourceNode> resources = new ArrayList<>();
Set<ResourceNode> visited = new HashSet<>();
for (Node n : graph.getResourceNodes()) {
ResourceNode resNode = (ResourceNode) n;
topologicalSort(resNode, graph, dependedRootComponentGraph, visited, resources);
}
return resources;
}
static private void topologicalSort(ResourceNode curResNode, DataFlowGraph graph, Map<ResourceHierarchy, Set<ResourceHierarchy>> dependedRootComponentGraph, Set<ResourceNode> visited, List<ResourceNode> orderedList) {
if (visited.contains(curResNode)) return;
visited.add(curResNode);
// For each incoming PUSH transfer.
for (Edge chToRes: curResNode.getInEdges()) {
for (Edge resToCh: chToRes.getSource().getInEdges()) {
DataFlowEdge re = (DataFlowEdge) resToCh;
if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) {
topologicalSort((ResourceNode) re.getSource(), graph, dependedRootComponentGraph, visited, orderedList);
}
}
}
// For each outgoing PULL transfer.
for (Edge resToCh: curResNode.getOutEdges()) {
DataFlowEdge de = (DataFlowEdge) resToCh;
if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) {
for (Edge chToRes : resToCh.getDestination().getOutEdges()) {
topologicalSort((ResourceNode) chToRes.getDestination(), graph, dependedRootComponentGraph, visited, orderedList);
}
}
}
// For each depending root node.
if (dependedRootComponentGraph.get(curResNode.getResourceHierarchy()) != null) {
for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(curResNode.getResourceHierarchy())) {
for (ResourceNode root: graph.getRootResourceNodes()) {
if (root.getResourceHierarchy().equals(dependingRes)) {
topologicalSort(root, graph, dependedRootComponentGraph, visited, orderedList);
}
}
}
}
// For each reference resource.
for (Node n: graph.getResourceNodes()) {
ResourceNode resNode = (ResourceNode) n;
for (Edge resToCh : resNode.getOutEdges()) {
ChannelNode chNode = (ChannelNode) resToCh.getDestination();
for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) {
if (curResNode.getOutSideResources().contains(m.getResource())) {
topologicalSort(resNode, graph, dependedRootComponentGraph, visited, orderedList);
}
}
}
}
orderedList.add(0, curResNode);
}
private static void declareAccessorMethodInMainComponent(ResourceNode resourceNode, TypeDeclaration mainComponent) {
MethodDeclaration getterAccessor = null;
List<VariableDeclaration> mainGetterParams = new ArrayList<>();
int v = 1;
for (Expression param: resourceNode.getPrimaryResourcePath().getPathParams()) {
if (param instanceof Variable) {
Variable var = (Variable) param;
mainGetterParams.add(new VariableDeclaration(var.getType(), var.getName()));
} else if (param instanceof Term) {
Term var = (Term) param;
mainGetterParams.add(new VariableDeclaration(var.getType(), "v" + v));
}
v++;
}
if (mainGetterParams.size() > 0) {
getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()),
false,
getImplStateType(resourceNode.getResourceHierarchy()),
mainGetterParams);
} else {
getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()),
getImplStateType(resourceNode.getResourceHierarchy()));
}
getterAccessor.setBody(new Block());
Expression getState = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(resourceNode.getPrimaryResourcePath(), null);
getterAccessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";");
mainComponent.addMethod(getterAccessor);
}
private static List<VariableDeclaration> addConstructorParameters(ResourceHierarchy resource,
Map<ResourceHierarchy, TypeDeclaration> resourceComponents,
Map<ResourceHierarchy, MethodDeclaration> resourceConstructors,
List<Entry<ResourceHierarchy, VariableDeclaration>> constructorParams) {
List<VariableDeclaration> params = new ArrayList<>();
for (ResourceHierarchy child: resource.getChildren()) {
params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams));
}
for (Entry<ResourceHierarchy, VariableDeclaration> paramEnt: constructorParams) {
if (paramEnt.getKey().equals(resource)) {
params.add(paramEnt.getValue());
}
}
if (params.size() > 0) {
MethodDeclaration constructor = resourceConstructors.get(resource);
if (constructor == null) {
if (resourceComponents.get(resource) != null) {
String resourceName = getComponentName(resource);
constructor = new MethodDeclaration(resourceName, true);
Block body = new Block();
constructor.setBody(body);
resourceComponents.get(resource).addMethod(constructor);
resourceConstructors.put(resource, constructor);
}
}
if (constructor != null) {
for (VariableDeclaration param: params) {
boolean existsParam = false;
if (constructor.getParameters() != null) {
for (VariableDeclaration constParam: constructor.getParameters()) {
if (constParam.getName().equals(param.getName())) {
existsParam = true;
break;
}
}
}
if (!existsParam) {
constructor.addParameter(param);
constructor.getBody().addStatement("this." + toVariableName(param.getName()) + " = " + toVariableName(param.getName()) + ";");
}
}
}
}
if (resource.getNumParameters() > 0) params.clear();
return params;
}
private static String getInitializer(ResourceHierarchy res) {
Type stateType = res.getResourceStateType();
String initializer = null;
if (res.getInitialValue() != null) {
initializer = res.getInitialValue().toImplementation(new String[] {""});
} else if (stateType != null) {
initializer = DataConstraintModel.getDefaultValue(stateType);
}
return initializer;
}
static public ArrayList<String> getCodes(ArrayList<TypeDeclaration> codeTree) {
ArrayList<String> codes = new ArrayList<>();
for (TypeDeclaration type : codeTree) {
codes.add("public class " + type.getTypeName() + "{");
for (FieldDeclaration field : type.getFields()) {
if (type.getTypeName() != mainTypeName) {
String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " "
+ field.getName();
if (DataConstraintModel.isListType(field.getType()))
cons += " = new ArrayList<>()";
cons += ";";
codes.add(cons);
} else {
String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " "
+ field.getName() + " = new " + field.getType().getTypeName() + "(";
cons += ");";
codes.add(cons);
}
}
codes.add("");
for (MethodDeclaration method : type.getMethods()) {
String varstr = "\t" + "public " + method.getReturnType().getInterfaceTypeName() + " "
+ method.getName() + "(";
if (method.getParameters() != null) {
for (VariableDeclaration var : method.getParameters()) {
varstr += var.getType().getInterfaceTypeName() + " " + var.getName() + ",";
}
if (!method.getParameters().isEmpty())
varstr = varstr.substring(0, varstr.length() - 1);
}
if (method.getBody() != null) {
for (String str : method.getBody().getStatements()) {
codes.add("\t\t" + str + ";");
}
}
codes.add(varstr + ")" + "{");
codes.add("\t" + "}");
codes.add("");
}
codes.add("}");
codes.add("");
}
return codes;
}
private static MethodDeclaration getMethod(TypeDeclaration type, String methodName, List<VariableDeclaration> params) {
for (MethodDeclaration m: type.getMethods()) {
if (m.getName().equals(methodName)) {
if (m.getParameters() == null && (params == null || params.size() == 0)) return m;
if (m.getParameters() != null && params != null && m.getParameters().size() == params.size()) {
boolean matchParams = true;
for (int i = 0; i < m.getParameters().size(); i++) {
if (!m.getParameters().get(i).getType().equals(params.get(i).getType())) {
matchParams = false;
break;
}
}
if (matchParams) return m;
}
}
}
return null;
}
static public IResourceStateAccessor pushAccessor = new IResourceStateAccessor() {
@Override
public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) {
ResourcePath targetRes = target.getResource();
ResourcePath fromRes = from.getResource();
if (targetRes.equals(fromRes)) {
return new Field("value",
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
// use the cached value as the current state
return new Field(targetRes.getLeafResourceName(),
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
@Override
public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) {
ResourcePath targetRes = target.getResource();
return new Parameter(targetRes.getLeafResourceName(),
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
@Override
public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) {
if (fromRes != null && targetRes.equals(fromRes)) {
return new Field("value",
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
// for reference channel member
return new Parameter(targetRes.getLeafResourceName(),
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
};
static public IResourceStateAccessor pullAccessor = new IResourceStateAccessor() {
@Override
public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) {
ResourcePath targetRes = target.getResource();
if (from != null) {
ResourcePath fromRes = from.getResource();
if (!target.isOutside()) {
return getDirectStateAccessorFor(targetRes, fromRes);
}
Term getter = null;
String targetComponentName = getComponentName(targetRes.getResourceHierarchy());
if (generatesComponent(targetRes.getResourceHierarchy())) {
getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD));
getter.addChild(new Field(toVariableName(targetComponentName), targetRes.getResourceStateType()));
} else {
String parentName = toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent()));
Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType();
getter = new Term(new Symbol("get" + targetComponentName, 1, Symbol.Type.METHOD));
getter.addChild(new Field(parentName, parentType));
}
return getter;
} else {
return getDirectStateAccessorFor(targetRes, null);
}
}
@Override
public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) {
ResourcePath targetRes = target.getResource();
if (from != null) {
ResourcePath fromRes = from.getResource();
if (!target.isOutside()) {
return getDirectStateAccessorFor(targetRes, fromRes);
}
Term getter = null;
String targetComponentName = getComponentName(targetRes.getResourceHierarchy());
if (generatesComponent(targetRes.getResourceHierarchy())) {
getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD));
getter.addChild(new Field(toVariableName(targetComponentName), targetRes.getResourceStateType()));
} else {
String parentName = toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent()));
Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType();
getter = new Term(new Symbol("get" + targetComponentName, 1, Symbol.Type.METHOD));
getter.addChild(new Field(parentName, parentType));
}
return getter;
} else {
return getDirectStateAccessorFor(targetRes, null);
}
}
@Override
public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) {
if (fromRes != null) {
if (targetRes.equals(fromRes)) {
return new Field("value",
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
// for reference channel member
Term getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD));
getter.addChild(new Field(targetRes.getLeafResourceName(), targetRes.getResourceStateType()));
return getter;
} else {
// access from the outside of the hierarchy
Stack<ResourcePath> pathStack = new Stack<>();
ResourcePath curPath = targetRes;
do {
pathStack.push(curPath);
curPath = curPath.getParent();
} while (curPath != null);
// iterate from the root resource
Term getter = null;
int v = 1;
int arity = 2;
while (!pathStack.empty()) {
curPath = pathStack.pop();
String typeName = getComponentName(curPath.getResourceHierarchy());
if (getter == null) {
// root resource
String fieldName = toVariableName(typeName);
getter = new Field(fieldName, new Type(typeName, typeName));
} else {
if (generatesComponent(curPath.getResourceHierarchy())) {
if (arity == 2) {
Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD));
newGetter.addChild(getter);
if (curPath.getResourceHierarchy().getNumParameters() > 0) {
Variable var = null;
Expression param = curPath.getLastParam();
if (param instanceof Variable) {
var = (Variable) param;
} else if (param instanceof Term) {
var = new Variable("v" + v, ((Term) param).getType());
}
if (var != null) {
newGetter.addChild(var);
newGetter.getSymbol().setArity(2);
}
v++;
}
getter = newGetter;
} else {
if (curPath.getResourceHierarchy().getNumParameters() > 0) {
Variable var = null;
Expression param = curPath.getLastParam();
if (param instanceof Variable) {
var = (Variable) param;
} else if (param instanceof Term) {
var = new Variable("v" + v, ((Term) param).getType());
}
if (var != null) {
getter.getSymbol().setArity(arity);
getter.addChild(var);
}
v++;
}
}
arity = 2;
} else {
// to get a descendant resource directly.
if (arity == 2) {
Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD));
newGetter.addChild(getter);
getter = newGetter;
}
if (curPath.getResourceHierarchy().getNumParameters() > 0) {
Variable var = null;
Expression param = curPath.getLastParam();
if (param instanceof Variable) {
var = (Variable) param;
} else if (param instanceof Term) {
var = new Variable("v" + v, ((Term) param).getType());
}
if (var != null) {
getter.getSymbol().setArity(arity);
getter.addChild(var);
arity++;
}
v++;
}
}
}
}
if (generatesComponent(targetRes.getResourceHierarchy())) {
Term newGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD));
newGetter.addChild(getter);
getter = newGetter;
}
return getter;
}
}
};
static public IResourceStateAccessor refAccessor = new IResourceStateAccessor() {
@Override
public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) {
ResourcePath targetRes = target.getResource();
ResourcePath fromRes = from.getResource();
if (targetRes.equals(fromRes)) {
return new Field("value",
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
// for reference channel member
return new Parameter(targetRes.getLeafResourceName(),
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
@Override
public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) {
ResourcePath targetRes = target.getResource();
return new Parameter(targetRes.getLeafResourceName(),
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
@Override
public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) {
if (fromRes != null && targetRes.equals(fromRes)) {
return new Field("value",
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
// for reference channel member
return new Parameter(targetRes.getLeafResourceName(),
targetRes.getResourceStateType() != null ? targetRes.getResourceStateType()
: DataConstraintModel.typeInt);
}
};
}