diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 9c77ea6..f90f701 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -57,6 +57,8 @@ 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; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index c87b111..37d70a5 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -57,6 +57,7 @@ import models.dataFlowModel.ChannelNode; import models.dataFlowModel.StoreAttribute; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import simulator.ResourceIdentifier; public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { @@ -175,7 +176,7 @@ // 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, constructorParams, platformSpec, langSpec); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndUpdateUpdates.getKey()) { @@ -209,7 +210,7 @@ // 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, constructorParams, platformSpec, langSpec); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndInputUpdates.getKey()) { @@ -1335,7 +1336,7 @@ } private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, - TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent, Map> constructorParams, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { // Declare cash fields and update methods in the component. String resComponentName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); List constructorStatements = new ArrayList<>(); @@ -2003,210 +2004,27 @@ 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, component, parentComponent, resComponentName, ch2, in, out1, + inDegree, outsideOutputResource2, forVarName, addForStatement, + hasUpdateMethodinvoked, platformSpec, langSpec); } } + + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, update, ch, directDstCh, out, in, platformSpec, langSpec); + 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,7 +2087,7 @@ } 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, Map> constructorParams, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { // Declare input methods. String resName = resourceNode.getResourceName(); String resComponentName = langSpec.toComponentName(resName); @@ -2798,6 +2616,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 +2658,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 +2773,27 @@ 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, component, parentComponent, resComponentName, ch2, in, out2, + inDegree, outsideOutputResource2, forVarName, addForStatement, + hasUpdateMethodinvoked, platformSpec, langSpec); } } + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, input, ((DataTransferChannel) ch), directDstCh, out, in, platformSpec, langSpec); + 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,6 +2854,270 @@ return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements); } + 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) { + 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); + // Call the update method. + String updateMethodName = null; + ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); + 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 + || (!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 resName = langSpec.toVariableName(componentName); + if (inDegree <= 1) { + resName = 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. + 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)) { + // 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(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)); + callerMethod.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(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()); + } + callerMethod.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) { + callerMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) + + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); + } else { + callerMethod.addStatement(langSpec.getMethodInvocation(updateMethodName, args) + + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); + } + } + 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, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + // 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 void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { if (resourceNode.getResourceHierarchy().getParent() != null) {