diff --git a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model index 6d4cb43..b105544 100644 --- a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model +++ b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model @@ -2,15 +2,17 @@ screenTemplates := { "000": {"widgets": {"001": {"type": "textInput", "text": "", "state": 0, "visible": true}, "002": {"type": "button", "text": "Next", "state": 0, "visible": true}}, - "layout": true}, + "layout": true, + "screenId": "000"}, "001": {"widgets": {"003": {"type": "label", "text": "label", "state": 0, "visible": true}, "004": {"type": "button", "text": "Back", "state": 0, "visible": true}}, - "layout": true} + "layout": true, + "screenId": "001"} } } native channel ScreenUpdate { - in screen(curSc: Json, update(curSc, nextSc)) = nextSc + in screen(curSc: Json, screenUpdate(curSc, nextSc)) = nextSc } native channel SetLayout { diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java index 2b4f654..844691d 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java @@ -2,31 +2,88 @@ import java.util.List; import java.util.ArrayList; +import java.util.stream.Collectors; -public class Block extends ASTNode { - private List statements = new ArrayList(); +public class Block extends Statement { + private List statements = new ArrayList(); - public List getStatements() { + public List getStatements2() { return statements; } - public void setStatements(List statements) { + public void setStatements(List statements) { this.statements = statements; } - public void addFirstStatement(String statement) { + public void addFirstStatement(Statement statement) { statements.add(0, statement); } - - public void addStatement(String statement) { + + public void addStatement(Statement statement) { statements.add(statement); } - - public String toString() { - String code = ""; - for (String statement: statements) { - code += (statement + "\n"); + + public void addFirstStatements(List statements) { + this.statements.addAll(0, statements); + } + + public void addStatements(List statements) { + this.statements.addAll(statements); + } + + //==================================================== + //TODO: CodeGenerator修正後削除 + + public List getStatements() { + List strings = new ArrayList<>(); + for (Statement stmt : statements) { + if (stmt != null) { + strings.add(stmt.toString()); + } } - return code; + return strings; + } + + public void addFirstStatement(String code) { + if (code != null) { + this.addFirstStatement(new Statement() { + @Override + public String toString() { + return code; + } + }.toString()); + } + } + + public void addStatement(String code) { + if (code != null) { + this.addStatement(new PlainStatement(code)); + } + } + + //==================================================== + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{\n"); + + for (Statement statement : statements) { + if (statement != null) { + String content = statement.toString(); + + // split statement + String[] lines = content.split("\n"); + + // Tab + for (String line : lines) { + sb.append("\t").append(line).append("\n"); + } + } + } + + sb.append("}"); + return sb.toString(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java new file mode 100644 index 0000000..e1d1b42 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java @@ -0,0 +1,22 @@ +package code.ast; + +public class EnhancedForStatement extends Statement { + + private VariableDeclaration singleVariableDeclaration; + private Statement expression; + private Statement body; + + public VariableDeclaration getParameter() { return singleVariableDeclaration; } + public void setParameter(VariableDeclaration parameter) { this.singleVariableDeclaration = parameter; } + + public Statement getExpression() { return expression; } + public void setExpression(Statement expression) { this.expression = expression; } + + public Statement getBody() { return body; } + public void setBody(Statement body) { this.body = body; } + + @Override + public String toString() { + return "for (" + singleVariableDeclaration + " : " + expression + ") " + body; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java new file mode 100644 index 0000000..1d23a01 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java @@ -0,0 +1,13 @@ +package code.ast; + +public class ExpressionStatement extends Statement{ + private Statement expression; + + public Statement getExpression() { return expression; } + public void setExpression(Statement expression) { this.expression = expression; } + + @Override + public String toString() { + return expression + ";"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java index 0993b92..cedf1a4 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java @@ -9,7 +9,8 @@ public class FieldDeclaration extends BodyDeclaration implements IAnnotatable { private Type type; private String fieldName; - private String initializer; + private String initializer = null; + private String initializationBlock = null; private Map annotations = new HashMap<>(); public FieldDeclaration(Type type, String fieldName) { @@ -47,6 +48,14 @@ this.initializer = initializer; } + public String getInitializationBlock() { + return initializationBlock; + } + + public void setInitializationBlock(String initializationBlock) { + this.initializationBlock = initializationBlock; + } + @Override public Annotation getAnnotation(String name) { return annotations.get(name); @@ -67,10 +76,14 @@ for (Annotation annotation: getAnnotations()) { code += annotation.toString() + "\n"; } - if (initializer == null) { - code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n"; + if (initializationBlock != null) { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n" + initializationBlock + "\n"; } else { - code += "private " + type.getInterfaceTypeName() + " " + fieldName + " = " + initializer + ";\n"; + if (initializer == null) { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n"; + } else { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + " = " + initializer + ";\n"; + } } return code; } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java new file mode 100644 index 0000000..bf736a5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java @@ -0,0 +1,69 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; + +public class ForStatement extends Statement { + + private List initializers = new ArrayList<>(); + private Statement condition; + private List updaters = new ArrayList<>(); + private Statement body; + + public List getInitializers() { + return initializers; + } + + public void setInitializers(List initializers) { + this.initializers = initializers; + } + + public Statement getCondition() { + return condition; + } + + public void setCondition(Statement condition) { + this.condition = condition; + } + + public List getUpdaters() { + return updaters; + } + + public void setUpdaters(List updaters) { + this.updaters = updaters; + } + + public Statement getBody() { + return body; + } + + public void setBody(Statement body) { + this.body = body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("for ("); + + for (int i = 0; i < initializers.size(); i++) { + sb.append(initializers.get(i)); + if (i < initializers.size() - 1) sb.append(", "); + } + sb.append("; "); + + if (condition != null) sb.append(condition); + sb.append("; "); + + for (int i = 0; i < updaters.size(); i++) { + sb.append(updaters.get(i)); + if (i < updaters.size() - 1) sb.append(", "); + } + sb.append(") "); + + if (body != null) sb.append(body); + + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java new file mode 100644 index 0000000..e7521f1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java @@ -0,0 +1,43 @@ +package code.ast; + +public class IfStatement extends Statement { + + private Statement expression; + private Statement thenStatement; + private Statement elseStatement; + + public Statement getExpression() { + return expression; + } + + public void setExpression(Statement expression) { + this.expression = expression; + } + + public Statement getThenStatement() { + return thenStatement; + } + + public void setThenStatement(Statement thenStatement) { + this.thenStatement = thenStatement; + } + + public Statement getElseStatement() { + return elseStatement; + } + + public void setElseStatement(Statement elseStatement) { + this.elseStatement = elseStatement; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("if (").append(expression).append(") "); + sb.append(thenStatement); + if (elseStatement != null) { + sb.append(" else ").append(elseStatement); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java index 5f5aafc..b541ce6 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java @@ -142,21 +142,18 @@ } code += (name + "("); if (parameters != null) { - String delimitar = ""; - for (VariableDeclaration parameter: parameters) { - code = code + delimitar + parameter.toString(); - delimitar = ", "; + for (int i = 0; i < parameters.size(); i++) { + code += parameters.get(i).toString(); + if (i < parameters.size() - 1) code += ", "; } } code += ") "; - if (thrws != null) { - code += thrws.toString() + " "; - } - code += "{\n"; + if (body != null) { - code += CodeUtil.insertTab(body.toString()); + code += body.toString(); + } else { + code += ";"; } - code += "}"; return code; } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java new file mode 100644 index 0000000..edc9ff5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java @@ -0,0 +1,18 @@ +package code.ast; + +//==================================================== +//TODO: CodeGenerator修正後削除 +//==================================================== + +public class PlainStatement extends Statement { + private String code; + + public PlainStatement(String code) { + this.code = code; + } + + @Override + public String toString() { + return code; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java new file mode 100644 index 0000000..501cd26 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java @@ -0,0 +1,21 @@ +package code.ast; + +public class ReturnStatement extends Statement{ + private Statement expression; + + public Statement getExpression() { + return expression; + } + + public void setExpression(Statement expression) { + this.expression = expression; + } + + @Override + public String toString() { + if (expression != null) { + return "return " + expression + ";"; + } + return "return;"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java new file mode 100644 index 0000000..96d1af1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java @@ -0,0 +1,7 @@ +package code.ast; + +public abstract class Statement extends ASTNode { + + @Override + public abstract String toString(); +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java new file mode 100644 index 0000000..0348fce --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java @@ -0,0 +1,56 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; + +public class VariableDeclarationStatement extends Statement { + + private List modifiers = new ArrayList<>(); + private Type type; + private List fragments = new ArrayList<>(); + + public List getModifiers() { + return modifiers; + } + + public void setModifiers(List modifiers) { + this.modifiers = modifiers; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getFragments() { + return fragments; + } + + public void setFragments(List fragments) { + this.fragments = fragments; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + for (Statement mod : modifiers) { + sb.append(mod.toString()).append(" "); + } + + if (type != null) { + sb.append(type.toString()).append(" "); + } + + for (int i = 0; i < fragments.size(); i++) { + sb.append(fragments.get(i).getName()); + if (i < fragments.size() - 1) sb.append(", "); + } + + sb.append(";"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java new file mode 100644 index 0000000..be37a35 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java @@ -0,0 +1,33 @@ +package code.ast; + +public class WhileStatement extends Statement { + + private Statement expression; + private Statement body; + + public Statement getExpression() { + return expression; + } + + public void setExpression(Statement expression) { + this.expression = expression; + } + + public Statement getBody() { + return body; + } + + public void setBody(Statement body) { + this.body = body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("while (").append(expression).append(") "); + if (body != null) { + sb.append(body); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 7b819b4..37bf0f2 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -57,10 +57,13 @@ public static final String updateMethodPrefix = "update"; public static final String from = "From"; public static final String _for = "For"; + public static final String presenter = "presenter"; + public static final Type presenterType = new Type("SwingPresenter", "SwingPresenter"); private static String mainTypeName = null; - private static ILanguageSpecific langSpec = null; - private static IPlatformSpecific platformSpec = null; private static HashMap> componentNames = new HashMap<>(); + protected Map>> updateMethods; + protected ILanguageSpecific langSpec = null; + protected IPlatformSpecific platformSpec = null; public CodeGenerator() { componentNames.clear(); @@ -158,8 +161,9 @@ * @return source codes */ public ArrayList generateCode(DataTransferModel model, DataFlowGraph flowGraph, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - CodeGenerator.langSpec = langSpec; - CodeGenerator.platformSpec = platformSpec; + this.langSpec = langSpec; + this.platformSpec = platformSpec; + this.updateMethods = new HashMap<>(); ArrayList codes = new ArrayList<>(); Map> dependedRootComponentGraph = null; @@ -178,13 +182,12 @@ } // Generate the other components. - generateCodeFromFlowGraph(model, flowGraph, components, codes, dependedRootComponentGraph, platformSpec, langSpec); + generateCodeFromFlowGraph(model, flowGraph, components, codes, dependedRootComponentGraph); return codes; } - public abstract void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, - Map> dependedRootComponentGraph, IPlatformSpecific platformSpec, ILanguageSpecific langSpec); + public abstract void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, Map> dependedRootComponentGraph); private static Map> getDependedRootComponentGraph(DataTransferModel model) { Map> dependedComponentGraph = new HashMap<>(); @@ -298,8 +301,7 @@ orderedList.add(0, curResNode); } - protected void updateMainComponent(TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, - MethodDeclaration constructor, final List depends, ILanguageSpecific langSpec) { + protected void updateMainComponent(TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, MethodDeclaration constructor, final List depends) { // Declare the field to refer to each object in the main type. ResourceNode resNode = null; String nodeName = null; @@ -352,7 +354,7 @@ return dstRes; } - protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType) { // returns the state field when all incoming data-flow edges are PUSH-style. if (langSpec.isValueType(resStateType)) { stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; @@ -388,7 +390,7 @@ composerSub.setType(DataConstraintModel.typeMap); for (ResourceHierarchy child: resourceHierarchy.getChildren()) { String childTypeName = getComponentName(child, langSpec); - String fieldName = langSpec.toVariableName(childTypeName); + String fieldName = child.getResourceName(); Term childGetter = null; if (!generatesComponent(child)) { // the child is not a class @@ -420,7 +422,7 @@ } protected void fillDescendantGetterMethod(MethodDeclaration descendantGetter, ResourceHierarchy descendant, - ResourceHierarchy child, ResourceHierarchy ancestor, TypeDeclaration ancestorComponent, ILanguageSpecific langSpec) { + ResourceHierarchy child, ResourceHierarchy ancestor, TypeDeclaration ancestorComponent) { // (#4) descendant getter method (the implementation must be kept consistent with #3) Expression selector; if (DataConstraintModel.typeList.isAncestorOf(ancestor.getResourceStateType())) { @@ -428,7 +430,7 @@ } else if (DataConstraintModel.typeMap.isAncestorOf(ancestor.getResourceStateType())) { selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); } else { - String fieldName = langSpec.toVariableName(getComponentName(child, langSpec)); + String fieldName = child.getResourceName(); selector = new Variable(langSpec.getFieldAccessor(fieldName)); } if (descendantGetter.getParameters() != null) { @@ -454,7 +456,7 @@ } } - protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourceNode accessRes, MethodDeclaration stateGetter, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourceNode accessRes, MethodDeclaration stateGetter) { List mainGetterParams = new ArrayList<>(); int v = 1; for (Expression param: accessRes.getPrimaryResourcePath().getPathParams()) { @@ -494,8 +496,7 @@ mainComponent.addMethod(accessor); } - protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, - final List depends, ILanguageSpecific langSpec) { + protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, final List depends) { Set refs = new HashSet<>(); for (Channel ch : model.getChannels()) { DataTransferChannel c = (DataTransferChannel) ch; @@ -513,6 +514,28 @@ } } + protected String getUpdateMethodName(ResourceHierarchy srcRes, ResourceHierarchy dstRes, DataTransferChannel ch) { + Map> dstResUpdatesMethods = updateMethods.getOrDefault(dstRes, new HashMap<>()); + updateMethods.put(dstRes, dstResUpdatesMethods); + Map dstResFromSrcResUpdatesMethods = dstResUpdatesMethods.getOrDefault(srcRes, new HashMap<>()); + dstResUpdatesMethods.put(srcRes, dstResFromSrcResUpdatesMethods); + String updateMethodName = dstResFromSrcResUpdatesMethods.get(ch); + if (updateMethodName == null) { + String srcResComponentName = getComponentName(srcRes, langSpec); + String dstResComponentName = getComponentName(dstRes, langSpec); + if (generatesComponent(dstRes)) { + updateMethodName = updateMethodPrefix + from + srcResComponentName; + } else if (dstRes.getParent() != null) { + updateMethodName = updateMethodPrefix + dstResComponentName + from + srcResComponentName; + } + if (dstResFromSrcResUpdatesMethods.size() > 0) { + updateMethodName += dstResFromSrcResUpdatesMethods.size() + 1; // To avoid declaring the method multiply. + } + dstResFromSrcResUpdatesMethods.put(ch, updateMethodName); + } + return updateMethodName; + } + protected MethodDeclaration getConstructor(TypeDeclaration component) { for (MethodDeclaration m: component.getMethods()) { if (m.isConstructor()) return m; @@ -855,7 +878,23 @@ } return decoded; } - + + protected void setFieldInitializer(FieldDeclaration field, Type type, Expression initialValue) { + String initializer = null; + if (initialValue != null) { + String sideEffects[] = new String[]{""}; + initializer = initialValue.toImplementation(sideEffects); + if (sideEffects[0] == null || sideEffects[0].length() == 0) { + field.setInitializer(initializer); + } else { + field.setInitializationBlock("{\n" + sideEffects[0] + field.getName() + " = " + initializer + ";\n" + "}\n"); + } + } else if (type != null) { + initializer = DataConstraintModel.getDefaultValue(type); + field.setInitializer(initializer); + } + } + protected IResourceStateAccessor getPushAccessor(IPlatformSpecific platformSpec) { if (platformSpec.isMonolithic()) { return new IResourceStateAccessor() { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index d8f4ae2..4237555 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -57,14 +57,16 @@ import models.dataFlowModel.ChannelNode; import models.dataFlowModel.StoreAttribute; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import simulator.ResourceIdentifier; public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { + protected Map resourceHierarchyToComponent; + protected Map> constructorParams; - public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, - Map> dependedRootComponentGraph, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - Map resHierarchyToComponent = new HashMap<>(); + public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, Map> dependedRootComponentGraph) { + resourceHierarchyToComponent = new HashMap<>(); + constructorParams = new HashMap<>(); Map resourceConstructors = new HashMap<>(); - Map> constructorParams = new HashMap<>(); List> constructorStatements = new ArrayList<>(); Map>> updateStatements = new HashMap<>(); Map> descendantGetters = new HashMap<>(); @@ -91,7 +93,7 @@ // A component will be generated for this resource. String resourceName = getComponentName(resourceHierarchy, langSpec); Type resStateType = getImplStateType(resourceHierarchy, langSpec); - component = resHierarchyToComponent.get(resourceHierarchy); + component = resourceHierarchyToComponent.get(resourceHierarchy); List depends = new ArrayList<>(); if (component == null) { // Add compilation unit for this component. @@ -100,7 +102,7 @@ // For each root node, add component annotations. ((RestApiSpecific) platformSpec).addComponentAnnotations(component, resourceNode.getResourceName()); } - resHierarchyToComponent.put(resourceHierarchy, component); + resourceHierarchyToComponent.put(resourceHierarchy, component); CompilationUnit cu = langSpec.newCompilationUnit(component); if (!platformSpec.isMonolithic() && resourceHierarchy.getParent() == null) { // For each root node, add platform specific imports. @@ -112,16 +114,16 @@ // For monolithic applications (components are tightly coupled and must be built together). // Declare the constructor. - MethodDeclaration constructor = declareConstructor(resourceNode, component, dependedRootComponentGraph, depends, langSpec); + MethodDeclaration constructor = declareConstructor(resourceNode, component, dependedRootComponentGraph, depends); if (platformSpec.hasMain() && resourceHierarchy.getParent() == null) { // For each root resource // Update the main component for this component. - updateMainComponent(mainComponent, mainConstructor, componentNode, constructor, depends, langSpec); + updateMainComponent(mainComponent, mainConstructor, componentNode, constructor, depends); } // Declare the fields to refer to reference resources. - declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); + declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends); if (constructor.getParameters() == null || constructor.getParameters().size() == 0) { component.removeMethod(constructor); @@ -132,23 +134,23 @@ // Declare the field to store the state in this resource. if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - declareStateField(resourceNode, resourceName, component, resStateType, constructorParams, langSpec); + declareStateField(resourceNode, resourceName, component, resStateType); } // Declare the getter method in this resource to obtain the state. - MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType, platformSpec, langSpec); + MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType); // Declare the accessor method in the main component to call the getter method. if (platformSpec.hasMain()) { - declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, platformSpec, langSpec); + declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter); } } if (component != null) { - if (resHierarchyToComponent.get(resourceHierarchy) == null) { - resHierarchyToComponent.put(resourceHierarchy, component); + if (resourceHierarchyToComponent.get(resourceHierarchy) == null) { + resourceHierarchyToComponent.put(resourceHierarchy, component); } // (#1) Declare the getter methods in this resource to obtain the descendant resources. (complementary to #2) - declareDescendantGetterMethods(resourceNode, component, descendantGetters, langSpec); + declareDescendantGetterMethods(resourceNode, component, descendantGetters); } } } @@ -166,16 +168,16 @@ TypeDeclaration parentComponent = null; TypeDeclaration rootComponent = null; if (generatesComponent(resourceHierarchy)) { - component = resHierarchyToComponent.get(resourceHierarchy); + component = resourceHierarchyToComponent.get(resourceHierarchy); } if (resourceHierarchy.getParent() != null) { - parentComponent = resHierarchyToComponent.get(resourceHierarchy.getParent()); + parentComponent = resourceHierarchyToComponent.get(resourceHierarchy.getParent()); } - rootComponent = resHierarchyToComponent.get(resourceHierarchy.getRoot()); + rootComponent = resourceHierarchyToComponent.get(resourceHierarchy.getRoot()); // Declare cache fields and update methods in this resource, and an update accessor method in the type of root resource. Map.Entry, Map>>> initStatementsAndUpdateUpdates - = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, rootComponent, platformSpec, langSpec); + = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, rootComponent); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndUpdateUpdates.getKey()) { @@ -189,27 +191,27 @@ } // Declare the fields to refer to other resources for push/pull transfer in the parent/this component, and the state field in the parent component. - declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent, constructorParams, platformSpec, langSpec); + declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent); // (#2) Declare the getter method to obtain the resource state in an ancestor resource. (complementary to #1) if (component == null) { - MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resHierarchyToComponent, resStateType, platformSpec, langSpec); + MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resStateType); if (stateGetter != null && platformSpec.hasMain()) { // Declare the accessor method in the main component to call the getter method. - declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, platformSpec, langSpec); + declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter); } } if (!platformSpec.isMonolithic() && !generatedResources.contains(resourceHierarchy)) { // Declare the getter accessor in the root resource. - declareGetterAccessorInTheRootResource(resourceNode, rootComponent, platformSpec, langSpec); + declareGetterAccessorInTheRootResource(resourceNode, rootComponent); } // Declare input methods in this component and the main component. if (!generatedResources.contains(resourceHierarchy)) { Map.Entry, Map>>> initStatementsAndInputUpdates - = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, rootComponent, model, priorMemberForInputChannel, platformSpec, langSpec); + = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, rootComponent, model, priorMemberForInputChannel); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndInputUpdates.getKey()) { @@ -228,7 +230,7 @@ // Add constructor parameters to the ancestor components. for (ResourceNode root: flowGraph.getRootResourceNodes()) { - addConstructorParameters(root.getResourceHierarchy(), resHierarchyToComponent, resourceConstructors, constructorParams, langSpec); + addConstructorParameters(root.getResourceHierarchy(), resourceConstructors); } // Add constructor statements. @@ -241,8 +243,8 @@ Expression updateExp = updateStatements.get(method).getKey(); ResourceHierarchy resource = updateStatements.get(method).getValue().getKey(); ResourceHierarchy descendantRes = updateStatements.get(method).getValue().getValue(); - TypeDeclaration descendantComponent = resHierarchyToComponent.get(descendantRes); - addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, resource, descendantRes, descendantComponent, langSpec); + TypeDeclaration descendantComponent = resourceHierarchyToComponent.get(descendantRes); + addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, resource, descendantRes, descendantComponent); } } @@ -279,11 +281,10 @@ } } - private static List addConstructorParameters(ResourceHierarchy resource, Map resourceComponents, - Map resourceConstructors, Map> constructorParams, ILanguageSpecific langSpec) { + private List addConstructorParameters(ResourceHierarchy resource, Map resourceConstructors) { List params = new ArrayList<>(); for (ResourceHierarchy child: resource.getChildren()) { - params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams, langSpec)); + params.addAll(addConstructorParameters(child, resourceConstructors)); } if (constructorParams.get(resource) != null) { for (VariableDeclaration param: constructorParams.get(resource).values()) { @@ -293,12 +294,12 @@ if (params.size() > 0) { MethodDeclaration constructor = resourceConstructors.get(resource); if (constructor == null) { - if (resourceComponents.get(resource) != null) { + if (resourceHierarchyToComponent.get(resource) != null) { String resourceName = getComponentName(resource, langSpec); constructor = langSpec.newMethodDeclaration(resourceName, true, null, null); Block body = new Block(); constructor.setBody(body); - resourceComponents.get(resource).addMethod(constructor); + resourceHierarchyToComponent.get(resource).addMethod(constructor); resourceConstructors.put(resource, constructor); } } @@ -317,13 +318,13 @@ constructor.addParameter(param); constructor.getBody().addStatement(langSpec.getFieldAccessor(langSpec.toVariableName(param.getName())) + langSpec.getAssignment() + langSpec.toVariableName(param.getName()) + langSpec.getStatementDelimiter()); boolean existsField = false; - for (FieldDeclaration field: resourceComponents.get(resource).getFields()) { + for (FieldDeclaration field: resourceHierarchyToComponent.get(resource).getFields()) { if (field.getName().equals(param.getName())) { existsField = true; } } if (!existsField) { - resourceComponents.get(resource).addField(langSpec.newFieldDeclaration(param.getType(), param.getName())); + resourceHierarchyToComponent.get(resource).addField(langSpec.newFieldDeclaration(param.getType(), param.getName())); } } } @@ -333,7 +334,7 @@ return params; } - private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy resource, ResourceHierarchy descendantRes, TypeDeclaration descendantComponent, ILanguageSpecific langSpec) { + private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy resource, ResourceHierarchy descendantRes, TypeDeclaration descendantComponent) { // Replace each json term in exp with the corresponding constructor invocation. Type replacedJsonType = descendantRes.getResourceStateType(); String replacingClassName = getComponentName(descendantRes, langSpec); @@ -415,8 +416,7 @@ method.addStatement(updateStatement); } - private MethodDeclaration declareConstructor(ResourceNode resourceNode, TypeDeclaration component, Map> dependedRootComponentGraph, - List depends, ILanguageSpecific langSpec) { + private MethodDeclaration declareConstructor(ResourceNode resourceNode, TypeDeclaration component, Map> dependedRootComponentGraph, List depends) { // Declare a constructor in each component. String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); MethodDeclaration constructor = langSpec.newMethodDeclaration(resourceName, true, null, null); @@ -513,11 +513,12 @@ return constructor; } - private void declareStateField(ResourceNode resourceNode, String resourceName, TypeDeclaration component, Type resStateType, Map> constructorParams, ILanguageSpecific langSpec) { + private void declareStateField(ResourceNode resourceNode, String resourceName, TypeDeclaration component, Type resStateType) { Set children = resourceNode.getResourceHierarchy().getChildren(); if (children == null || children.size() == 0) { // leaf resource. - FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue())); + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState); + setFieldInitializer(stateField, resStateType, resourceNode.getResourceHierarchy().getInitialValue()); component.addField(stateField); // Add a parameter to initialize the state field to the constructor. // Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); @@ -533,7 +534,8 @@ ResourceHierarchy child = children.iterator().next(); if (children.size() == 1 && child.getNumParameters() > 0) { // map or list. - FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue())); + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState); + setFieldInitializer(stateField, resStateType, resourceNode.getResourceHierarchy().getInitialValue()); component.addField(stateField); } else { // class @@ -543,7 +545,7 @@ if (generatesComponent(c)) { // The child has a component. childType = new Type(childTypeName, childTypeName); - String fieldName = langSpec.toVariableName(childTypeName); + String fieldName = c.getResourceName(); FieldDeclaration stateField = langSpec.newFieldDeclaration(childType, fieldName, langSpec.getConstructorInvocation(childTypeName, new ArrayList<>())); component.addField(stateField); } @@ -552,8 +554,7 @@ } } - private void declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, - Map> constructorParams, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private void declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent) { // Declare reference fields for push data transfer. boolean noPullTransfer = true; for (Edge resToCh : resourceNode.getOutEdges()) { @@ -889,8 +890,7 @@ } - private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType) { // Declare the getter method of the resource state. MethodDeclaration stateGetter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { @@ -901,10 +901,10 @@ boolean hasDescendantIn = hasDescendantInput(resourceNode); if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { - fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType, platformSpec, langSpec); + fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType); } else { // invocations to other getter methods when at least one incoming data-flow edges is PULL-style. - if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec)) { + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode)) { // Declare a client field to connect to the destination resource of push transfer. if (!((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); @@ -915,8 +915,7 @@ return stateGetter; } - private MethodDeclaration declareStateGetterMethodInAncestor(ResourceNode resourceNode, Map resourceComponents, Type resStateType, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private MethodDeclaration declareStateGetterMethodInAncestor(ResourceNode resourceNode, Type resStateType) { // Search an ancestor in which the getter method is declared. ResourceNode ancestorNode = resourceNode; ResourceNode childNode = null; @@ -926,7 +925,7 @@ childNode = ancestorNode; ancestorNode = ancestorNode.getParent(); } while (!generatesComponent(ancestorNode.getResourceHierarchy())); - TypeDeclaration ancestorComponent = resourceComponents.get(ancestorNode.getResourceHierarchy()); + TypeDeclaration ancestorComponent = resourceHierarchyToComponent.get(ancestorNode.getResourceHierarchy()); List getterParams = new ArrayList<>(); int v = 1; while (ancestors.size() > 0) { @@ -961,9 +960,9 @@ boolean hasDescendantIn = hasDescendantInput(resourceNode); if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { - fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), childNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent, langSpec); + fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), childNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent); } else { - if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec)) { + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode)) { // Declare a client field to connect to the destination resource of push transfer. if (ancestorComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(ancestorComponent)) { ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(ancestorComponent); @@ -989,8 +988,7 @@ return hasDescendantIn; } - private boolean addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private boolean addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode) { boolean bDeclareClientField = false; try { // Data transfer on the same channel hierarchy. @@ -1286,7 +1284,7 @@ return bDeclareClientField; } - private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters, ILanguageSpecific langSpec) { + private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters) { // Declare the getter methods in this resource to obtain descendant resources. Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); if (descendants == null) { @@ -1324,7 +1322,7 @@ descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, false, descendantType, params); } - fillDescendantGetterMethod(descendantGetter, descendant.getResourceHierarchy(), child.getResourceHierarchy(), resourceNode.getResourceHierarchy(), component, langSpec); + fillDescendantGetterMethod(descendantGetter, descendant.getResourceHierarchy(), child.getResourceHierarchy(), resourceNode.getResourceHierarchy(), component); component.addMethod(descendantGetter); } break; @@ -1334,10 +1332,9 @@ } } - private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, - TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods( + ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent) { // Declare cash fields and update methods in the component. - String resComponentName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); List constructorStatements = new ArrayList<>(); Map>> updateStatements = new HashMap<>(); for (Edge chToRes: resourceNode.getInEdges()) { @@ -1360,8 +1357,7 @@ ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); - String srcResComponentName = getComponentName(srcResPath.getResourceHierarchy(), langSpec); - String srcResName = langSpec.toVariableName(srcResComponentName); + String srcResName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { @@ -1428,28 +1424,9 @@ parameters.add(param); } } - MethodDeclaration update = null; - if (component != null) { - for (MethodDeclaration method: component.getMethods()) { - if (method.getName().equals(updateMethodPrefix + from + srcResComponentName)) { - update = method; - break; - } - } - if (update == null) { - update = langSpec.newMethodDeclaration(updateMethodPrefix + from + srcResComponentName, false, null, parameters); - } - } else if (parentComponent != null) { - for (MethodDeclaration method: parentComponent.getMethods()) { - if (method.getName().equals(updateMethodPrefix + resComponentName + from + srcResComponentName)) { - update = method; - break; - } - } - if (update == null) { - update = langSpec.newMethodDeclaration(updateMethodPrefix + resComponentName + from + srcResComponentName, false, null, parameters); - } - } + // Get or declare the update method. + MethodDeclaration update = getOrDeclareUpdateMethod(srcResPath.getResourceHierarchy(), resourceNode.getResourceHierarchy(), ch, parameters); + // Calculate in-degree (PUSH transfer) of the destination resource. int inDegree = 0; for (Edge resToCh2: inEdges) { @@ -1474,15 +1451,6 @@ if (isRestAPI) ((RestApiSpecific) platformSpec).addPathAnnotation(update, "/" + srcResName); } } - if (update != null) { - if (component != null) { - // A component is created for this resource. - component.addMethod(update); - } else if (parentComponent != null) { - // No component is created for this resource. - parentComponent.addMethod(update); - } - } // Add a statement to update the state field if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { @@ -1735,10 +1703,8 @@ if (langSpec.declareField()) { // Declare the cache field. String cacheFieldName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); - FieldDeclaration cacheField = langSpec.newFieldDeclaration( - srcResPath.getResourceStateType(), - cacheFieldName, - langSpec.getFieldInitializer(srcResPath.getResourceStateType(), srcResPath.getResourceHierarchy().getInitialValue())); + FieldDeclaration cacheField = langSpec.newFieldDeclaration(srcResPath.getResourceStateType(), cacheFieldName); + setFieldInitializer(cacheField, srcResPath.getResourceStateType(), srcResPath.getResourceHierarchy().getInitialValue()); if (component != null) { component.addField(cacheField); } else if (parentComponent != null){ @@ -2003,210 +1969,26 @@ refVarName))); } } - List>> pathParams = new ArrayList<>(); - if (platformSpec.isMonolithic()) { - // Update fields to refer to outside resources. - ResourcePath filledOutsideResourcePath = null; - try { - Map>> resourcePaths = ch2.fillOutsideResourcePaths(out1, getPullAccessor(platformSpec)); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: resourcePaths.keySet()) { - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (out1.equals(outsideMember)) { - filledOutsideResourcePath = outsidePath; - } - if (!generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); - Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); - if (generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } - if (outsideExp instanceof Field) { - outsideExp = new Variable(((Field) outsideExp).getSymbol().getName(), ((Field) outsideExp).getType()); - } else if (outsideExp instanceof Term) { - for (Entry fieldEnt: ((Term) outsideExp).getSubTerms(Field.class).entrySet()) { - Position pos = fieldEnt.getKey(); - Field field = fieldEnt.getValue(); - Variable var = new Variable(field.getSymbol().getName(), field.getType()); - ((Term) outsideExp).replaceSubTerm(pos, var); - } - } - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - // Values of path parameters to call the update method. - if (filledOutsideResourcePath == null) { - filledOutsideResourcePath = out1.getResource(); - } - for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } else if (pathParam instanceof Constant) { - Constant pathVar = (Constant) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getSymbol().getName(), - pathVar.getSymbol().getName()))); - } - } - } else { - // Values of path parameters to call the update method. - for (Expression pathParam: out1.getResource().getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } - } - } - // Values of channel parameters to call the update method. - List>> params = new ArrayList<>(); - for (Selector selector: ch2.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), - new AbstractMap.SimpleEntry<>(selVar.getName(), - selVar.getName()))); - } - } - // Value of the source side (input side) resource to call the update method. - ResourceHierarchy srcRes2 = resourceNode.getResourceHierarchy(); - if (generatesComponent(srcRes2)) { - params.add(new AbstractMap.SimpleEntry<>(srcRes2.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes2.getResourceName()), - langSpec.getFieldAccessor(fieldOfResourceState)))); - } else { - params.add(new AbstractMap.SimpleEntry<>(srcRes2.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes2.getResourceName()), - langSpec.getFieldAccessor(langSpec.toVariableName(srcRes2.getResourceName()))))); - srcRes2 = srcRes2.getParent(); - } - params.addAll(refParams); - // Call the update method. - String updateMethodName = null; - ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); - if (!generatesComponent(dstRes)) { - updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; - dstRes = dstRes.getParent(); - } else { - updateMethodName = updateMethodPrefix + from + resComponentName; - } - String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (outsideOutputResource2 - || (!platformSpec.isMonolithic() && in.getResource().getCommonPrefix(out1.getResource()) == null && platformSpec.isDifferentTreesAsDifferentServices())) { - // Inter-servces - if (!platformSpec.isMonolithic()) { - // REST API - RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; - String httpMethod = null; - if (out1.getStateTransition().isRightUnary()) { - httpMethod = "put"; - } else { - httpMethod = "post"; - } - String[] sideEffects = new String[] {""}; - List pathParamsUrl = new ArrayList<>(); - for (Expression pathExp: out1.getResource().getPathParams()) { - pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - String resName = langSpec.toVariableName(resComponentName); - if (inDegree <= 1) { - resName = null; - } - Map>> filledPaths = null; - try { - filledPaths = ch2.fillOutsideResourcePaths(out1, getPushAccessor(platformSpec)); - } catch (ParameterizedIdentifierIsFutureWork - | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage - | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - String dstPath = null; - if (filledPaths != null && filledPaths.get(out1) != null) { - ResourcePath filledDstPath = filledPaths.get(out1).getKey(); - dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - } else { - dstPath = dstRes.toResourcePath(pathParamsUrl); - } - // Call the update method. - if (!hasUpdateMethodinvoked) { - // The first call to an update method in this method - update.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes2.getResourceName(), params, true)); - update.addStatement(langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") - + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName, httpMethod)); - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); - } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); - } - if (!((RestApiSpecific) platformSpec).hasJsonException(update)) { - ((RestApiSpecific) platformSpec).addJsonException(update); - } - hasUpdateMethodinvoked = true; - } else { - // After the second time of call to update methods in this method - update.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes2.getResourceName(), params, false)); - update.addStatement("result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName, httpMethod)); - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); - } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); - } - if (!((RestApiSpecific) platformSpec).hasJsonException(update)) { - ((RestApiSpecific) platformSpec).addJsonException(update); - } - } - } else { - // Use the reference field to refer to outside destination resource. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } - } else { - // Intra-service - // The destination resource is not outside. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - if (srcRes2 != dstRes) { - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } else { - update.addStatement(langSpec.getMethodInvocation(updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); - } - } - if (addForStatement) { - // Close the for loop - update.addStatement(langSpec.getEndForStatement(forVarName)); - } + // Add an update method invocation. + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, update, refParams, + ch2, in, out1, inDegree, outsideOutputResource2, + forVarName, addForStatement, hasUpdateMethodinvoked); } } + + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, update, ch, directDstCh, out, in); + if (component != null) { + component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } else if (parentComponent != null) { + parentComponent.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } + Map nameToParam = constructorParams.getOrDefault(resourceNode.getResourceHierarchy(), new HashMap<>()); + nameToParam.put(presenter,langSpec.newVariableDeclaration(presenterType, presenter)); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + if (outsideInputMembers2.size() > 0) { if (!generatesComponent(resourceNode.getResourceHierarchy())) { // srcRes2 does not have a component. @@ -2269,10 +2051,9 @@ } private Map.Entry, Map>>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, - TypeDeclaration parentComponent, TypeDeclaration mainComponent, TypeDeclaration rootComponent, DataTransferModel model, Map priorMemberForInputChannel, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + TypeDeclaration parentComponent, TypeDeclaration mainComponent, TypeDeclaration rootComponent, DataTransferModel model, Map priorMemberForInputChannel) { // Declare input methods. String resName = resourceNode.getResourceName(); - String resComponentName = langSpec.toComponentName(resName); List constructorStatements = new ArrayList<>(); Map>> inputStatements = new HashMap<>(); for (Channel ch: model.getInputChannels()) { @@ -2798,6 +2579,22 @@ for (ChannelNode descendantDst: descendantDstChannels) { outEdges.addAll(descendantDst.getOutEdges()); } + // Calculate in-degree (PUSH transfer) of the destination resource. + Set inEdges = new HashSet<>(); + inEdges.addAll(directDstChNode.getInEdges()); + for (ChannelNode ancestorSrc: ancestorDstChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantDstChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + int inDegree = 0; + for (Edge resToCh2: inEdges) { + DataFlowEdge df =(DataFlowEdge) resToCh2; + if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + inDegree++; + } + } for (Edge chToRes: outEdges) { // For each data transfer to dstNode:ResourceNode. ResourceNode dstNode = ((ResourceNode) chToRes.getDestination()); @@ -2824,23 +2621,6 @@ } if ((((PushPullAttribute) dOut.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { // PUSH transfer - - // Calculate in-degree (PUSH transfer) of the destination resource. - Set inEdges = new HashSet<>(); - inEdges.addAll(directDstChNode.getInEdges()); - for (ChannelNode ancestorSrc: ancestorDstChannels) { - inEdges.addAll(ancestorSrc.getInEdges()); - } - for (ChannelNode descendantSrc: descendantDstChannels) { - inEdges.addAll(descendantSrc.getInEdges()); - } - int inDegree = 0; - for (Edge resToCh2: inEdges) { - DataFlowEdge df =(DataFlowEdge) resToCh2; - if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { - inDegree++; - } - } boolean addForStatement = false; String forVarName = null; if (descendantDstChannels.contains(chNode2)) { @@ -2956,211 +2736,26 @@ refVarName))); } } - List>> pathParams = new ArrayList<>(); - if (platformSpec.isMonolithic()) { - // Update fields to refer to outside resources. - ResourcePath filledOutsideResourcePath = null; - try { - Map>> resourcePaths = ch2.fillOutsideResourcePaths(out2, getPullAccessor(platformSpec)); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: resourcePaths.keySet()) { - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (out2.equals(outsideMember)) { - filledOutsideResourcePath = outsidePath; - } - if (!generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); - Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); - if (generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } - if (outsideExp instanceof Field) { - outsideExp = new Variable(((Field) outsideExp).getSymbol().getName(), ((Field) outsideExp).getType()); - } else if (outsideExp instanceof Term) { - for (Entry fieldEnt: ((Term) outsideExp).getSubTerms(Field.class).entrySet()) { - Position pos = fieldEnt.getKey(); - Field field = fieldEnt.getValue(); - Variable var = new Variable(field.getSymbol().getName(), field.getType()); - ((Term) outsideExp).replaceSubTerm(pos, var); - } - } - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - input.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - // Values of path parameters to call the update method. - if (filledOutsideResourcePath == null) { - filledOutsideResourcePath = out2.getResource(); - } - for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } else if (pathParam instanceof Constant) { - Constant pathVar = (Constant) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getSymbol().getName(), - pathVar.getSymbol().getName()))); - } - } - } else { - // Values of path parameters to call the update method. - for (Expression pathParam: out2.getResource().getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } - } - } - // Values of channel parameters to call the update method. - List>> params = new ArrayList<>(); - for (Selector selector: ch2.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), - new AbstractMap.SimpleEntry<>(selVar.getName(), - selVar.getName()))); - } - } - // Value of the source side (input side) resource to call the update method. - ResourceHierarchy srcRes = resourceNode.getResourceHierarchy(); - if (generatesComponent(srcRes)) { - params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), - langSpec.getFieldAccessor(fieldOfResourceState)))); - } else { - params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), - langSpec.getFieldAccessor(langSpec.toVariableName(srcRes.getResourceName()))))); - srcRes = srcRes.getParent(); - } - params.addAll(refParams); - // Call the update method. - String updateMethodName = null; - ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); - if (!generatesComponent(dstRes)) { - updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; - dstRes = dstRes.getParent(); - } else { - updateMethodName = updateMethodPrefix + from + resComponentName; - } - String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (outsideOutputResource2 - || (!platformSpec.isMonolithic() && in.getResource().getCommonPrefix(out2.getResource()) == null && platformSpec.isDifferentTreesAsDifferentServices())) { - // Inter-servces - if (!platformSpec.isMonolithic()) { - // REST API - RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; - String httpMethod = null; - if (out2.getStateTransition().isRightUnary()) { - httpMethod = "put"; - } else { - httpMethod = "post"; - } - String[] sideEffects = new String[] {""}; - List pathParamsUrl = new ArrayList<>(); - for (Expression pathExp: out2.getResource().getPathParams()) { - pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - String resName2 = langSpec.toVariableName(resComponentName); - if (inDegree <= 1) { - resName2 = null; - } - Map>> filledPaths = null; - try { - filledPaths = ch2.fillOutsideResourcePaths(out2, getPushAccessor(platformSpec)); - } catch (ParameterizedIdentifierIsFutureWork - | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage - | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - String dstPath = null; - if (filledPaths != null && filledPaths.get(out2) != null) { - ResourcePath filledDstPath = filledPaths.get(out2).getKey(); - dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - } else { - dstPath = dstRes.toResourcePath(pathParamsUrl); - } - // Call the update method. - if (!hasUpdateMethodinvoked) { - // The first call to an update method in this method - input.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, true)); - input.addStatement(langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") - + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName2, httpMethod)); - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); - } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); - } - if (!((RestApiSpecific) platformSpec).hasJsonException(input)) { - ((RestApiSpecific) platformSpec).addJsonException(input); - } - hasUpdateMethodinvoked = true; - } else { - // After the second time of call to update methods in this method - input.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); - input.addStatement("result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName2, httpMethod)); - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); - } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); - } - if (!((RestApiSpecific) platformSpec).hasJsonException(input)) { - ((RestApiSpecific) platformSpec).addJsonException(input); - } - } - } else { - // Use the reference field to refer to outside destination resource. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } - } else { - // Intra-service - // The destination resource is not outside. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - if (srcRes != dstRes) { - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } else { - input.addStatement(langSpec.getMethodInvocation(updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); - } - } - if (addForStatement) { - // Close the for loop. - input.addStatement(langSpec.getEndForStatement(forVarName)); - } + // Add an update method invocation. + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, input, refParams, + ch2, in, out2, inDegree, outsideOutputResource2, + forVarName, addForStatement, hasUpdateMethodinvoked); } } + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, input, ((DataTransferChannel) ch), directDstCh, out, in); + if (component != null) { + component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } else if (parentComponent != null) { + parentComponent.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } + Map nameToParam = constructorParams.getOrDefault(resourceNode.getResourceHierarchy(), new HashMap<>()); + nameToParam.put(presenter,langSpec.newVariableDeclaration(presenterType, presenter)); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + // Update and initialize a field to refer to an outside input resource for PULL transfer. if (platformSpec.isMonolithic()) { // For a monolithic application. @@ -3221,8 +2816,355 @@ return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements); } - protected void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private boolean addUpdateMethodInvocation(ResourceNode srcNode, ResourceNode dstNode, + MethodDeclaration callerMethod, List>> refParams, + DataTransferChannel ch, ChannelMember in, ChannelMember out, int inDegree, boolean outsideOutputResource, + String forVarName, boolean addForStatement, boolean hasUpdateMethodinvoked) { + List>> pathParams = new ArrayList<>(); + if (platformSpec.isMonolithic()) { + // Update fields to refer to outside resources. + ResourcePath filledOutsideResourcePath = null; + try { + Map>> resourcePaths = ch.fillOutsideResourcePaths(out, getPullAccessor(platformSpec)); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: resourcePaths.keySet()) { + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (out.equals(outsideMember)) { + filledOutsideResourcePath = outsidePath; + } + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + if (outsideExp instanceof Field) { + outsideExp = new Variable(((Field) outsideExp).getSymbol().getName(), ((Field) outsideExp).getType()); + } else if (outsideExp instanceof Term) { + for (Entry fieldEnt: ((Term) outsideExp).getSubTerms(Field.class).entrySet()) { + Position pos = fieldEnt.getKey(); + Field field = fieldEnt.getValue(); + Variable var = new Variable(field.getSymbol().getName(), field.getType()); + ((Term) outsideExp).replaceSubTerm(pos, var); + } + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + callerMethod.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + // Values of path parameters to call the update method. + if (filledOutsideResourcePath == null) { + filledOutsideResourcePath = out.getResource(); + } + for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getName(), + pathVar.getName()))); + } else if (pathParam instanceof Constant) { + Constant pathVar = (Constant) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getSymbol().getName(), + pathVar.getSymbol().getName()))); + } + } + } else { + // Values of path parameters to call the update method. + for (Expression pathParam: out.getResource().getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getName(), + pathVar.getName()))); + } + } + } + // Values of channel parameters to call the update method. + List>> params = new ArrayList<>(); + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), + new AbstractMap.SimpleEntry<>(selVar.getName(), + selVar.getName()))); + } + } + // Value of the source side (input side) resource to call the update method. + ResourceHierarchy srcRes = srcNode.getResourceHierarchy(); + if (generatesComponent(srcRes)) { + params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), + langSpec.getFieldAccessor(fieldOfResourceState)))); + } else { + params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), + langSpec.getFieldAccessor(langSpec.toVariableName(srcRes.getResourceName()))))); + srcRes = srcRes.getParent(); + } + params.addAll(refParams); + + // Create a guard condition. + Term guardCondition = null; + for (Map.Entry paramEnt: in.getResource().getPathParamsAndConstraints()) { + if (paramEnt.getValue() != null) { + Term newCondition = new Term(DataConstraintModel.eq); + newCondition.addChild(paramEnt.getKey(), true); + newCondition.addChild(paramEnt.getValue(), true); + if (guardCondition == null) { + guardCondition = newCondition; + } else { + Term composedCondition = new Term(DataConstraintModel.and); + composedCondition.addChild(guardCondition, true); + composedCondition.addChild(newCondition, true); + guardCondition = composedCondition; + } + } + } + + // Call the update method. + ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); + String updateMethodName = getUpdateMethodName(srcNode.getResourceHierarchy(), dstRes, ch); // Get the method name. + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); + if (outsideOutputResource + || (!platformSpec.isMonolithic() && in.getResource().getCommonPrefix(out.getResource()) == null && platformSpec.isDifferentTreesAsDifferentServices())) { + // Inter-servces + if (!platformSpec.isMonolithic()) { + // REST API + RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; + String httpMethod = null; + if (out.getStateTransition().isRightUnary()) { + httpMethod = "put"; + } else { + httpMethod = "post"; + } + String[] sideEffects = new String[] {""}; + List pathParamsUrl = new ArrayList<>(); + for (Expression pathExp: out.getResource().getPathParams()) { + pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + String srcResName = langSpec.toVariableName(getComponentName(srcNode.getResourceHierarchy(), langSpec)); + if (inDegree <= 1) { + srcResName = null; + } + Map>> filledPaths = null; + try { + filledPaths = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec)); + } catch (ParameterizedIdentifierIsFutureWork + | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage + | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + String dstPath = null; + if (filledPaths != null && filledPaths.get(out) != null) { + ResourcePath filledDstPath = filledPaths.get(out).getKey(); + dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + } else { + dstPath = dstRes.toResourcePath(pathParamsUrl); + } + // Call the update method. + TypeDeclaration srcComponent = null; + TypeDeclaration srcParentComponent = null; + if (generatesComponent(srcRes)) { + srcComponent = resourceHierarchyToComponent.get(srcRes); + } else if (srcRes.getParent() != null) { + srcParentComponent = resourceHierarchyToComponent.get(srcRes.getParent()); + } + if (!hasUpdateMethodinvoked) { + // The first call to an update method in this method + callerMethod.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, true)); + String httpMethodCall = langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") + + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod); + if (guardCondition == null) { + // Non-conditional http method call. + callerMethod.addStatement(httpMethodCall); + } else { + // Conditional http method call by a guarded state transition. + callerMethod.addStatement(langSpec.getIfStatement(guardCondition, httpMethodCall)); + } + if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcComponent); + } else if (srcParentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcParentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); + } + if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { + ((RestApiSpecific) platformSpec).addJsonException(callerMethod); + } + hasUpdateMethodinvoked = true; + } else { + // After the second time of call to update methods in this method + callerMethod.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); + String httpMethodCall = "result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod); + if (guardCondition == null) { + // Non-conditional http method call. + callerMethod.addStatement(httpMethodCall); + } else { + // Conditional http method call by a guarded state transition. + callerMethod.addStatement(langSpec.getIfStatement(guardCondition, httpMethodCall)); + } + if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcComponent); + } else if (srcParentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcParentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); + } + if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { + ((RestApiSpecific) platformSpec).addJsonException(callerMethod); + } + } + } else { + // Use the reference field to refer to outside destination resource. + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: pathParams) { + args.add(paramEnt.getValue().getValue()); + } + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + String methodInvocation = null; + methodInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.dst.updateDstFromSrc(value, refParams); + if (guardCondition == null) { + // Non-conditional invocation. + callerMethod.addStatement(methodInvocation); + } else { + // Conditional invocation by a guarded state transition. + callerMethod.addStatement(langSpec.getIfStatement(guardCondition, methodInvocation)); + } + } + } else { + // Intra-service + // The destination resource is not outside. + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: pathParams) { + args.add(paramEnt.getValue().getValue()); + } + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + String methodInvocation = null; + if (srcRes != dstRes) { + methodInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.dst.updateDstFromSrc(value, refParams); + } else { + methodInvocation = langSpec.getMethodInvocation(updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.updateDstFromSrc(value, refParams); + } + if (guardCondition == null) { + // Non-conditional invocation. + callerMethod.addStatement(methodInvocation); + } else { + // Conditional invocation by a guarded state transition. + callerMethod.addStatement(langSpec.getIfStatement(guardCondition, methodInvocation)); + } + } + if (addForStatement) { + // Close the for loop + callerMethod.addStatement(langSpec.getEndForStatement(forVarName)); + } + return hasUpdateMethodinvoked; + } + + private void addNativeMethodInvocation(ResourceNode srcNode, String receiverName, MethodDeclaration callerMethod, + DataTransferChannel inCh, DataTransferChannel ch, ChannelMember out, ChannelMember in) { + // Values of channel parameters to call the update method. + List>> params = new ArrayList<>(); + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), + new AbstractMap.SimpleEntry<>(selVar.getName(), + selVar.getName()))); + } + } + // Call the native method. + try { + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + IResourceStateAccessor resouceStateAccessor = new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + return getPushAccessor(platformSpec).getCurrentStateAccessorFor(out, out); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + try { + return inCh.deriveUpdateExpressionOf(out, getPushAccessor(platformSpec)).getKey(); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + return getPushAccessor(platformSpec).getNextStateAccessorFor(out, out); + } + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) { + return getPushAccessor(platformSpec).getDirectStateAccessorFor(target, from); + } + }; + Map> substitutedPositionsInMessageFromChannels = new HashMap<>(); + Expression message = ch.calcMessageConstraintForInputMember(in, in, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + if (message instanceof Term) { + String updateMethodName = ((Term) message).getSymbol().getName(); + for (Expression messageArg: ((Term) message).getChildren()) { + args.add(messageArg.toImplementation(new String[] {null})); + } + callerMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(receiverName), updateMethodName, args) + + langSpec.getStatementDelimiter()); + } + } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage e) { + } + } + + protected MethodDeclaration getOrDeclareUpdateMethod(ResourceHierarchy srcRes, ResourceHierarchy dstRes, DataTransferChannel ch, ArrayList parameters) { + MethodDeclaration update = null; + String updateMethodName = getUpdateMethodName(srcRes, dstRes, ch); + if (generatesComponent(dstRes)) { + // A component is created for this resource. + TypeDeclaration dstComponent = resourceHierarchyToComponent.get(dstRes); + for (MethodDeclaration method: dstComponent.getMethods()) { + if (method.getName().equals(updateMethodName)) { + update = method; + break; + } + } + if (update == null) { + update = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); + dstComponent.addMethod(update); + } + } else if (dstRes.getParent() != null) { + // No component is created for this resource. + TypeDeclaration dstParentComponent = resourceHierarchyToComponent.get(dstRes.getParent()); + for (MethodDeclaration method: dstParentComponent.getMethods()) { + if (method.getName().equals(updateMethodName)) { + update = method; + break; + } + } + if (update == null) { + update = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); + dstParentComponent.addMethod(update); + } + } + return update; + } + + protected void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent) { if (resourceNode.getResourceHierarchy().getParent() != null) { // For a non-root resource MethodDeclaration getterAccessor = null; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 5e5ea4a..bce2707 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -25,7 +25,6 @@ Type newMapType(Type keyType, String compTypeName); Type newTupleType(List compTypes); String getVariableDeclaration(String typeName, String varName); - String getFieldInitializer(Type type, Expression initialValue); boolean declareField(); String getSelfExp(); String getFieldAccessor(String fieldName); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index 7115e57..e40f789 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -101,17 +101,6 @@ } @Override - public String getFieldInitializer(Type type, Expression initialValue) { - String initializer = null; - if (initialValue != null) { - initializer = initialValue.toImplementation(new String[] {""}); - } else if (type != null) { - initializer = DataConstraintModel.getDefaultValue(type); - } - return initializer; - } - - @Override public boolean declareField() { return true; } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java index 8dba4c8..6f32281 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java @@ -14,6 +14,7 @@ public class JsonTerm extends Term { private Map keyToIndex = new HashMap<>(); + private static int count = 0; public JsonTerm() { super(new Symbol("json", -1)); @@ -93,15 +94,14 @@ } public String toImplementation(String[] sideEffects) { - final int count[] = new int[]{0}; - String temp = "temp_json" + count[0]; + String temp = "temp_json" + count; + count++; String impl = ""; impl += "Map " + temp + " = new HashMap<>();\n"; for (String key: keySet()) { impl += temp + ".put(\"" + key + "\", " + get(key).toImplementation(sideEffects) + ");\n"; } sideEffects[0] += impl; - count[0]++; return temp; } } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java new file mode 100644 index 0000000..c29320f --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java @@ -0,0 +1,72 @@ +package tests; + +import code.ast.*; +import models.dataConstraintModel.DataConstraintModel; + +import java.util.Arrays; +import java.util.List; + +public class ASTTest { + public static void main(String[] args) { + + MethodDeclaration method = new MethodDeclaration("Test", false); + Block methodBody = new Block(); + + VariableDeclarationStatement varStmt = new VariableDeclarationStatement(); + varStmt.setModifiers(List.of(new PlainStatement("private"))); + varStmt.setType(new PrimitiveType(new SimpleName("int"))); + varStmt.setFragments(List.of( + new VariableDeclaration(DataConstraintModel.typeInt, "x"), + new VariableDeclaration(DataConstraintModel.typeInt, "sum") + )); + methodBody.addStatement(varStmt); + + ForStatement forStmt = new ForStatement(); + forStmt.setInitializers(Arrays.asList(new PlainStatement("int j = 0"))); + forStmt.setCondition(new PlainStatement("j < 5")); + forStmt.setUpdaters(Arrays.asList(new PlainStatement("j++"))); + Block forBody = new Block(); + forBody.addStatement("sum += j;"); + forStmt.setBody(forBody); + methodBody.addStatement(forStmt); + + EnhancedForStatement enhancedFor = new EnhancedForStatement(); + enhancedFor.setParameter(new VariableDeclaration(DataConstraintModel.typeString, "s")); + enhancedFor.setExpression(new PlainStatement("list")); + Block eForBody = new Block(); + eForBody.addStatement("System.out.println(s);"); + enhancedFor.setBody(eForBody); + methodBody.addStatement(enhancedFor); + + WhileStatement whileStmt = new WhileStatement(); + whileStmt.setExpression(new PlainStatement("sum < 100")); + + Block whileBody = new Block(); + IfStatement ifStmt = new IfStatement(); + ifStmt.setExpression(new PlainStatement("sum % 2 == 0")); + + Block thenBlock = new Block(); + ExpressionStatement exprStmt = new ExpressionStatement(); + exprStmt.setExpression(new PlainStatement("sum += 10")); + thenBlock.addStatement(exprStmt); + + Block elseBlock = new Block(); + elseBlock.addStatement("sum += 5;"); + + ifStmt.setThenStatement(thenBlock); + ifStmt.setElseStatement(elseBlock); + + whileBody.addStatement(ifStmt); + whileStmt.setBody(whileBody); + methodBody.addStatement(whileStmt); + + ReturnStatement returnStmt = new ReturnStatement(); + returnStmt.setExpression(new PlainStatement("sum")); + methodBody.addStatement(returnStmt); + + method.setBody(methodBody); + + System.out.println("--- Generated Code ---"); + System.out.println(method.toString()); + } +} \ No newline at end of file