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().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) { if (DataConstraintModel.typeList.isAncestorOf(stateType)) { initializer = "new " + res.getResourceStateType().getImplementationTypeName() + "()"; } else if (DataConstraintModel.typeMap.isAncestorOf(stateType)) { initializer = "new " + res.getResourceStateType().getImplementationTypeName() + "()"; } } 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); } }; }