diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java index 7c66b96..58cc392 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java @@ -86,9 +86,8 @@ } for (Edge e : rn.getInEdges()) { ResourceDependency re = (ResourceDependency) e; - String srcResName = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName() - .substring(0, 1).toUpperCase() - + ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName().substring(1); + IdentifierTemplate srcRes = ((ResourceNode) re.getSource()).getIdentifierTemplate(); + String srcResName = srcRes.getResourceName().substring(0, 1).toUpperCase() + srcRes.getResourceName().substring(1); if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { if (!bDeclareClientField) { // Declare a client field to connect to the source resource of pull transfer. @@ -98,11 +97,18 @@ } else { // Declare an update method in the type of the destination resource. ArrayList vars = new ArrayList<>(); - String srcName = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName(); - Type srcType = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceStateType(); + String srcName = srcRes.getResourceName(); + Type srcType = srcRes.getResourceStateType(); VariableDeclaration param = new VariableDeclaration(srcType, srcName); param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); vars.add(param); + for (IdentifierTemplate refRes: re.getChannelGenerator().getReferenceIdentifierTemplates()) { + if (refRes != rn.getIdentifierTemplate()) { + param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); + param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); + vars.add(param); + } + } MethodDeclaration update = new MethodDeclaration("update" + srcResName, false, typeVoid, vars); for (ChannelMember cm: re.getChannelGenerator().getOutputChannelMembers()) { if (cm.getIdentifierTemplate() == rn.getIdentifierTemplate()) { @@ -124,23 +130,23 @@ } } - // Declare a client field to connect to the source resource of reference transfer. - if (!bDeclareClientField) { - for (ChannelGenerator cg : model.getChannelGenerators()) { - DataflowChannelGenerator dcg = ((DataflowChannelGenerator) cg); - for (ChannelMember cm : dcg.getOutputChannelMembers()) { - if (cm.getIdentifierTemplate().getResourceName().equals(type.getTypeName().toLowerCase())) { - if (dcg.getReferenceChannelMembers().size() > 0) { - // If there exists one or more reference channel member. - type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; - break; - } - } - } - if (bDeclareClientField) break; - } - } +// // Declare a client field to connect to the source resource of reference transfer. +// if (!bDeclareClientField) { +// for (ChannelGenerator cg : model.getChannelGenerators()) { +// DataflowChannelGenerator dcg = ((DataflowChannelGenerator) cg); +// for (ChannelMember cm : dcg.getOutputChannelMembers()) { +// if (cm.getIdentifierTemplate().getResourceName().equals(type.getTypeName().toLowerCase())) { +// if (dcg.getReferenceChannelMembers().size() > 0) { +// // If there exists one or more reference channel member. +// type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); +// bDeclareClientField = true; +// break; +// } +// } +// } +// if (bDeclareClientField) break; +// } +// } // Declare input methods in resources. for (ChannelGenerator cg : model.getIOChannelGenerators()) { diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java index 580df67..b691e8a 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java @@ -53,6 +53,7 @@ // Generate the body of each update or getter method. try { Set chainedCalls = new HashSet<>(); + Map> referredResources = new HashMap<>(); for (Edge e: graph.getEdges()) { ResourceDependency d = (ResourceDependency) e; PushPullAttribute pushPull = (PushPullAttribute) d.getAttribute(); @@ -95,14 +96,6 @@ if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { // add an update statement of the state of dst side resource. update.addFirstStatement(updateStatement); - if (d.getChannelGenerator().getReferenceChannelMembers().size() > 0) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - for (ChannelMember c: d.getChannelGenerator().getReferenceChannelMembers()) { - String refResourceName = c.getIdentifierTemplate().getResourceName(); - Type refResourceType = c.getIdentifierTemplate().getResourceStateType(); - generatePullDataTransfer(update, refResourceName, refResourceType); - } - } } } if (dst.getIndegree() > 1) { @@ -112,7 +105,7 @@ update.addFirstStatement(cashStatement); } } - // to convert a json param to a tuple or pair object. + // to convert a json param to a tuple, pair or map object. for (VariableDeclaration param: update.getParameters()) { Type paramType = param.getType(); String paramName = param.getName(); @@ -139,6 +132,9 @@ paramConverter += "\t" + paramName + ".add(" + getCodeForConversionFromMapToPair(compType, "i") + ");\n"; paramConverter += "}"; update.addThrow("JsonProcessingException"); + } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { + param.setType(DataConstraintModel.typeListStr); + // To do. } } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType)) { param.setType(DataConstraintModel.typeString); @@ -160,6 +156,16 @@ paramConverter += "\t" + paramName + " = " + getCodeForConversionFromMapToPair(paramType, "i") + ";\n"; paramConverter += "}"; update.addThrow("JsonProcessingException"); + } else if (DataConstraintModel.typeMap.isAncestorOf(paramType)) { + param.setType(DataConstraintModel.typeString); + param.setName(paramName + "_json"); + paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = " + "new " + paramType.getImplementationTypeName() + "();\n"; + paramConverter += "{\n"; + String mapTypeName = convertFromEntryToMapType(paramType); + paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; + paramConverter += "\t" + getCodeForConversionFromMapToMap(paramType, "i", paramName) + "\n"; + paramConverter += "}"; + update.addThrow("JsonProcessingException"); } if (paramConverter.length() > 0) update.addFirstStatement(paramConverter); } @@ -179,30 +185,86 @@ } for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { if (srcUpdate != null) { + List>> params = new ArrayList<>(); + Set referredSet = referredResources.get(srcUpdate); + if (d.getChannelGenerator().getReferenceChannelMembers().size() > 0) { + for (ChannelMember rc: d.getChannelGenerator().getReferenceChannelMembers()) { + // For each reference channel member, get the current state of the reference side resource by pull data transfer. + IdentifierTemplate ref = rc.getIdentifierTemplate(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(srcUpdate, referredSet); + } + if (ref != dst.getIdentifierTemplate()) { + String refResourceName = ref.getResourceName(); + Type refResourceType = ref.getResourceStateType(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + generatePullDataTransfer(srcUpdate, refResourceName, refResourceType); + } + // Value of a reference side resource. + params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); + } + } + } String srcResName = null; if (dst.getIndegree() > 1) { srcResName = srcResourceName; } if (!chainedCalls.contains(srcUpdate)) { - srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), src.getIdentifierTemplate().getResourceStateType(), srcResourceName, "this.value")); + // The first call to an update method in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, true)); srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); chainedCalls.add(srcUpdate); } else { + // After the second time of call to update methods in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, false)); srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); } srcUpdate.addThrow("JsonProcessingException"); } } for (MethodDeclaration srcInput: getInputMethods(srcType, src, model)) { + List>> params = new ArrayList<>(); + Set referredSet = referredResources.get(srcInput); + for (ChannelMember rc: d.getChannelGenerator().getReferenceChannelMembers()) { + // For each reference channel member, get the current state of the reference side resource by pull data transfer. + IdentifierTemplate ref = rc.getIdentifierTemplate(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(srcInput, referredSet); + } + if (ref != dst.getIdentifierTemplate()) { + String refResourceName = ref.getResourceName(); + Type refResourceType = ref.getResourceStateType(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + generatePullDataTransfer(srcInput, refResourceName, refResourceType); + } + // Value of a reference side resource. + params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); + } + } String srcResName = null; if (dst.getIndegree() > 1) { srcResName = srcResourceName; } if (!chainedCalls.contains(srcInput)) { - srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), src.getIdentifierTemplate().getResourceStateType(), srcResourceName, "this.value")); + // First call to an update method in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, true)); srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); chainedCalls.add(srcInput); } else { + // After the second time of call to update methods in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, false)); srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); } srcInput.addThrow("JsonProcessingException"); @@ -287,6 +349,8 @@ respConverter += "\t" + fromResourceName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i") + ");\n"; respConverter += "}"; methodBody.addThrow("JsonProcessingException"); + } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { + // To do. } } else if (DataConstraintModel.typeTuple.isAncestorOf(fromResourceType)) { varName += "_json"; @@ -298,6 +362,12 @@ respTypeName = convertFromEntryToMapType(fromResourceType); respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = " + getCodeForConversionFromMapToPair(fromResourceType, varName) + ";"; respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType); + respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = new " + fromResourceType.getImplementationTypeName() + "();\n"; + respConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName); + respImplTypeName = "HashMap"; } if (respConverter.length() > 0) { methodBody.addFirstStatement(respConverter); @@ -315,6 +385,14 @@ } else { mapTypeName = "Map"; } + } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { + List compTypes = TypeInference.getMapComponentTypes(type); + String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); + if (wrapperType != null) { + mapTypeName = "Map"; + } else { + mapTypeName = "Map"; + } } else { mapTypeName = type.getInterfaceTypeName(); mapTypeName = mapTypeName.replace("Map.Entry", "Map"); @@ -359,31 +437,65 @@ return decoded; } - private static String getHttpMethodParamsStatement(String callerResourceName, Type paramType, String paramName, String value) { - if (DataConstraintModel.typeList.isAncestorOf(paramType)) { - Type compType = TypeInference.getListComponentType(paramType); - String statements = "Form form = new Form();\n"; - 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)) { - statements += "\tform.param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(i));\n"; // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} - } else { - statements += "\tform.param(\"" + paramName + "\", i.toString());\n"; - } - statements += "}\n"; - statements += "Entity
entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED);"; - return statements; -// return "Entity entity = Entity.entity(" + paramName + ".toString(), MediaType.APPLICATION_JSON);"; - } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType) || DataConstraintModel.typePair.isAncestorOf(paramType)) { - // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} - return "Entity entity = Entity.entity(new Form().param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(" + value + ")), MediaType.APPLICATION_FORM_URLENCODED_TYPE);"; - } else { - return "Entity entity = Entity.entity(new Form().param(\"" + paramName + "\", " + CodeUtil.getToStringExp(paramType.getImplementationTypeName(), value) + "), MediaType.APPLICATION_FORM_URLENCODED_TYPE);"; + private static String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar) { + List elementsTypes = TypeInference.getMapComponentTypes(mapType); + Type keyType = elementsTypes.get(0); + Type valType = elementsTypes.get(1); + String keyVal = null; + String decoded = ""; + if (keyType == DataConstraintModel.typeBoolean + || keyType == DataConstraintModel.typeInt + || keyType == DataConstraintModel.typeLong + || keyType == DataConstraintModel.typeFloat + || keyType == DataConstraintModel.typeDouble) { + decoded += "for (String k: " + mapVal + ".keySet()) {\n"; + decoded += "\t" + mapVar + ".put("; + keyVal = CodeUtil.getToValueExp(keyType.getImplementationTypeName(), "k"); + decoded += keyVal + ", " + mapVal + ".get(" + keyVal + ")" + ");\n"; + decoded += "}"; + } else if (keyType == DataConstraintModel.typeString) { + decoded += mapVar + " = " + mapVal + ";"; } + return decoded; + } + + private static String getHttpMethodParamsStatement(String callerResourceName, List>> params, boolean isFirstCall) { + String statements = ""; + if (isFirstCall) { + statements += "Form "; + } + statements += "form = new Form();\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 + "\", new ObjectMapper().writeValueAsString(i));\n"; // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + } else { + statements += "\tform.param(\"" + paramName + "\", i.toString());\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 + "\", new ObjectMapper().writeValueAsString(" + value + "));\n"; + } else { + statements += "form.param(\"" + paramName + "\", " + CodeUtil.getToStringExp(paramType.getImplementationTypeName(), value) + ");\n"; + } + } + if (isFirstCall) { + statements += "Entity "; + } + statements += "entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED);"; + return statements; } private static String getHttpMethodCallStatement(String baseURL, String resourceName, String srcResName, String httpMethod) {