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) {