diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java index 2b3a636..da1a3df 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java @@ -15,6 +15,7 @@ import generators.DataTransferMethodAnalyzer; import generators.JavaSpecific; import generators.JerseyCodeGenerator; +import generators.JerseyMethodBodyGenerator; import generators.JerseySpecific; import models.dataConstraintModel.ResourceHierarchy; import models.dataFlowModel.DataTransferModel; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 6bd89a9..0ac7327 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -1612,6 +1612,7 @@ } // Add an invocation to another update method (for a chain of update method invocations). + boolean hasUpdateMethodinvoked = false; for (Edge resToCh2: resourceNode.getOutEdges()) { DataFlowEdge dOut = (DataFlowEdge) resToCh2; ChannelNode directDstChNode = (ChannelNode) resToCh2.getDestination(); @@ -1706,7 +1707,15 @@ insideResPath = insideResPath.getParent(); } insideResPath = insideResPath.getParent(); - String parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getPrimaryResourcePath()).toImplementation(new String[] {}); + String parent = null; + if (!platformSpec.isMonolithic() && generatesComponent(insideResPath.getResourceHierarchy())) { + Expression getter = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getPrimaryResourcePath()); + Term valueGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + valueGetter.addChild(getter); + parent = valueGetter.toImplementation(new String[] {}); + } else { + parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getPrimaryResourcePath()).toImplementation(new String[] {}); + } if (insideResPath != null) { if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for broadcasting. @@ -1724,7 +1733,7 @@ } } // Get the value of reference member to call the update method. - List params = new ArrayList<>(); + List>> refParams = new ArrayList<>(); Map> referredResources = new HashMap<>(); Set referredSet = referredResources.get(update); for (ChannelMember rc: ch2.getReferenceChannelMembers()) { @@ -1735,99 +1744,187 @@ } if (!resourceNode.getInSideResources().contains(ref)) { String refVarName = langSpec.toVariableName(getComponentName(ref.getResourceHierarchy(), langSpec)); + Type refResourceType = ref.getResourceStateType(); if (!referredSet.contains(ref)) { referredSet.add(ref); - ResourcePath srcRes = in.getResource(); - if (!generatesComponent(srcRes.getResourceHierarchy())) { - srcRes = srcRes.getParent(); - } - Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, srcRes); String[] sideEffects = new String[] {""}; - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - update.addStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + if (!platformSpec.isMonolithic() && rc.isOutside()) { + List pathParams = new ArrayList<>(); + for (Expression pathExp: ref.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(update, refVarName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType, false, platformSpec, langSpec); + } else { + ResourcePath srcRes = in.getResource(); + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); + } + Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, srcRes); + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + update.addStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + } } - params.add(refVarName); + refParams.add(new AbstractMap.SimpleEntry<>(ref.getResourceStateType(), + new AbstractMap.SimpleEntry<>(refVarName, + refVarName))); } } // Update fields to refer to outside resources. - 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 (!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); + if (platformSpec.isMonolithic()) { + 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 (!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. } - 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(); } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); } // Values of path parameters to call the update method. + List>> pathParams = new ArrayList<>(); for (Expression pathParam: out1.getResource().getPathParams()) { if (pathParam instanceof Variable) { Variable pathVar = (Variable) pathParam; - params.add(pathVar.getName()); + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getName(), + pathVar.getName()))); } } // Values of channel parameters to call the update method. - for (Selector selector: ch.getAllSelectors()) { + List>> params = new ArrayList<>(); + for (Selector selector: ch2.getAllSelectors()) { if (selector.getExpression() instanceof Variable) { Variable selVar = (Variable) selector.getExpression(); - params.add(selVar.getName()); + 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(langSpec.getFieldAccessor(fieldOfResourceState)); + params.add(new AbstractMap.SimpleEntry<>(srcRes2.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes2.getResourceName()), + langSpec.getFieldAccessor(fieldOfResourceState)))); } else { - params.add(langSpec.getFieldAccessor(langSpec.toVariableName(srcRes2.getResourceName()))); + 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; + updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; dstRes = dstRes.getParent(); } else { updateMethodName = updateMethodPrefix + from + resComponentName; } String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (!outsideOutputResource2) { - // The destination resource is not outside. - if (srcRes2 != dstRes) { - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); + 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.toString().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)); + 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)); + } } else { - update.addStatement(langSpec.getMethodInvocation(updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); + // 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 { - // Use the reference field to refer to outside destination resource. - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); + // 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 @@ -2298,6 +2395,7 @@ } // Add an invocation to an update method (for a chain of update method invocations). + boolean hasUpdateMethodinvoked = false; for (Edge resToCh: resourceNode.getOutEdges()) { DataFlowEdge dOut = (DataFlowEdge) resToCh; ChannelNode directDstChNode = (ChannelNode) resToCh.getDestination(); @@ -2354,6 +2452,23 @@ } 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)) { @@ -2410,7 +2525,7 @@ } } // Get the value of reference member to call the update method. - List params = new ArrayList<>(); + List>> refParams = new ArrayList<>(); Map> referredResources = new HashMap<>(); Set referredSet = referredResources.get(input); for (ChannelMember rc: ch2.getReferenceChannelMembers()) { @@ -2433,64 +2548,79 @@ String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); input.addStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); } - params.add(refVarName); + refParams.add(new AbstractMap.SimpleEntry<>(ref.getResourceStateType(), + new AbstractMap.SimpleEntry<>(refVarName, + refVarName))); } } // Update fields to refer to outside resources. - 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 (!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); + if (platformSpec.isMonolithic()) { + 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 (!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. } - 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(); } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); } // Values of path parameters to call the update method. + List>> pathParams = new ArrayList<>(); for (Expression pathParam: out2.getResource().getPathParams()) { if (pathParam instanceof Variable) { Variable pathVar = (Variable) pathParam; - params.add(pathVar.getName()); + 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(selVar.getName()); + 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(langSpec.getFieldAccessor(fieldOfResourceState)); + params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), + langSpec.getFieldAccessor(fieldOfResourceState)))); } else { - params.add(langSpec.getFieldAccessor(langSpec.toVariableName(srcRes.getResourceName()))); + 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(); @@ -2501,19 +2631,83 @@ updateMethodName = updateMethodPrefix + from + resComponentName; } String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (!outsideOutputResource2) { - // The destination resource is not outside. - if (srcRes != dstRes) { - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); + 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.toString().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)); + 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)); + } } else { - input.addStatement(langSpec.getMethodInvocation(updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); + // 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 { - // Use the reference field to refer to outside destination resource. - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); + // 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. @@ -2848,7 +3042,58 @@ return resPath.getResourceHierarchy().toResourcePath(params); } - private static String convertFromEntryToMapType(Type type, ILanguageSpecific langSpec) { + private void generatePullDataTransfer(MethodDeclaration methodBody, String fromResourceName, String fromResourcePath, Type fromResourceType, boolean doesAddFirst, + IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; + String varName = new String(fromResourceName); + String respTypeName = fromResourceType.getInterfaceTypeName(); + String respImplTypeName = fromResourceType.getImplementationTypeName(); + String respConverter = ""; + if (DataConstraintModel.typeList.isAncestorOf(fromResourceType) && fromResourceType != DataConstraintModel.typeList) { + Type compType = TypeInference.getListComponentType(fromResourceType); + if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { + varName += "_json"; + String mapTypeName = convertFromEntryToMapType(compType, langSpec); + respTypeName = "List<" + mapTypeName + ">"; + respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStringDelimiter() + "\n"; + respConverter += "for (" + mapTypeName + " i: " + varName + ") {\n"; + respConverter += "\t" + fromResourceName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i", langSpec) + ")" + langSpec.getStringDelimiter() + "\n"; + respConverter += "}"; + restApiSpec.addJsonException(methodBody); + } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { + // To do. + } + } else if (DataConstraintModel.typeTuple.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); + respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(fromResourceType, varName, langSpec) + langSpec.getStringDelimiter(); + respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); + respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + langSpec.getAssignment() + getCodeForConversionFromMapToPair(fromResourceType, varName, langSpec) + langSpec.getStringDelimiter(); + respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); + respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStringDelimiter() + "\n"; + respConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName, langSpec); + respImplTypeName = "HashMap"; + } + if (doesAddFirst) { + if (respConverter.length() > 0) { + methodBody.addFirstStatement(respConverter); + } + methodBody.addFirstStatement(respTypeName + " " + varName + " = " + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + } else { + methodBody.addStatement(respTypeName + " " + varName + " = " + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + if (respConverter.length() > 0) { + methodBody.addStatement(respConverter); + } + } + } + + private String convertFromEntryToMapType(Type type, ILanguageSpecific langSpec) { String mapTypeName = null; if (DataConstraintModel.typePair.isAncestorOf(type)) { Type compType = TypeInference.getPairComponentType(type); @@ -2879,7 +3124,7 @@ return mapTypeName; } - private static String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar, ILanguageSpecific langSpec) { + private String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar, ILanguageSpecific langSpec) { String decoded = "$x"; List elementsTypes = TypeInference.getTupleComponentTypes(tupleType); String elementBase = mapVar; @@ -2905,14 +3150,14 @@ return decoded; } - private static String getCodeForConversionFromMapToPair(Type pairType, String mapVar, ILanguageSpecific langSpec) { + private String getCodeForConversionFromMapToPair(Type pairType, String mapVar, ILanguageSpecific langSpec) { String decoded = "$x"; decoded = decoded.replace("$x", "new Pair<>(" + mapVar + ".get(\"left\"), $x)"); decoded = decoded.replace("$x", mapVar + ".get(\"right\")"); return decoded; } - private static String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar, ILanguageSpecific langSpec) { + private String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar, ILanguageSpecific langSpec) { List elementsTypes = TypeInference.getMapComponentTypes(mapType); Type keyType = elementsTypes.get(0); // Type valType = elementsTypes.get(1); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 5df4876..2cba6d3 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -409,6 +409,11 @@ chParams += selVar.getName() + ", "; } } + // Value of the source side (input side) resource. + String srcFieldName = "value"; + if (!JavaCodeGenerator.generatesComponent(src.getResourceHierarchy())) { + srcFieldName = JavaCodeGenerator.toVariableName(srcResourceName); + } // Call the update method. String updateMethodName = null; if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { @@ -416,11 +421,6 @@ } else { updateMethodName = "update" + dstResourceName + "From" + srcResourceName; } - // Value of the source side (input side) resource. - String srcFieldName = "value"; - if (!JavaCodeGenerator.generatesComponent(src.getResourceHierarchy())) { - srcFieldName = JavaCodeGenerator.toVariableName(srcResourceName); - } if (!outsideOutputResource) { // The destination resource is not outside. if (srcComponent != dstComponent) { @@ -430,17 +430,17 @@ } } else { // Use the reference field to refer to outside destination resource. - srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); + srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); } if (descendantDstChannels.contains(chNode)) { // For hierarchical channels (broadcasting push transfer). if (ch.getSelectors() != null && ch.getSelectors().size() > 0) { Expression selExp = ch.getSelectors().get(0).getExpression(); Type selType = null; - String varName = null; + String forVarName = null; if (selExp instanceof Variable) { selType = ((Variable) selExp).getType(); - varName = ((Variable) selExp).getName(); + forVarName = ((Variable) selExp).getName(); ChannelMember insideChMem = null; for (ChannelMember cm :ch.getInputChannelMembers()) { if (!cm.isOutside()) { @@ -473,11 +473,11 @@ if (insideResPath != null) { if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for broadcasting. - srcUpdate.addFirstStatement("for (int " + varName + " = 0; " + varName +" < " + parent + ".size(); " + varName + "++) {"); + srcUpdate.addFirstStatement("for (int " + forVarName + " = 0; " + forVarName +" < " + parent + ".size(); " + forVarName + "++) {"); srcUpdate.addStatement("}"); } else if (selType.equals(DataConstraintModel.typeString)) { // make a for loop (for a map) for broadcasting. - srcUpdate.addFirstStatement("for (String " + varName + ": " + parent + ".keySet()) {"); + srcUpdate.addFirstStatement("for (String " + forVarName + ": " + parent + ".keySet()) {"); srcUpdate.addStatement("}"); } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 7d7cf9a..62140b9 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -459,6 +459,7 @@ } params.add(new AbstractMap.SimpleEntry<>(src.getResourceStateType(), new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); + // Get the value of reference member to call the update method. Set referredSet = referredResources.get(srcUpdate); if (ch.getReferenceChannelMembers().size() > 0) { for (ChannelMember rc: ch.getReferenceChannelMembers()) { @@ -507,14 +508,15 @@ if (inDegree <= 1) { srcResName = null; } - Entry> filledEntry = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor).get(out); + Map>> filledPaths = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor); String dstPath = null; - if (filledEntry != null) { - ResourcePath filledDstPath = filledEntry.getKey(); + if (filledPaths != null && filledPaths.get(out) != null) { + ResourcePath filledDstPath = filledPaths.get(out).getKey(); dstPath = filledDstPath.toString().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); } else { dstPath = dstRes.getResourceHierarchy().toResourcePath(pathParams); } + // Call the update method. if (!chainedCalls.contains(srcUpdate)) { // The first call to an update method in this method srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); @@ -589,7 +591,7 @@ } srcUpdate.addThrow("JsonProcessingException"); } else { - // Inner-service + // Intra-service String updateMethodName = null; if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { updateMethodName = "updateFrom" + srcResourceName; @@ -611,6 +613,7 @@ callParams += delimiter + paramEnt.getValue().getValue(); delimiter = ", "; } + // Call the update method. if (srcComponent != dstComponent) { srcUpdate.addStatement("this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); } else { @@ -641,6 +644,7 @@ } params.add(new AbstractMap.SimpleEntry<>(src.getResourceStateType(), new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); + // Get the value of reference member to call the update method. Set referredSet = referredResources.get(srcInput); for (ChannelMember rc: ch.getReferenceChannelMembers()) { // For each reference channel member, get the current state of the reference side resource by pull data transfer. @@ -687,14 +691,15 @@ if (inDegree <= 1) { srcResName = null; } - Entry> filledEntry = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor).get(out); + Map>> filledPaths = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor); String dstPath = null; - if (filledEntry != null) { - ResourcePath filledDstPath = filledEntry.getKey(); + if (filledPaths != null && filledPaths.get(out) != null) { + ResourcePath filledDstPath = filledPaths.get(out).getKey(); dstPath = filledDstPath.toString().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); } else { dstPath = dstRes.getResourceHierarchy().toResourcePath(pathParams); } + // Call the update method. if (!chainedCalls.contains(srcInput)) { // First call to an update method in this method srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); @@ -710,10 +715,10 @@ if (ch.getSelectors() != null && ch.getSelectors().size() > 0) { Expression selExp = ch.getSelectors().get(0).getExpression(); Type selType = null; - String varName = null; + String forVarName = null; if (selExp instanceof Variable) { selType = ((Variable) selExp).getType(); - varName = ((Variable) selExp).getName(); + forVarName = ((Variable) selExp).getName(); ChannelMember insideChMem = null; for (ChannelMember cm :ch.getInputChannelMembers()) { if (!cm.isOutside()) { @@ -754,11 +759,11 @@ if (insideResPath != null) { if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for broadcasting. - srcInput.addFirstStatement("for (int " + varName + " = 0; " + varName +" < " + parent + ".size(); " + varName + "++) {"); + srcInput.addFirstStatement("for (int " + forVarName + " = 0; " + forVarName +" < " + parent + ".size(); " + forVarName + "++) {"); srcInput.addStatement("}"); } else if (selType.equals(DataConstraintModel.typeString)) { // make a for loop (for a map) for broadcasting. - srcInput.addFirstStatement("for (String " + varName + ": " + parent + ".keySet()) {"); + srcInput.addFirstStatement("for (String " + forVarName + ": " + parent + ".keySet()) {"); srcInput.addStatement("}"); } } @@ -769,7 +774,7 @@ } srcInput.addThrow("JsonProcessingException"); } else { - // Inner-service + // Intra-service String updateMethodName = null; if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { updateMethodName = "updateFrom" + srcResourceName; @@ -791,6 +796,7 @@ callParams += delimiter + paramEnt.getValue().getValue(); delimiter = ", "; } + // Call the update method. if (srcComponent != dstComponent) { srcInput.addStatement("this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); } else { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java index 4bb3c4b..5db510d 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java @@ -1,5 +1,9 @@ package generators; +import java.util.List; +import java.util.Map; + +import algorithms.TypeInference; import code.ast.Annotation; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; @@ -8,6 +12,7 @@ import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; import models.algebra.Type; +import models.dataConstraintModel.DataConstraintModel; public class JerseySpecific extends RestApiSpecific { public static final Type typeClient = new Type("Client", "Client"); @@ -78,6 +83,65 @@ public String getConversionFromJsonString(String fromStrVarName, String toVarName, String toVarType) { return toVarType + toVarName + langSpec.getAssignment() + langSpec.getConstructorInvocation("ObjectMapper", null) + ".readValue(" + fromStrVarName + ", HashMap.class)"; } + + @Override + public String getHttpMethodParamsConstructionStatement(String callerResourceName, List>> params, boolean isFirstCall) { + String statements = ""; + if (isFirstCall) { + statements += "Form "; + } + statements += "form" + langSpec.getAssignment() + langSpec.getConstructorInvocation("Form", null) + langSpec.getStatementDelimiter() + "\n"; + for (Map.Entry> param: params) { + Type paramType = param.getKey(); + String paramName = param.getValue().getKey(); + String value = param.getValue().getValue(); + if (DataConstraintModel.typeList.isAncestorOf(paramType)) { + Type compType = TypeInference.getListComponentType(paramType); + String wrapperType = DataConstraintModel.getWrapperType(compType); + if (wrapperType == null) { + statements += "for (" + compType.getInterfaceTypeName() + " i: " + value + ") {\n"; + } else { + statements += "for (" + wrapperType + " i: " + value + ") {\n"; + } + if (DataConstraintModel.typeTuple.isAncestorOf(compType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeList.isAncestorOf(compType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { + statements += "\tform.param(\"" + paramName + "\", " + langSpec.getConstructorInvocation("ObjectMapper", null) + ".writeValueAsString(i))" + langSpec.getStatementDelimiter() + "\n"; // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + } else { + statements += "\tform.param(\"" + paramName + "\", i.toString())" + langSpec.getStatementDelimiter() + "\n"; + } + statements += "}\n"; +// return "Entity entity = Entity.entity(" + paramName + ".toString(), MediaType.APPLICATION_JSON);"; + } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { + // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + statements += "form.param(\"" + paramName + "\", " + langSpec.getConstructorInvocation("ObjectMapper", null) + ".writeValueAsString(" + value + "))" + langSpec.getStatementDelimiter() + "\n"; + } else { + statements += "form.param(\"" + paramName + "\", " + new JavaSpecific().getValueToStringExp(paramType.getImplementationTypeName(), value) + ")" + langSpec.getStatementDelimiter() + "\n"; + } + } + if (isFirstCall) { + statements += "Entity
"; + } + statements += "entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED)" + langSpec.getStatementDelimiter(); + return statements; + } + + @Override + public String getHttpMethodCallStatement(String baseURL, String resourceName, String senderResName, String httpMethod) { + if (senderResName == null) { + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(entity, String.class)" + langSpec.getStatementDelimiter(); + } else { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "/" + senderResName + "\").request()." + httpMethod + "(entity, String.class)" + langSpec.getStatementDelimiter(); + } + } + + @Override + public String getHttpMethodCallWithResponseStatement(String baseURL, String resourceName, String httpMethod, String responseTypeName) { + String responseShortTypeName = responseTypeName; + if (responseTypeName.contains("<")) { + responseShortTypeName = responseTypeName.substring(0, responseTypeName.indexOf("<")); + } + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(" + responseShortTypeName + ".class)" + langSpec.getStatementDelimiter() + "\n"; + } @Override public void addJsonException(MethodDeclaration method) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java index f8aeb83..7a495e9 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map.Entry; import code.ast.Annotation; import code.ast.CompilationUnit; @@ -51,6 +52,17 @@ abstract public void addPlatformSpecificImports(CompilationUnit cu); abstract public String getConversionFromJsonString(String fromStrVarName, String toVarName, String toVarType); + + abstract public String getHttpMethodParamsConstructionStatement(String callerResourceName, List>> params, boolean isFirstCall); + + abstract public String getHttpMethodCallStatement(String baseURL, String resourceName, String senderResName, String httpMethod); + + abstract public String getHttpMethodCallWithResponseStatement(String baseURL, String resourceName, String httpMethod, String responseTypeName); abstract public void addJsonException(MethodDeclaration method); + + public String getBaseURL() { + return "http://localhost:8080"; + } + }