diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 5c7a65b..3f8105c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -973,28 +973,39 @@ DataTransferChannel ch2 = ((ChannelNode) resToCh2.getDestination()).getChannel(); // Check if the input resource is outside of the channel scope. boolean outsideInputResource2 = false; + ChannelMember in = null; Set outsideInputMembers2 = new HashSet<>(); for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (cm.isOutside()) { - outsideInputMembers2.add(cm); - if (cm.getResource().equals(resourceNode.getOutSideResource())) { + if (cm.getResource().equals(resourceNode.getOutSideResource())) { + if (cm.isOutside()) { outsideInputResource2 = true; // Regarded as pull transfer. } + in = cm; + } + if (cm.isOutside()) { + outsideInputMembers2.add(cm); } } - if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) { - for (Edge chToRes2: resToCh2.getDestination().getOutEdges()) { - // PUSH transfer - ChannelMember in = null; - for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (cm.getResource().equals(resourceNode.getOutSideResource())) { - in = cm; - break; - } + for (Edge chToRes2: resToCh2.getDestination().getOutEdges()) { + ResourceNode dstNode = ((ResourceNode) chToRes2.getDestination()); + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource2 = false; + for (ChannelMember cm: ch2.getOutputChannelMembers()) { + if (dstNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { + outsideOutputResource2 = true; } + } + if ((((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { + // PUSH transfer Map> referredResources = new HashMap<>(); List params = new ArrayList<>(); - params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + ResourceHierarchy srcRes2 = resourceNode.getResourceHierarchy(); + if (generatesComponent(srcRes2)) { + params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + } else { + params.add(langSpec.getFieldAccessor(langSpec.toVariableName(srcRes2.getResourceName()))); + srcRes2 = srcRes2.getParent(); + } Set referredSet = referredResources.get(update); for (ChannelMember rc: ch2.getReferenceChannelMembers()) { // to get the value of reference member. @@ -1016,12 +1027,8 @@ params.add(refVarName); } } - ResourceHierarchy srcRes2 = resourceNode.getResourceHierarchy(); - if (!generatesComponent(srcRes2)) { - srcRes2 = srcRes2.getParent(); - } String updateMethodName = null; - ResourceHierarchy dstRes = ((ResourceNode) chToRes2.getDestination()).getResourceHierarchy(); + ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); if (!generatesComponent(dstRes)) { updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; dstRes = dstRes.getParent(); @@ -1029,12 +1036,19 @@ updateMethodName = updateMethodPrefix + from + resComponentName; } String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (srcRes2 != dstRes) { + 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); + } else { + update.addStatement(langSpec.getMethodInvocation(updateMethodName, params) + + langSpec.getStatementDelimiter()); // this.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); - } else { - update.addStatement(langSpec.getMethodInvocation(updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); } } } @@ -1419,29 +1433,41 @@ for (Edge resToCh: resourceNode.getOutEdges()) { DataFlowEdge dOut = (DataFlowEdge) resToCh; DataTransferChannel ch2 = ((ChannelNode) resToCh.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. boolean outsideInputResource2 = false; + ChannelMember in = null; Set outsideInputMembers2 = new HashSet<>(); for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (cm.isOutside()) { - outsideInputMembers2.add(cm); - if (cm.getResource().equals(resourceNode.getOutSideResource())) { + if (cm.getResource().equals(resourceNode.getOutSideResource())) { + if (cm.isOutside()) { outsideInputResource2 = true; // Regarded as pull transfer. } + in = cm; + } + if (cm.isOutside()) { + outsideInputMembers2.add(cm); } } - if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) { - for (Edge chToRes: resToCh.getDestination().getOutEdges()) { - // PUSH transfer - ChannelMember in = null; - for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (cm.getResource().equals(resourceNode.getOutSideResource())) { - in = cm; - break; - } + for (Edge chToRes: resToCh.getDestination().getOutEdges()) { + ResourceNode dstNode = ((ResourceNode) chToRes.getDestination()); + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource2 = false; + for (ChannelMember cm: ch2.getOutputChannelMembers()) { + if (dstNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { + outsideOutputResource2 = true; } + } + if ((((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { + // PUSH transfer Map> referredResources = new HashMap<>(); List params = new ArrayList<>(); - params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + ResourceHierarchy srcRes = resourceNode.getResourceHierarchy(); + if (generatesComponent(srcRes)) { + params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + } else { + params.add(langSpec.getFieldAccessor(langSpec.toVariableName(srcRes.getResourceName()))); + srcRes = srcRes.getParent(); + } Set referredSet = referredResources.get(input); for (ChannelMember rc: ch2.getReferenceChannelMembers()) { // to get the value of reference member. @@ -1463,12 +1489,8 @@ params.add(refVarName); } } - ResourceHierarchy srcRes = resourceNode.getResourceHierarchy(); - if (!generatesComponent(srcRes)) { - srcRes = srcRes.getParent(); - } String updateMethodName = null; - ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); + ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); if (!generatesComponent(dstRes)) { updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; dstRes = dstRes.getParent(); @@ -1476,12 +1498,19 @@ updateMethodName = updateMethodPrefix + from + resComponentName; } String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (srcRes != dstRes) { + 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); + } else { + input.addStatement(langSpec.getMethodInvocation(updateMethodName, params) + + langSpec.getStatementDelimiter()); // this.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); - } else { - input.addStatement(langSpec.getMethodInvocation(updateMethodName, params) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 8e8466e..9cb1c6c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -74,20 +74,14 @@ // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(src.getResourceHierarchy()) && cm.isOutside()) { + if (cm.getResource().equals(src.getOutSideResource()) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } } // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(dst.getResourceHierarchy()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - if (pushPull.getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { + boolean outsideOutputResource = out.isOutside(); + if ((pushPull.getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // for push data transfer MethodDeclaration update = null; if (dstComponent == null) { @@ -267,10 +261,20 @@ } else { updateMethodName = "update" + dstResourceName + "From" + srcResourceName; } - if (srcComponent != dstComponent) { - srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(value" + refParams + ");"); + String srcFieldName = "value"; + if (!JavaCodeGenerator.generatesComponent(src.getResourceHierarchy())) { + srcFieldName = JavaCodeGenerator.toVariableName(srcResourceName); + } + if (!outsideOutputResource) { + // The destination resource is not outside. + if (srcComponent != dstComponent) { + srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); + } else { + srcUpdate.addStatement("this." + updateMethodName + "(" + srcFieldName + refParams + ");"); + } } else { - srcUpdate.addStatement("this." + updateMethodName + "(value" + refParams + ");"); + // Use the reference field to refer to outside destination resource. + srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); } } for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { @@ -302,10 +306,20 @@ } else { updateMethodName = "update" + dstResourceName + "From" + srcResourceName; } - if (srcComponent != dstComponent) { - srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(value" + refParams + ");"); + String srcFieldName = "value"; + if (!JavaCodeGenerator.generatesComponent(src.getResourceHierarchy())) { + srcFieldName = JavaCodeGenerator.toVariableName(srcResourceName); + } + if (!outsideOutputResource) { + // The destination resource is not outside. + if (srcComponent != dstComponent) { + srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); + } else { + srcInput.addStatement("this." + updateMethodName + "(" + srcFieldName + refParams + ");"); + } } else { - srcInput.addStatement("this." + updateMethodName + "(value" + refParams + ");"); + // Use the reference field to refer to outside destination resource. + srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); } } } else if ((pushPull.getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 88e747f..18c8b1b 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -295,7 +295,7 @@ dstRes = dstRes.getParent(); } String dstResName = getComponentName(dstRes.getResourceHierarchy()); - if (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { +// if (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { // Inter-service if (!bDeclareClientField) { // Declare a client field to connect to the destination resource of push transfer. @@ -303,14 +303,14 @@ fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); bDeclareClientField = true; } - } else { - // Inner-service - // Declare a field to directly refer to the destination resource of push transfer. - if (resourceNode.getParent().getResourceHierarchy() != dstRes.getResourceHierarchy()) { - FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); - } - } +// } else { +// // Inner-service +// // Declare a field to directly refer to the destination resource of push transfer. +// if (resourceNode.getParent().getResourceHierarchy() != dstRes.getResourceHierarchy()) { +// FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); +// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); +// } +// } } } } @@ -333,7 +333,7 @@ srcRes = srcRes.getParent(); } String srcResName = getComponentName(srcRes.getResourceHierarchy()); - if (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { +// if (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { // Inter-service if (!bDeclareClientField) { // Declare a client field to connect to the source resource of pull transfer. @@ -341,14 +341,14 @@ fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); bDeclareClientField = true; } - } else { - // Inner-service - // Declare a field to directly refer to the source resource of pull transfer. - if (resourceNode.getParent().getResourceHierarchy() != srcRes.getResourceHierarchy()) { - FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); - } - } +// } else { +// // Inner-service +// // Declare a field to directly refer to the source resource of pull transfer. +// if (resourceNode.getParent().getResourceHierarchy() != srcRes.getResourceHierarchy()) { +// FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); +// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); +// } +// } noPullTransfer = false; } } @@ -457,11 +457,12 @@ // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = cm.isOutside(); if (!bDeclareClientField && ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource)) { + // For push transfer. if (!generatesComponent(dstRes.getResourceHierarchy())) { dstRes = dstRes.getParent(); } String dstResName = getComponentName(dstRes.getResourceHierarchy()); - if (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { + if (outsideOutputResource || (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices)) { // Inter-service if (!bDeclareClientField) { // Declare a client field to connect to the destination resource of push transfer. @@ -509,18 +510,24 @@ } // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = false; + ChannelMember out = null; for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; + if (resourceNode.getInSideResources().contains(cm.getResource())) { + out = cm; + if (cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } } } String srcResName = getComponentName(srcRes.getResourceHierarchy()); + Type srcType = srcRes.getResourceStateType(); if (!generatesComponent(srcRes.getResourceHierarchy())) { srcRes = srcRes.getParent(); } if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - if (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { + // For pull transfer. + if (outsideInputResource || (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices)) { // Inter-service if (!bDeclareClientField) { // Declare a client field to connect to the source resource of pull transfer. @@ -551,17 +558,27 @@ } } } else { + // For push transfer. + boolean hasRestAPI = false; + boolean isRestAPI = false; + if (outsideOutputResource || (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices)) { + // Inter-service + hasRestAPI = true; + if (resourceNode.getParent() == null) { + // A root resource + isRestAPI = true; + } + } // Declare an update method in the type of the destination resource. ArrayList vars = new ArrayList<>(); - String srcName = srcRes.getResourceName(); - Type srcType = srcRes.getResourceStateType(); + String srcName = toVariableName(srcResName); VariableDeclaration param = new VariableDeclaration(srcType, srcName); - param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); + if (isRestAPI) param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); vars.add(param); for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { if (!refRes.equals(resourceNode.getOutSideResource())) { param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); - param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); + if (isRestAPI) param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); vars.add(param); } } @@ -574,17 +591,37 @@ String resourceName = getComponentName(resourceNode.getResourceHierarchy()); update = new MethodDeclaration("update" + resourceName + "From" + srcResName, false, typeVoid, vars); } + // Determine whether the update method is put or post. + boolean isPut = false; for (ChannelMember cm: ((ChannelNode) re.getDestination()).getChannel().getOutputChannelMembers()) { if (resourceNode.getInSideResources().contains(cm.getResource())) { if (cm.getStateTransition().isRightUnary()) { - update.addAnnotation(new Annotation("PUT")); + isPut = true; } else { - update.addAnnotation(new Annotation("POST")); + isPut = false; } } } - if (re.getDestination().getIndegree() > 1 - || (re.getDestination().getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + if (isRestAPI) { + if (isPut) { + update.addAnnotation(new Annotation("PUT")); + } else { + update.addAnnotation(new Annotation("POST")); + } + } + // Calculate in-degree of the destination resource. + Set inResources = new HashSet<>(); + for (ResourceNode rn: graph.getResourceNodes(out.getResource().getResourceHierarchy())) { + // ResourceNodes that have the same ResourceHierarchy. + for (Edge chToRes2: rn.getInEdges()) { + for (Edge resToCh2: chToRes2.getSource().getInEdges()) { + inResources.add(((ResourceNode) resToCh2.getSource()).getResourceHierarchy()); + } + } + } + int inDegree = inResources.size(); + if (inDegree > 1 + || (inDegree == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { // Declare a field to cache the state of the source resource in the type of the destination resource. ResourcePath cacheRes = ((ResourceNode) re.getSource()).getOutSideResource(); FieldDeclaration cacheField = new FieldDeclaration(cacheRes.getResourceStateType(), srcName, getInitializer(cacheRes)); @@ -595,9 +632,9 @@ // No component is created for this resource. fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), cacheField)); } - if (re.getDestination().getIndegree() > 1) { + if (inDegree > 1) { // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); + if (isRestAPI) update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); } } if (component != null) { @@ -615,6 +652,41 @@ nameToMethod.put(updateMethodName, update); } } + if (hasRestAPI && !isRestAPI) { + // Declare an update accessor method in the type of root resource. + String updateMethodName = update.getName(); + vars = new ArrayList<>(); + String resourcePath = getUpdateAccessorResourcePathAndPathParams(out.getResource(), vars); + param = new VariableDeclaration(srcType, srcName); + param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); + vars.add(param); + for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { + if (!refRes.equals(resourceNode.getOutSideResource())) { + param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); + param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); + vars.add(param); + } + } + MethodDeclaration updateAccessor = new MethodDeclaration(updateMethodName, false, typeVoid, vars); + if (isPut) { + updateAccessor.addAnnotation(new Annotation("PUT")); + } else { + updateAccessor.addAnnotation(new Annotation("POST")); + } + if (inDegree > 1) { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + resourcePath += "/" + toVariableName(srcResName); + } + updateAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); + Map nameToMethod = updates.get(resourceNode.getResourceHierarchy().getRoot()); + if (nameToMethod == null) { + nameToMethod = new HashMap<>(); + updates.put(resourceNode.getResourceHierarchy().getRoot(), nameToMethod); + } + if (nameToMethod.get(updateMethodName) == null) { + nameToMethod.put(updateMethodName, updateAccessor); + } + } } } } @@ -951,6 +1023,30 @@ } return resPath.getResourceHierarchy().toResourcePath(params); } + + private static String getUpdateAccessorResourcePathAndPathParams(ResourcePath resPath, ArrayList rootParams) { + 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 = new VariableDeclaration(var.getType(), paramName); + param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + rootParams.add(param); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + String paramName = "v" + v; + params.add("{" + paramName + "}"); + VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); + param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + rootParams.add(param); + } + v++; + } + return resPath.getResourceHierarchy().toResourcePath(params); + } private static String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList resInputParams, ArrayList rootInputParams) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 4254cab..352e5ba 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -79,21 +79,19 @@ if (dst.getInSideResources().contains(out.getResource())) { // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; + ChannelMember in = null; for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(src.getResourceHierarchy()) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; + if (cm.getResource().equals(src.getOutSideResource())) { + in = cm; + if (cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } } } // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(dst.getResourceHierarchy()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - if (pushPull.getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { + boolean outsideOutputResource = out.isOutside(); + if ((pushPull.getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // for push data transfer MethodDeclaration update = null; if (dstComponent == null) { @@ -115,14 +113,14 @@ DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); for (Edge resToCh2: chToRes2.getSource().getInEdges()) { DataFlowEdge dIn = (DataFlowEdge) resToCh2; - ChannelMember in = null; + ChannelMember in2 = null; for (ChannelMember cm: ch2.getInputChannelMembers()) { if (cm.getResource().equals(((ResourceNode) dIn.getSource()).getOutSideResource())) { - in = cm; + in2 = cm; break; } } - inputResourceToStateAccessor.put(in, JerseyCodeGenerator.pushAccessor); + inputResourceToStateAccessor.put(in2, JerseyCodeGenerator.pushAccessor); } } for (ChannelMember c: ch.getReferenceChannelMembers()) { @@ -186,77 +184,119 @@ } } } - if (resToCh.getDestination().getIndegree() > 1 - || (resToCh.getDestination().getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // Calculate in-degree of the destination resource. + Set inResources = new HashSet<>(); + for (ResourceNode rn: graph.getResourceNodes(out.getResource().getResourceHierarchy())) { + // ResourceNodes that have the same ResourceHierarchy. + for (Edge chToRes2: rn.getInEdges()) { + for (Edge resToCh2: chToRes2.getSource().getInEdges()) { + inResources.add(((ResourceNode) resToCh2.getSource()).getResourceHierarchy()); + } + } + } + int inDegree = inResources.size(); + if (inDegree > 1 + || (inDegree == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { // update a cache of src side resource (when incoming edges are multiple) String cacheStatement = "this." + JerseyCodeGenerator.toVariableName(srcResourceName) + " = " + JerseyCodeGenerator.toVariableName(srcResourceName) + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { update.addStatement(cacheStatement); - } - } - // 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); + } + // For a post/put REST API. + if (outsideOutputResource + || (in.getResource().getCommonPrefix(out.getResource()) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { + // Inter-services + if (dst.getResourceHierarchy().getParent() != null) { + // If not a root resource. + TypeDeclaration rootComponent = componentMap.get(JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getRoot())); + MethodDeclaration update2 = update; + update = getMethod(rootComponent, update2.getName()); // get the accessor to the update method. + // To make the accessor call the update method. + Expression resExp = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(out.getResource(), out.getResource().getRoot()); + String args = ""; + String delimiter = ""; + if (resExp instanceof Term) { + // to access the parent + if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) { + args += delimiter + ((Variable)((Term) resExp).getChild(1)).getName(); + delimiter = ", "; + } + resExp = ((Term) resExp).getChild(0); + } + String resourceAccess = resExp.toImplementation(new String[] {null}); + for (VariableDeclaration var: update2.getParameters()) { + args += delimiter + var.getName(); + delimiter = ", "; + } + update.addStatement(resourceAccess + "." + update2.getName() + "(" + args + ");"); + } + // 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.getBody().getStatements().contains(paramConverter)) { + update.addFirstStatement(paramConverter); + } + } } if (((StoreAttribute) dst.getAttribute()).isStored()) { // returns the state stored in a field. @@ -321,36 +361,88 @@ Type refResourceType = ref.getResourceStateType(); if (!referredSet.contains(ref)) { referredSet.add(ref); - generatePullDataTransfer(srcUpdate, refResourceName, refResourceName, refResourceType); + String[] sideEffects = new String[] {""}; + if (rc.isOutside()) { + List pathParams = new ArrayList<>(); + for (Expression pathExp: ref.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(srcUpdate, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType); + } else { + ResourcePath srcRes = in.getResource(); + if (!JerseyCodeGenerator.generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); + } + Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, srcRes); + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + srcUpdate.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); + } } // Value of a reference side resource. params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); } } } - 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.getResourceStateType(), - new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), "this.value"))); - srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); - srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, - JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResourceName), - 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.getResourceStateType(), - new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), "this.value"))); - srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); - srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, - JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResourceName), - httpMethod)); + ResourcePath dstRes = out.getResource(); + // Value of the source side (input side) resource. + String srcFieldName = "this.value"; + if (!JerseyCodeGenerator.generatesComponent(src.getResourceHierarchy())) { + srcFieldName = JerseyCodeGenerator.toVariableName(srcResourceName); } - srcUpdate.addThrow("JsonProcessingException"); + params.add(0, new AbstractMap.SimpleEntry<>(src.getResourceStateType(), + new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); + if (outsideOutputResource || (in.getResource().getCommonPrefix(dstRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { + // Inter-servces + String[] sideEffects = new String[] {""}; + List pathParams = new ArrayList<>(); + for (Expression pathExp: dstRes.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + String srcResName = JerseyCodeGenerator.toVariableName(srcResourceName); + if (inDegree <= 1) { + srcResName = null; + } + if (!chainedCalls.contains(srcUpdate)) { + // The first call to an update method in this method + srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); + srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, + dstRes.getResourceHierarchy().toResourcePath(pathParams), + srcResName, + httpMethod)); + chainedCalls.add(srcUpdate); + } else { + // After the second time of call to update methods in this method + srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); + srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, + dstRes.getResourceHierarchy().toResourcePath(pathParams), + srcResName, + httpMethod)); + } + srcUpdate.addThrow("JsonProcessingException"); + } else { + // Inner-service + String updateMethodName = null; + if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { + updateMethodName = "updateFrom" + srcResourceName; + } else { + updateMethodName = "update" + dstResourceName + "From" + srcResourceName; + } + String callParams = ""; + String delimiter = ""; + for (Map.Entry> paramEnt: params) { + callParams += delimiter + paramEnt.getValue().getValue(); + delimiter = ", "; + } + if (!chainedCalls.contains(srcUpdate)) { + // The first call to an update method in this method + srcUpdate.addStatement("String result = this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); + chainedCalls.add(srcUpdate); + } else { + // After the second time of call to update methods in this method + srcUpdate.addStatement("result = this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); + } + } } } for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { @@ -368,35 +460,87 @@ Type refResourceType = ref.getResourceStateType(); if (!referredSet.contains(ref)) { referredSet.add(ref); - generatePullDataTransfer(srcInput, refResourceName, refResourceName, refResourceType); + String[] sideEffects = new String[] {""}; + if (rc.isOutside()) { + List pathParams = new ArrayList<>(); + for (Expression pathExp: ref.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(srcInput, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType); + } else { + ResourcePath srcRes = in.getResource(); + if (!JerseyCodeGenerator.generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); + } + Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, srcRes); + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + srcInput.addFirstStatement(sideEffects[0] + refTypeName + " " + ref.getResourceName() + " = " + refExp + ";"); + } } // Value of a reference side resource. params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); } } - 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.getResourceStateType(), - new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), "this.value"))); - srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); - srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, - JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResourceName), - 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.getResourceStateType(), - new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), "this.value"))); - srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); - srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, - JerseyCodeGenerator.toVariableName(dstResourceName), - JerseyCodeGenerator.toVariableName(srcResourceName), - httpMethod)); + ResourcePath dstRes = out.getResource(); + // Value of the source side (input side) resource. + String srcFieldName = "this.value"; + if (!JerseyCodeGenerator.generatesComponent(src.getResourceHierarchy())) { + srcFieldName = JerseyCodeGenerator.toVariableName(srcResourceName); } - srcInput.addThrow("JsonProcessingException"); + params.add(0, new AbstractMap.SimpleEntry<>(src.getResourceStateType(), + new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); + if (outsideOutputResource || (in.getResource().getCommonPrefix(dstRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { + // Inter-services + String[] sideEffects = new String[] {""}; + List pathParams = new ArrayList<>(); + for (Expression pathExp: dstRes.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + String srcResName = JerseyCodeGenerator.toVariableName(srcResourceName); + if (inDegree <= 1) { + srcResName = null; + } + if (!chainedCalls.contains(srcInput)) { + // First call to an update method in this method + srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); + srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, + dstRes.getResourceHierarchy().toResourcePath(pathParams), + srcResName, + httpMethod)); + chainedCalls.add(srcInput); + } else { + // After the second time of call to update methods in this method + srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); + srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, + dstRes.getResourceHierarchy().toResourcePath(pathParams), + srcResName, + httpMethod)); + } + srcInput.addThrow("JsonProcessingException"); + } else { + // Inner-service + String updateMethodName = null; + if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { + updateMethodName = "updateFrom" + srcResourceName; + } else { + updateMethodName = "update" + dstResourceName + "From" + srcResourceName; + } + String callParams = ""; + String delimiter = ""; + for (Map.Entry> paramEnt: params) { + callParams += delimiter + paramEnt.getValue().getValue(); + delimiter = ", "; + } + if (!chainedCalls.contains(srcInput)) { + // The first call to an update method in this method + srcInput.addStatement("String result = this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); + chainedCalls.add(srcInput); + } else { + // After the second time of call to update methods in this method + srcInput.addStatement("result = this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); + } + } } } else if ((pushPull.getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // for pull (or push/pull) data transfer @@ -418,10 +562,26 @@ String curState = curExp.toImplementation(sideEffects); 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: ((ChannelNode) resToCh.getDestination()).getChannel().getReferenceChannelMembers()) { - String refResourceName = c.getResource().getResourceName(); - Type refResourceType = c.getResource().getResourceStateType(); - generatePullDataTransfer(getter, refResourceName, refResourceName, refResourceType); + for (ChannelMember rc: ch.getReferenceChannelMembers()) { + ResourcePath refRes = rc.getResource(); + String refResourceName = refRes.getResourceName(); + Type refResourceType = refRes.getResourceStateType(); + if (rc.isOutside()) { + List pathParams = new ArrayList<>(); + for (Expression pathExp: refRes.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(getter, refResourceName, refRes.getResourceHierarchy().toResourcePath(pathParams), refResourceType); + } else { + ResourcePath dstRes = out.getResource(); + if (!JerseyCodeGenerator.generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); + } + Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(refRes, dstRes); + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = refResourceType.getInterfaceTypeName(); + getter.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); + } } for (Entry>> pathEnt: resourcePaths.entrySet()) { ChannelMember cm = pathEnt.getKey(); @@ -575,7 +735,23 @@ Type refResourceType = ref.getResourceStateType(); if (!referredSet.contains(ref)) { referredSet.add(ref); - generatePullDataTransfer(input, refResourceName, refResourceName, refResourceType); + String[] sideEffects = new String[] {""}; + if (rc.isOutside()) { + List pathParams = new ArrayList<>(); + for (Expression pathExp: ref.getPathParams()) { + pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + generatePullDataTransfer(input, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType); + } else { + ResourcePath dstRes = out.getResource(); + if (!JerseyCodeGenerator.generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); + } + Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, dstRes); + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = refResourceType.getInterfaceTypeName(); + input.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); + } } } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java index 6be124c..53ea105 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataFlowGraph.java @@ -1,5 +1,6 @@ package models.dataFlowModel; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -7,6 +8,7 @@ import java.util.Set; import models.DirectedGraph; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; public class DataFlowGraph extends DirectedGraph { @@ -81,6 +83,17 @@ return resourceNodeMap.values(); } + public Collection getResourceNodes(ResourceHierarchy resourceHierarchy) { + Collection resourceNodes = new ArrayList<>(); + for (ResourceNode rn: resourceNodeMap.values()) { + if (rn.getResourceHierarchy() == resourceHierarchy) { + resourceNodes.add(rn); + } + } + return resourceNodes; + } + + public Collection getChannelNodes() { return channelNodeMap.values(); }