package generators; import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import algorithms.TypeInference; import code.ast.CodeUtil; import code.ast.CompilationUnit; import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; import models.Edge; import models.Node; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; import models.algebra.Term; import models.algebra.Type; import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; import models.algebra.Variable; import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; import models.dataFlowModel.DataFlowEdge; import models.dataFlowModel.DataFlowGraph; import models.dataFlowModel.ResourceNode; import models.dataFlowModel.StoreAttribute; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; public class JerseyMethodBodyGenerator { private static String baseURL = "http://localhost:8080"; public static ArrayList<CompilationUnit> doGenerate(DataFlowGraph graph, DataTransferModel model, ArrayList<CompilationUnit> codes) { // Create a map from type names (lower case) to their types. Map<String, TypeDeclaration> typeMap = new HashMap<>(); for (CompilationUnit code: codes) { for (TypeDeclaration type: code.types()) { typeMap.put(type.getTypeName().substring(0,1).toLowerCase() + type.getTypeName().substring(1), type); } } // Generate the body of each update or getter method. try { Set<MethodDeclaration> chainedCalls = new HashSet<>(); Map<MethodDeclaration, Set<ResourcePath>> referredResources = new HashMap<>(); for (Edge e: graph.getEdges()) { DataFlowEdge d = (DataFlowEdge) e; PushPullAttribute pushPull = (PushPullAttribute) d.getAttribute(); ResourceNode src = (ResourceNode) d.getSource(); ResourceNode dst = (ResourceNode) d.getDestination(); String srcResourceName = src.getResource().getResourceName(); String dstResourceName = dst.getResource().getResourceName(); TypeDeclaration srcType = typeMap.get(srcResourceName); TypeDeclaration dstType = typeMap.get(dstResourceName); for (ChannelMember out: d.getChannel().getOutputChannelMembers()) { if (out.getResource().equals(dst.getResource())) { if (pushPull.getOptions().get(0) == PushPullValue.PUSH && srcType != null) { // for push data transfer MethodDeclaration update = getUpdateMethod(dstType, srcType); if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst side resource (when every incoming edge is in push style) Expression updateExp = null; if (d.getChannel().getReferenceChannelMembers().size() == 0) { updateExp = d.getChannel().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor); } else { // if there exists one or more reference channel member. HashMap<ResourcePath, IResourceStateAccessor> inputResourceToStateAccessor = new HashMap<>(); for (Edge eIn: dst.getInEdges()) { DataFlowEdge dIn = (DataFlowEdge) eIn; inputResourceToStateAccessor.put(((ResourceNode) dIn.getSource()).getResource(), JerseyCodeGenerator.pushAccessor); } for (ChannelMember c: d.getChannel().getReferenceChannelMembers()) { inputResourceToStateAccessor.put(c.getResource(), JerseyCodeGenerator.pullAccessor); } updateExp = d.getChannel().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor, inputResourceToStateAccessor); } String[] sideEffects = new String[] {""}; String curState = updateExp.toImplementation(sideEffects); String updateStatement; if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { updateStatement = sideEffects[0]; } else { updateStatement = sideEffects[0] + "this.value = " + curState + ";"; } if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { // add an update statement of the state of dst side resource. update.addFirstStatement(updateStatement); } } if (dst.getIndegree() > 1) { // update a cash of src side resource (when incoming edges are multiple) String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { update.addFirstStatement(cashStatement); } } // 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(); String paramConverter = ""; if (DataConstraintModel.typeList.isAncestorOf(paramType) && paramType != DataConstraintModel.typeList) { Type compType = TypeInference.getListComponentType(paramType); if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { param.setType(DataConstraintModel.typeListStr); param.setName(paramName + "_json"); paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = new " + paramType.getImplementationTypeName() + "();\n"; paramConverter += "for (String str: " + param.getName() + ") {\n"; String mapTypeName = convertFromEntryToMapType(compType); paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(str, HashMap.class);\n"; paramConverter += "\t" + paramName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i") + ");\n"; paramConverter += "}"; update.addThrow("JsonProcessingException"); } else if (DataConstraintModel.typePair.isAncestorOf(compType)) { param.setType(DataConstraintModel.typeListStr); param.setName(paramName + "_json"); paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = new " + paramType.getImplementationTypeName() + "();\n"; paramConverter += "for (String str: " + param.getName() + ") {\n"; String mapTypeName = convertFromEntryToMapType(compType); paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(str, HashMap.class);\n"; 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); param.setName(paramName + "_json"); paramConverter += paramType.getInterfaceTypeName() + " " + paramName + ";\n"; paramConverter += "{\n"; String mapTypeName = convertFromEntryToMapType(paramType); paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; paramConverter += "\t" + paramName + " = " + getCodeForConversionFromMapToTuple(paramType, "i") + ";\n"; paramConverter += "}"; update.addThrow("JsonProcessingException"); } else if (DataConstraintModel.typePair.isAncestorOf(paramType)) { param.setType(DataConstraintModel.typeString); param.setName(paramName + "_json"); paramConverter += paramType.getInterfaceTypeName() + " " + paramName + ";\n"; paramConverter += "{\n"; String mapTypeName = convertFromEntryToMapType(paramType); paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; 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); } MethodDeclaration getter = getGetterMethod(dstType); if (((StoreAttribute) dst.getAttribute()).isStored()) { // returns the state stored in a field. if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { getter.addStatement("return value;"); } } // src side (for a chain of update method invocations) String httpMethod = null; if (out.getStateTransition().isRightUnary()) { httpMethod = "put"; } else { httpMethod = "post"; } for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { if (srcUpdate != null) { List<Map.Entry<Type, Map.Entry<String, String>>> params = new ArrayList<>(); Set<ResourcePath> referredSet = referredResources.get(srcUpdate); if (d.getChannel().getReferenceChannelMembers().size() > 0) { for (ChannelMember rc: d.getChannel().getReferenceChannelMembers()) { // For each reference channel member, get the current state of the reference side resource by pull data transfer. ResourcePath ref = rc.getResource(); if (referredSet == null) { referredSet = new HashSet<>(); referredResources.put(srcUpdate, referredSet); } if (!ref.equals(dst.getResource())) { 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)) { // 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.getResource().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.getResource().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<Map.Entry<Type, Map.Entry<String, String>>> params = new ArrayList<>(); Set<ResourcePath> referredSet = referredResources.get(srcInput); for (ChannelMember rc: d.getChannel().getReferenceChannelMembers()) { // For each reference channel member, get the current state of the reference side resource by pull data transfer. ResourcePath ref = rc.getResource(); if (referredSet == null) { referredSet = new HashSet<>(); referredResources.put(srcInput, referredSet); } if (!ref.equals(dst.getResource())) { 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)) { // First call to an update method in this method // Value of the source side (input side) resource. params.add(0, new AbstractMap.SimpleEntry<>(src.getResource().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.getResource().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"); } } else { // for pull (or push/pull) data transfer MethodDeclaration getter = getGetterMethod(dstType); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { // generate a return statement. String[] sideEffects = new String[] {""}; String curState = d.getChannel().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pullAccessor).toImplementation(sideEffects); // no pull data transfer is included. getter.addStatement(sideEffects[0] + "return " + curState + ";"); // For each reference channel member, get the current state of the reference side resource by pull data transfer. for (ChannelMember c: d.getChannel().getReferenceChannelMembers()) { String refResourceName = c.getResource().getResourceName(); Type refResourceType = c.getResource().getResourceStateType(); generatePullDataTransfer(getter, refResourceName, refResourceType); } } // get src side resource state by pull data transfer. Type srcResourceType = src.getResource().getResourceStateType(); generatePullDataTransfer(getter, srcResourceName, srcResourceType); } } } } // for source nodes for (Node n: graph.getNodes()) { ResourceNode resource = (ResourceNode) n; String resourceName = resource.getResource().getResourceName(); TypeDeclaration type = typeMap.get(resourceName); if (type != null) { // getter method MethodDeclaration getter = getGetterMethod(type); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { getter.addStatement("return value;"); } // methods for input events Map<DataTransferChannel, Set<ChannelMember>> ioChannelsAndMembers = getIOChannelsAndMembers(resource, model); for (Map.Entry<DataTransferChannel, Set<ChannelMember>> entry: ioChannelsAndMembers.entrySet()) { Set<ChannelMember> outs = entry.getValue(); for (ChannelMember out: outs) { MethodDeclaration input = getInputMethod(type, out); if (input != null) { Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor); String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); String updateStatement; if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { updateStatement = sideEffects[0]; } else { updateStatement = sideEffects[0] + "this.value = " + newState + ";"; } if (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement)) { input.addFirstStatement(updateStatement); } } } } } } } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e1) { e1.printStackTrace(); } return codes; } private static void generatePullDataTransfer(MethodDeclaration methodBody, String fromResourceName, Type fromResourceType) { 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); respTypeName = "List<" + mapTypeName + ">"; respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = new " + fromResourceType.getImplementationTypeName() + "();\n"; respConverter += "for (" + mapTypeName + " i: " + varName + ") {\n"; 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"; respTypeName = convertFromEntryToMapType(fromResourceType); respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = " + getCodeForConversionFromMapToTuple(fromResourceType, varName) + ";"; respImplTypeName = "HashMap"; } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { varName += "_json"; 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); } methodBody.addFirstStatement(respTypeName + " " + varName + " = " + getHttpMethodCallStatementWithResponse(baseURL, fromResourceName, "get", respImplTypeName)); } private static String convertFromEntryToMapType(Type type) { String mapTypeName = null; if (DataConstraintModel.typePair.isAncestorOf(type)) { Type compType = TypeInference.getPairComponentType(type); String wrapperType = DataConstraintModel.getWrapperType(compType); if (wrapperType != null) { mapTypeName = "Map<String, " + wrapperType + ">"; } else { mapTypeName = "Map<String, " + compType.getInterfaceTypeName() + ">"; } } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { List<Type> compTypes = TypeInference.getMapComponentTypes(type); String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); if (wrapperType != null) { mapTypeName = "Map<String, " + wrapperType + ">"; } else { mapTypeName = "Map<String, " + compTypes.get(1).getInterfaceTypeName() + ">"; } } else { mapTypeName = type.getInterfaceTypeName(); mapTypeName = mapTypeName.replace("Map.Entry", "Map"); for (int idx = mapTypeName.indexOf("<", 0); idx >= 0; idx = mapTypeName.indexOf("<", idx + 1)) { int to = mapTypeName.indexOf(",", idx); if (to > idx) { mapTypeName = mapTypeName.substring(0, idx + 1) + "String" + mapTypeName.substring(to); // All elements except for the last one have the string type. } } } return mapTypeName; } private static String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar) { String decoded = "$x"; List<Type> elementsTypes = TypeInference.getTupleComponentTypes(tupleType); String elementBase = mapVar; for (Type elmType: elementsTypes.subList(0, elementsTypes.size() - 1)) { elementBase += ".entrySet().iterator().next()"; if (elmType == DataConstraintModel.typeBoolean || elmType == DataConstraintModel.typeInt || elmType == DataConstraintModel.typeLong || elmType == DataConstraintModel.typeFloat || elmType == DataConstraintModel.typeDouble) { String elmVal = CodeUtil.getToValueExp(elmType.getImplementationTypeName(), elementBase + ".getKey()"); decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elmVal + ", $x)"); } else if (elmType == DataConstraintModel.typeString) { decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elementBase + ".getKey(), $x)"); } else { // To do. } elementBase += ".getValue()"; } decoded = decoded.replace("$x", elementBase); return decoded; } private static String getCodeForConversionFromMapToPair(Type pairType, String mapVar) { 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) { List<Type> 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<Map.Entry<Type, Map.Entry<String, String>>> params, boolean isFirstCall) { String statements = ""; if (isFirstCall) { statements += "Form "; } statements += "form = new Form();\n"; for (Map.Entry<Type, Map.Entry<String, String>> 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<String> 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<Form> "; } statements += "entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED);"; return statements; } private static String getHttpMethodCallStatement(String baseURL, String resourceName, String srcResName, String httpMethod) { if (srcResName == null) { return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(entity, String.class);"; } 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 + "/" + srcResName + "\").request()." + httpMethod + "(entity, String.class);"; } } private static String getHttpMethodCallStatementWithResponse(String baseURL, String resourceName, String httpMethod, String respImplName) { String responseShortTypeName = respImplName; if (respImplName.contains("<")) { responseShortTypeName = respImplName.substring(0, respImplName.indexOf("<")); } return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(" + responseShortTypeName + ".class);"; } private static MethodDeclaration getUpdateMethod(TypeDeclaration type, TypeDeclaration from) { for (MethodDeclaration m: type.getMethods()) { if (m.getName().equals("update" + from.getTypeName())) return m; } return null; } private static List<MethodDeclaration> getUpdateMethods(TypeDeclaration type) { List<MethodDeclaration> updates = new ArrayList<>(); for (MethodDeclaration m: type.getMethods()) { if (m.getName().startsWith("update")) { updates.add(m); } } return updates; } private static MethodDeclaration getGetterMethod(TypeDeclaration type) { for (MethodDeclaration m: type.getMethods()) { if (m.getName().startsWith("get")) return m; } return null; } private static Map<DataTransferChannel, Set<ChannelMember>> getIOChannelsAndMembers(ResourceNode resource, DataTransferModel model) { Map<DataTransferChannel, Set<ChannelMember>> ioChannelsAndMembers = new HashMap<>(); for (Channel c: model.getIOChannels()) { DataTransferChannel ch = (DataTransferChannel) c; // I/O channel for (ChannelMember out: ch.getOutputChannelMembers()) { if (out.getResource().equals(resource.getResource())) { if (out.getStateTransition().getMessageExpression() instanceof Term || out.getStateTransition().getMessageExpression() instanceof Variable) { Set<ChannelMember> channelMembers = ioChannelsAndMembers.get(ch); if (channelMembers == null) { channelMembers = new HashSet<>(); ioChannelsAndMembers.put(ch, channelMembers); } channelMembers.add(out); } } } } return ioChannelsAndMembers; } private static List<MethodDeclaration> getInputMethods(TypeDeclaration type, ResourceNode resource, DataTransferModel model) { List<MethodDeclaration> inputs = new ArrayList<>(); for (Channel c: model.getIOChannels()) { DataTransferChannel channel = (DataTransferChannel) c; // I/O channel for (ChannelMember out: channel.getOutputChannelMembers()) { if (out.getResource().equals(resource.getResource())) { MethodDeclaration input = getInputMethod(type, out); inputs.add(input); } } } return inputs; } private static MethodDeclaration getInputMethod(TypeDeclaration type, ChannelMember out) { MethodDeclaration input = null; if (out.getStateTransition().getMessageExpression() instanceof Term) { Term message = (Term) out.getStateTransition().getMessageExpression(); input = getMethod(type, message.getSymbol().getImplName()); } else if (out.getStateTransition().getMessageExpression() instanceof Variable) { Variable message = (Variable) out.getStateTransition().getMessageExpression(); input = getMethod(type, message.getName()); } return input; } private static MethodDeclaration getMethod(TypeDeclaration type, String methodName) { for (MethodDeclaration m: type.getMethods()) { if (m.getName().equals(methodName)) return m; } return null; } }