diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index ff94af2..0ba11ba 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -10,6 +10,7 @@ import java.util.Set; import java.util.Stack; +import algorithms.TypeInference; import code.ast.Block; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; @@ -547,6 +548,278 @@ if (m.getName().equals(methodName)) return m; } return null; + } + + protected boolean isPut(ChannelMember cm) { + return cm.getStateTransition().isRightUnary(); + } + + protected boolean isDelete(ChannelMember cm) { + boolean isDelete = false; + Expression nextExp = cm.getStateTransition().getNextStateExpression(); + if (nextExp instanceof Term) { + Symbol rootSymbol = ((Term) nextExp).getSymbol(); + if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { + isDelete = true; + } else if (rootSymbol.equals(DataConstraintModel.cond)) { + Expression childExp = ((Term) nextExp).getChild(1); + if (childExp instanceof Term) { + rootSymbol = ((Term) childExp).getSymbol(); + if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { + isDelete = true; + } + } + childExp = ((Term) nextExp).getChild(2); + if (childExp instanceof Term) { + rootSymbol = ((Term) childExp).getSymbol(); + if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { + isDelete = true; + } + } + } + } + return isDelete; + } + + protected String getGetterResourcePathAndPathParams(ResourcePath resPath, List pathParams, + IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + int v = 1; + List params = new ArrayList<>(); + for (Expression pathParam: resPath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = var.getName(); + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = "v" + v; + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } + } + return resPath.getResourceHierarchy().toResourcePath(params); + } + + protected String getUpdateResourcePathAndPathParams(ResourcePath resPath, ArrayList pathParams, boolean isRestAPI, + IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + int v = 1; + List params = new ArrayList<>(); + for (Expression pathParam: resPath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = null; + if (isRestAPI) { + paramName = var.getName(); + } else { + paramName = "self" + (v > 1 ? v : ""); + } + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = null; + if (isRestAPI) { + paramName = "v" + v; + } else { + paramName = "self" + (v > 1 ? v : ""); + } + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + pathParams.add(param); + } + v++; + } + return resPath.getResourceHierarchy().toResourcePath(params); + } + + protected String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList rootInputParams, + IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + int v = 1; + List params = new ArrayList<>(); + if (resPath.getLastParam() != null) { + Expression pathParam = resPath.getLastParam(); + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = var.getName(); + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = "v" + v; + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } + v++; + } + if (resPath.getParent() != null) { + for (Expression pathParam: resPath.getParent().getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + String paramName = var.getName(); + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = "v" + v; + params.add("{" + paramName + "}"); + VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); + if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); + rootInputParams.add(param); + } + v++; + } + } + return resPath.getResourceHierarchy().toResourcePath(params); + } + + protected 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 = langSpec.newListType(mapTypeName).getInterfaceTypeName(); + respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + respConverter += langSpec.getForStatementForCollection("i", mapTypeName, varName) + "\n"; + respConverter += "\t" + langSpec.getMethodInvocation(fromResourceName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter() + "\n"; + respConverter += langSpec.getEndForStatement("i") ; + restApiSpec.addJsonException(methodBody); + } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { + // To do. + } + } else if (DataConstraintModel.typeTuple.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); + respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); + respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); + respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToPair(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); + respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); + respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + respConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName, langSpec); + respImplTypeName = "HashMap"; + } + if (doesAddFirst) { + if (respConverter.length() > 0) { + methodBody.addFirstStatement(respConverter); + } + methodBody.addFirstStatement(langSpec.getVariableDeclaration(respTypeName, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + } else { + methodBody.addStatement(langSpec.getVariableDeclaration(respTypeName, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + if (respConverter.length() > 0) { + methodBody.addStatement(respConverter); + } + } + } + + protected String convertFromEntryToMapType(Type type, ILanguageSpecific langSpec) { + String mapTypeName = null; + if (DataConstraintModel.typePair.isAncestorOf(type)) { + Type compType = TypeInference.getPairComponentType(type); + String wrapperType = DataConstraintModel.getWrapperType(compType); + if (wrapperType != null) { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); + } else { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compType.getInterfaceTypeName()).getInterfaceTypeName(); + } + } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { + List compTypes = TypeInference.getMapComponentTypes(type); + String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); + if (wrapperType != null) { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); + } else { + mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compTypes.get(1).getInterfaceTypeName()).getInterfaceTypeName(); + } + } else { + mapTypeName = type.getInterfaceTypeName(); + mapTypeName = mapTypeName.replace(DataConstraintModel.typeTuple.getInterfaceTypeName(), DataConstraintModel.typeMap.getInterfaceTypeName()); + for (int idx = mapTypeName.indexOf("<", 0); idx >= 0; idx = mapTypeName.indexOf("<", idx + 1)) { // Java specific + int to = mapTypeName.indexOf(",", idx); // Java specific + if (to > idx) { + mapTypeName = mapTypeName.substring(0, idx + 1) + DataConstraintModel.typeString.getInterfaceTypeName() + mapTypeName.substring(to); // All elements except for the last one have the string type. + } + } + } + return mapTypeName; + } + + protected String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar, ILanguageSpecific langSpec) { + String decoded = "$x"; + List elementsTypes = TypeInference.getTupleComponentTypes(tupleType); + String elementBase = mapVar; + for (Type elmType: elementsTypes.subList(0, elementsTypes.size() - 1)) { + elementBase = langSpec.getFirstEntryFromMapExp(elementBase); // elementBase.entrySet().iterator().next() + if (elmType == DataConstraintModel.typeBoolean + || elmType == DataConstraintModel.typeInt + || elmType == DataConstraintModel.typeLong + || elmType == DataConstraintModel.typeFloat + || elmType == DataConstraintModel.typeDouble) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + String elmVal = langSpec.getStringToValueExp(elmType.getImplementationTypeName(), getKey); // Integer.parseInt(elementBase.getKey()) + decoded = decoded.replace("$x", langSpec.getPairExp(elmVal, "$x")); // new AbstractMap.SimpleEntry<>(Integer.parseInt(elementBase.getKey()), $x) + } else if (elmType == DataConstraintModel.typeString) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + decoded = decoded.replace("$x", langSpec.getPairExp(getKey, "$x")); // new AbstractMap.SimpleEntry<>(elementBase.getKey(), $x) + } else { + // To do. + } + elementBase = langSpec.getMethodInvocation(elementBase, DataConstraintModel.snd.getImplName()); // elementBase.getValue() + } + decoded = decoded.replace("$x", elementBase); + return decoded; + } + + protected 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; + } + + protected 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); + String decoded = ""; + if (keyType == DataConstraintModel.typeBoolean + || keyType == DataConstraintModel.typeInt + || keyType == DataConstraintModel.typeLong + || keyType == DataConstraintModel.typeFloat + || keyType == DataConstraintModel.typeDouble) { + String keyVal = langSpec.getStringToValueExp(keyType.getImplementationTypeName(), "k"); + String getInvocation = langSpec.getMethodInvocation(mapVal, DataConstraintModel.lookup.getImplName(), List.of(keyVal)); + decoded += langSpec.getForStatementForMap("k", DataConstraintModel.typeString.getInterfaceTypeName(), mapVal) + "\n"; + decoded += "\t" + langSpec.getMethodInvocation(mapVar, DataConstraintModel.insert.getImplName(), List.of(keyVal, getInvocation)) + langSpec.getStatementDelimiter() + "\n"; + decoded += langSpec.getEndForStatement("k"); + } else if (keyType == DataConstraintModel.typeString) { + decoded += mapVar + langSpec.getAssignment() + mapVal + langSpec.getStatementDelimiter(); + } + return decoded; } protected IResourceStateAccessor getPushAccessor(IPlatformSpecific platformSpec) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index c09fbaa..df21c03 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -564,7 +564,7 @@ bDeclareClientField = true; } } else { - // Monolithic or Inner-service (for REST API) + // Monolithic or Inner-service if (component != null) { // A component is created for this resource. if (resourceNode.getResourceHierarchy() != dstRes) { @@ -848,7 +848,10 @@ fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType, platformSpec, langSpec); } else { // invocations to other getter methods when at least one incoming data-flow edges is PULL-style. - addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec); + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addClientFieldDeclaration(component); + } } return stateGetter; @@ -902,7 +905,10 @@ if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), childNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent, langSpec); } else { - addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec); + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addClientFieldDeclaration(ancestorComponent); + } } return stateGetter; @@ -923,8 +929,9 @@ return hasDescendantIn; } - private void addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode, + private boolean addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + boolean bDeclareClientField = false; try { // Data transfer on the same channel hierarchy. boolean isContainedPush = false; @@ -966,6 +973,7 @@ generatePullDataTransfer(stateGetter, srcResourceName, srcResPath.getResourceHierarchy().toResourcePath(pathParams), srcResourceType, true, platformSpec, langSpec); + bDeclareClientField = true; } } } @@ -1000,6 +1008,7 @@ generatePullDataTransfer(stateGetter, refResourceName, refResPath.getResourceHierarchy().toResourcePath(pathParams), refResourceType, true, platformSpec, langSpec); + bDeclareClientField = true; } } @@ -1035,6 +1044,7 @@ String srcResName2 = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); String srcPath2 = srcResPath.toString().replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); generatePullDataTransfer(stateGetter, srcResName2, srcPath2, srcResourceType, false, platformSpec, langSpec); + bDeclareClientField = true; } } @@ -1065,6 +1075,7 @@ } else { String srcPath2 = src2.toString().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); generatePullDataTransfer(stateGetter, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); + bDeclareClientField = true; } } else { // a depending channel member. @@ -1081,6 +1092,7 @@ } else { String srcPath2 = src2.toString().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); generatePullDataTransfer(stateGetter, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); + bDeclareClientField = true; } } } @@ -1184,6 +1196,7 @@ String parentResName = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); String parentResPath = insideResPath.toString().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); generatePullDataTransfer(stateGetter, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); + bDeclareClientField = true; } } } @@ -1210,6 +1223,7 @@ | InvalidMessage | UnificationFailed | ValueUndefined e) { e.printStackTrace(); } + return bDeclareClientField; } private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters, ILanguageSpecific langSpec) { @@ -1266,6 +1280,7 @@ String resComponentName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); List constructorStatements = new ArrayList<>(); Map>> updateStatements = new HashMap<>(); + boolean bDeclareClientField = false; for (Edge chToRes: resourceNode.getInEdges()) { ChannelNode directSrcChannel = (ChannelNode) chToRes.getSource(); DataTransferChannel ch = directSrcChannel.getChannel(); @@ -1326,6 +1341,11 @@ && (outsideOutputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcResPath) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { // Inter-service hasRestAPI = true; + if (!bDeclareClientField && component != null) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addClientFieldDeclaration(component); + bDeclareClientField = true; + } if (resourceNode.getParent() == null) { // A root resource isRestAPI = true; @@ -1620,7 +1640,6 @@ } update.addFirstStatement(langSpec.getIfStatement(conditions, updateStatement)); } - break; } } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e1) { @@ -2113,6 +2132,7 @@ String resComponentName = langSpec.toComponentName(resName); List constructorStatements = new ArrayList<>(); Map>> inputStatements = new HashMap<>(); + boolean bDeclareClientField = false; for (Channel ch: model.getInputChannels()) { for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { if (!cm.isOutside()) { @@ -2889,6 +2909,11 @@ input.addStatement(langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName2, httpMethod)); hasUpdateMethodinvoked = true; + if (!bDeclareClientField && component != null) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addClientFieldDeclaration(component); + bDeclareClientField = true; + } } else { // After the second time of call to update methods in this method input.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); @@ -2986,37 +3011,6 @@ return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements); } - protected boolean isPut(ChannelMember cm) { - return cm.getStateTransition().isRightUnary(); - } - - protected boolean isDelete(ChannelMember cm) { - boolean isDelete = false; - Expression nextExp = cm.getStateTransition().getNextStateExpression(); - if (nextExp instanceof Term) { - Symbol rootSymbol = ((Term) nextExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } else if (rootSymbol.equals(DataConstraintModel.cond)) { - Expression childExp = ((Term) nextExp).getChild(1); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - childExp = ((Term) nextExp).getChild(2); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - } - } - return isDelete; - } - protected void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { if (resourceNode.getResourceHierarchy().getParent() != null) { @@ -3151,245 +3145,4 @@ rootComponent.addMethod(rootInputAccessor); return rootInputAccessor; } - - protected String getGetterResourcePathAndPathParams(ResourcePath resPath, List pathParams, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - int v = 1; - List params = new ArrayList<>(); - for (Expression pathParam: resPath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = var.getName(); - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - pathParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = "v" + v; - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - pathParams.add(param); - } - } - return resPath.getResourceHierarchy().toResourcePath(params); - } - - protected String getUpdateResourcePathAndPathParams(ResourcePath resPath, ArrayList pathParams, boolean isRestAPI, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - int v = 1; - List params = new ArrayList<>(); - for (Expression pathParam: resPath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = null; - if (isRestAPI) { - paramName = var.getName(); - } else { - paramName = "self" + (v > 1 ? v : ""); - } - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - pathParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = null; - if (isRestAPI) { - paramName = "v" + v; - } else { - paramName = "self" + (v > 1 ? v : ""); - } - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (isRestAPI) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - pathParams.add(param); - } - v++; - } - return resPath.getResourceHierarchy().toResourcePath(params); - } - - protected String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList rootInputParams, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - int v = 1; - List params = new ArrayList<>(); - if (resPath.getLastParam() != null) { - Expression pathParam = resPath.getLastParam(); - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = var.getName(); - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - rootInputParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = "v" + v; - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - rootInputParams.add(param); - } - v++; - } - if (resPath.getParent() != null) { - for (Expression pathParam: resPath.getParent().getPathParams()) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = var.getName(); - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - rootInputParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = "v" + v; - params.add("{" + paramName + "}"); - VariableDeclaration param = langSpec.newVariableDeclaration(var.getType(), paramName); - if (!platformSpec.isMonolithic()) ((RestApiSpecific) platformSpec).addPathParamAnnotation(param, paramName); - rootInputParams.add(param); - } - v++; - } - } - return resPath.getResourceHierarchy().toResourcePath(params); - } - - 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 += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; - respConverter += "for (" + mapTypeName + " i: " + varName + ") {\n"; - respConverter += "\t" + fromResourceName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i", langSpec) + ")" + langSpec.getStatementDelimiter() + "\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 += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); - respImplTypeName = "HashMap"; - } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { - varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); - respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToPair(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); - respImplTypeName = "HashMap"; - } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { - varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); - respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; - respConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName, langSpec); - respImplTypeName = "HashMap"; - } - if (doesAddFirst) { - if (respConverter.length() > 0) { - methodBody.addFirstStatement(respConverter); - } - methodBody.addFirstStatement(langSpec.getVariableDeclaration(respTypeName, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); - } else { - methodBody.addStatement(langSpec.getVariableDeclaration(respTypeName, varName) + langSpec.getAssignment() + 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); - String wrapperType = DataConstraintModel.getWrapperType(compType); - if (wrapperType != null) { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); - } else { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compType.getInterfaceTypeName()).getInterfaceTypeName(); - } - } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { - List compTypes = TypeInference.getMapComponentTypes(type); - String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); - if (wrapperType != null) { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); - } else { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compTypes.get(1).getInterfaceTypeName()).getInterfaceTypeName(); - } - } else { - mapTypeName = type.getInterfaceTypeName(); - mapTypeName = mapTypeName.replace(DataConstraintModel.typeTuple.getInterfaceTypeName(), DataConstraintModel.typeMap.getInterfaceTypeName()); - for (int idx = mapTypeName.indexOf("<", 0); idx >= 0; idx = mapTypeName.indexOf("<", idx + 1)) { // Java specific - int to = mapTypeName.indexOf(",", idx); // Java specific - if (to > idx) { - mapTypeName = mapTypeName.substring(0, idx + 1) + DataConstraintModel.typeString.getInterfaceTypeName() + mapTypeName.substring(to); // All elements except for the last one have the string type. - } - } - } - return mapTypeName; - } - - private String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar, ILanguageSpecific langSpec) { - String decoded = "$x"; - List elementsTypes = TypeInference.getTupleComponentTypes(tupleType); - String elementBase = mapVar; - for (Type elmType: elementsTypes.subList(0, elementsTypes.size() - 1)) { - elementBase = langSpec.getFirstEntryFromMapExp(elementBase); // elementBase.entrySet().iterator().next() - if (elmType == DataConstraintModel.typeBoolean - || elmType == DataConstraintModel.typeInt - || elmType == DataConstraintModel.typeLong - || elmType == DataConstraintModel.typeFloat - || elmType == DataConstraintModel.typeDouble) { - String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() - String elmVal = langSpec.getStringToValueExp(elmType.getImplementationTypeName(), getKey); // Integer.parseInt(elementBase.getKey()) - decoded = decoded.replace("$x", langSpec.getPairExp(elmVal, "$x")); // new AbstractMap.SimpleEntry<>(Integer.parseInt(elementBase.getKey()), $x) - } else if (elmType == DataConstraintModel.typeString) { - String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() - decoded = decoded.replace("$x", langSpec.getPairExp(getKey, "$x")); // new AbstractMap.SimpleEntry<>(elementBase.getKey(), $x) - } else { - // To do. - } - elementBase = langSpec.getMethodInvocation(elementBase, DataConstraintModel.snd.getImplName()); // elementBase.getValue() - } - decoded = decoded.replace("$x", elementBase); - return decoded; - } - - 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 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); - String decoded = ""; - if (keyType == DataConstraintModel.typeBoolean - || keyType == DataConstraintModel.typeInt - || keyType == DataConstraintModel.typeLong - || keyType == DataConstraintModel.typeFloat - || keyType == DataConstraintModel.typeDouble) { - String keyVal = langSpec.getStringToValueExp(keyType.getImplementationTypeName(), "k"); - String getInvocation = langSpec.getMethodInvocation(mapVal, DataConstraintModel.lookup.getImplName(), List.of(keyVal)); - decoded += langSpec.getForStatementForMap("k", DataConstraintModel.typeString.getInterfaceTypeName(), mapVal) + "\n"; - decoded += "\t" + langSpec.getMethodInvocation(mapVar, DataConstraintModel.insert.getImplName(), List.of(keyVal, getInvocation)) + langSpec.getStatementDelimiter() + "\n"; - decoded += langSpec.getEndForStatement("k"); - } else if (keyType == DataConstraintModel.typeString) { - decoded += mapVar + langSpec.getAssignment() + mapVal + langSpec.getStatementDelimiter(); - } - return decoded; - } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java index e500208..35bb630 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java @@ -99,16 +99,16 @@ Type compType = TypeInference.getListComponentType(paramType); String wrapperType = DataConstraintModel.getWrapperType(compType); if (wrapperType == null) { - statements += "for (" + compType.getInterfaceTypeName() + " i: " + value + ") {\n"; + statements += langSpec.getForStatementForCollection("i", compType.getInterfaceTypeName(), value) + "\n"; } else { - statements += "for (" + wrapperType + " i: " + value + ") {\n"; + statements += langSpec.getForStatementForCollection("i", wrapperType, 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"; + statements += langSpec.getEndForStatement("i") + "\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} diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java index f72baa9..0cfb682 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java @@ -23,11 +23,14 @@ import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; +import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; import generators.JavaCodeGenerator; import generators.JavaMethodBodyGenerator; +import generators.JavaSpecific; import generators.JerseyCodeGenerator; import generators.JerseyMethodBodyGenerator; +import generators.JerseySpecific; import models.Edge; import models.dataFlowModel.*; import parser.*; @@ -1346,6 +1349,7 @@ TypeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); ArrayList codetree = JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model)); +// ArrayList codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), new JavaSpecific()); return codetree; } @@ -1393,7 +1397,7 @@ if (expectedFieldType.equals("void")) { assertNull(generatedField.getType()); } else { - assertEquals(generatedField.getType().getInterfaceTypeName(), expectedFieldType); + assertEquals(expectedFieldType, generatedField.getType().getInterfaceTypeName()); } } @@ -1422,12 +1426,12 @@ String expectedReturnType = expectedMethodSignature.getKey(); if (expectedReturnType.equals("void")) { if (generatedMethod.getReturnType() != null) { - assertEquals(generatedMethod.getReturnType().getInterfaceTypeName(), expectedReturnType); + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); } else { assertNull(generatedMethod.getReturnType()); } } else { - assertEquals(generatedMethod.getReturnType().getInterfaceTypeName(), expectedReturnType); + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); } Entry, Integer> expectedMethodInfo2 = expectedMethodSignature.getValue(); List expectedArgTypes = expectedMethodInfo2.getKey(); @@ -1441,7 +1445,7 @@ assertTrue(existsArg); } int expectedLinesOfCode = expectedMethodInfo2.getValue(); - assertEquals(generatedMethod.getBody().getStatements().size(), expectedLinesOfCode); + assertEquals(expectedLinesOfCode, generatedMethod.getBody().getStatements().size()); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java index d9e266f..7c4f6aa 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java @@ -25,6 +25,7 @@ import generators.JavaCodeGenerator; import generators.JavaMethodBodyGenerator; import generators.JavaSpecific; +import generators.StandaloneSpecific; import models.Edge; import models.dataFlowModel.*; import parser.*; @@ -1803,7 +1804,7 @@ TypeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); ArrayList codetree = JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model)); -// ArrayList codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JavaSpecific()); +// ArrayList codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new StandaloneSpecific(), new JavaSpecific()); return codetree; } @@ -1840,7 +1841,7 @@ if (expectedFieldType.equals("void")) { assertNull(generatedField.getType()); } else { - assertEquals(generatedField.getType().getInterfaceTypeName(), expectedFieldType); + assertEquals(expectedFieldType, generatedField.getType().getInterfaceTypeName()); } } @@ -1858,12 +1859,12 @@ String expectedReturnType = expectedMethodInfo.getKey(); if (expectedReturnType.equals("void")) { if (generatedMethod.getReturnType() != null) { - assertEquals(generatedMethod.getReturnType().getInterfaceTypeName(), expectedReturnType); + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); } else { assertNull(generatedMethod.getReturnType()); } } else { - assertEquals(generatedMethod.getReturnType().getInterfaceTypeName(), expectedReturnType); + assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName()); } Entry, Integer> expectedMethodInfo2 = expectedMethodInfo.getValue(); List expectedArgTypes = expectedMethodInfo2.getKey(); @@ -1877,7 +1878,7 @@ assertTrue(existsArg); } int expectedLinesOfCode = expectedMethodInfo2.getValue(); - assertEquals(generatedMethod.getBody().getStatements().size(), expectedLinesOfCode); + assertEquals(expectedLinesOfCode, generatedMethod.getBody().getStatements().size()); } } }