diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 0319c58..eacaf25 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -60,9 +60,9 @@ 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 ILanguageSpecific langSpec = null; + protected IPlatformSpecific platformSpec = null; public CodeGenerator() { componentNames.clear(); @@ -160,8 +160,8 @@ * @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; ArrayList codes = new ArrayList<>(); Map> dependedRootComponentGraph = null; @@ -180,13 +180,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<>(); @@ -300,8 +299,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; @@ -354,7 +352,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; @@ -422,7 +420,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())) { @@ -456,7 +454,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()) { @@ -496,8 +494,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; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 3990544..69bcf51 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -60,12 +60,15 @@ import simulator.ResourceIdentifier; public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { + protected Map resourceHierarchyToComponent; + protected Map> constructorParams; + protected Map>> updateMethods; - 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<>(); + updateMethods = new HashMap<>(); Map resourceConstructors = new HashMap<>(); - Map> constructorParams = new HashMap<>(); List> constructorStatements = new ArrayList<>(); Map>> updateStatements = new HashMap<>(); Map> descendantGetters = new HashMap<>(); @@ -92,7 +95,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. @@ -101,7 +104,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. @@ -113,16 +116,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); @@ -133,23 +136,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); } } } @@ -167,16 +170,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, constructorParams, 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()) { @@ -190,27 +193,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, constructorParams, 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()) { @@ -229,7 +232,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. @@ -242,8 +245,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); } } @@ -280,11 +283,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()) { @@ -294,12 +296,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); } } @@ -318,13 +320,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())); } } } @@ -334,7 +336,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); @@ -416,8 +418,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); @@ -514,7 +515,7 @@ 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. @@ -555,8 +556,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()) { @@ -892,8 +892,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) { @@ -904,10 +903,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); @@ -918,8 +917,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; @@ -929,7 +927,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) { @@ -964,9 +962,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); @@ -992,8 +990,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. @@ -1289,7 +1286,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) { @@ -1327,7 +1324,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; @@ -1337,10 +1334,9 @@ } } - private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, - TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent, Map> constructorParams, 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()) { @@ -1363,8 +1359,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()) { @@ -1431,28 +1426,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) { @@ -1477,15 +1453,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()) { @@ -2005,16 +1972,15 @@ } } // Add an update method invocation. - hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, update, - refParams, component, parentComponent, resComponentName, ch2, in, out1, - inDegree, outsideOutputResource2, forVarName, addForStatement, - hasUpdateMethodinvoked, platformSpec, langSpec); + 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, platformSpec, langSpec); + addNativeMethodInvocation(resourceNode, presenter, update, ch, directDstCh, out, in); if (component != null) { component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); } else if (parentComponent != null) { @@ -2087,10 +2053,9 @@ } private Map.Entry, Map>>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, - TypeDeclaration parentComponent, TypeDeclaration mainComponent, TypeDeclaration rootComponent, DataTransferModel model, Map priorMemberForInputChannel, Map> constructorParams, 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()) { @@ -2774,16 +2739,15 @@ } } // Add an update method invocation. - hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, input, - refParams, component, parentComponent, resComponentName, ch2, in, out2, - inDegree, outsideOutputResource2, forVarName, addForStatement, - hasUpdateMethodinvoked, platformSpec, langSpec); + 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, platformSpec, langSpec); + addNativeMethodInvocation(resourceNode, presenter, input, ((DataTransferChannel) ch), directDstCh, out, in); if (component != null) { component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); } else if (parentComponent != null) { @@ -2856,10 +2820,8 @@ private boolean addUpdateMethodInvocation(ResourceNode srcNode, ResourceNode dstNode, MethodDeclaration callerMethod, List>> refParams, - TypeDeclaration component, TypeDeclaration parentComponent, String componentName, DataTransferChannel ch, - ChannelMember in, ChannelMember out, int inDegree, boolean outsideOutputResource, - String forVarName, boolean addForStatement, boolean hasUpdateMethodinvoked, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + 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. @@ -2950,14 +2912,12 @@ srcRes = srcRes.getParent(); } params.addAll(refParams); + // Call the update method. - String updateMethodName = null; ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); + String updateMethodName = getUpdateMethodName(srcNode.getResourceHierarchy(), dstRes, ch); // Get the method name. if (!generatesComponent(dstRes)) { - updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + componentName; dstRes = dstRes.getParent(); - } else { - updateMethodName = updateMethodPrefix + from + componentName; } String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); if (outsideOutputResource @@ -2977,9 +2937,9 @@ for (Expression pathExp: out.getResource().getPathParams()) { pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); } - String resName = langSpec.toVariableName(componentName); + String srcResName = langSpec.toVariableName(getComponentName(srcNode.getResourceHierarchy(), langSpec)); if (inDegree <= 1) { - resName = null; + srcResName = null; } Map>> filledPaths = null; try { @@ -2997,17 +2957,24 @@ 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)); callerMethod.addStatement(langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") - + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName, httpMethod)); - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { + + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod)); + if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { // 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)) { + ((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(parentComponent); + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); } if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { ((RestApiSpecific) platformSpec).addJsonException(callerMethod); @@ -3016,13 +2983,13 @@ } else { // After the second time of call to update methods in this method callerMethod.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); - callerMethod.addStatement("result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName, httpMethod)); - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { + callerMethod.addStatement("result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod)); + if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { // 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)) { + ((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(parentComponent); + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); } if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { ((RestApiSpecific) platformSpec).addJsonException(callerMethod); @@ -3066,7 +3033,7 @@ } private void addNativeMethodInvocation(ResourceNode srcNode, String receiverName, MethodDeclaration callerMethod, - DataTransferChannel inCh, DataTransferChannel ch, ChannelMember out, ChannelMember in, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + 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()) { @@ -3118,8 +3085,62 @@ } } - protected void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + 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 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 void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent) { if (resourceNode.getResourceHierarchy().getParent() != null) { // For a non-root resource MethodDeclaration getterAccessor = null;