diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 3f8105c..495452c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -750,35 +750,53 @@ for (Edge resToCh: chToRes.getSource().getInEdges()) { DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); DataFlowEdge re = (DataFlowEdge) resToCh; - ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); - String srcResComponentName = getComponentName(srcRes.getResourceHierarchy(), langSpec); + ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(); + String srcResComponentName = getComponentName(srcResPath.getResourceHierarchy(), langSpec); String srcResName = langSpec.toVariableName(srcResComponentName); // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().equals(srcRes) && cm.isOutside()) { + if (cm.getResource().equals(srcResPath) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } } // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = false; + ResourcePath dstResPath = 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())) { + dstResPath = cm.getResource(); + if (cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } } } if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // for push data transfer // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - vars.add(langSpec.newVariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); + ArrayList parameters = new ArrayList<>(); + for (Expression exp: dstResPath.getPathParams()) { + if (exp instanceof Variable) { + Variable pathVar = (Variable) exp; + VariableDeclaration pathParam = langSpec.newVariableDeclaration(pathVar.getType(), pathVar.getName()); + parameters.add(pathParam); // A path parameter to identify the self resource. + } + } + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + VariableDeclaration chParam = langSpec.newVariableDeclaration(selVar.getType(), selVar.getName()); + parameters.add(chParam); // A channel parameter to specify the context of the collaboration. + } + } + parameters.add(langSpec.newVariableDeclaration(srcResPath.getResourceStateType(), srcResPath.getResourceName())); // The state of the source resource to carry the data-flow. // For the refs. for (ResourcePath ref: ch.getReferenceResources()) { if (!resourceNode.getInSideResources().contains(ref)) { - vars.add(langSpec.newVariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); + parameters.add(langSpec.newVariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); } } MethodDeclaration update = null; @@ -790,7 +808,7 @@ } } if (update == null) { - update = langSpec.newMethodDeclaration(updateMethodPrefix + from + srcResComponentName, false, null, vars); + update = langSpec.newMethodDeclaration(updateMethodPrefix + from + srcResComponentName, false, null, parameters); component.addMethod(update); } } else if (parentComponent != null) { @@ -801,7 +819,7 @@ } } if (update == null) { - update = langSpec.newMethodDeclaration(updateMethodPrefix + resComponentName + from + srcResComponentName, false, null, vars); + update = langSpec.newMethodDeclaration(updateMethodPrefix + resComponentName + from + srcResComponentName, false, null, parameters); parentComponent.addMethod(update); } } @@ -895,9 +913,9 @@ if (langSpec.declareField()) { // Declare the cache field. FieldDeclaration cacheField = langSpec.newFieldDeclaration( - srcRes.getResourceStateType(), - srcRes.getResourceName(), - langSpec.getFieldInitializer(srcRes.getResourceStateType(), srcRes.getResourceHierarchy().getInitialValue())); + srcResPath.getResourceStateType(), + srcResPath.getResourceName(), + langSpec.getFieldInitializer(srcResPath.getResourceStateType(), srcResPath.getResourceHierarchy().getInitialValue())); if (component != null) { component.addField(cacheField); } else if (parentComponent != null){ @@ -934,7 +952,7 @@ if (resourcePaths != null && resourcePaths.size() > 0) { for (ChannelMember outsideMember: outsideInputMembers) { for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) { - if (dependingMember.getResource().equals(srcRes)) { + if (dependingMember.getResource().equals(srcResPath)) { // An outside input resource path depends on srcRes. ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); @@ -990,15 +1008,34 @@ ResourceNode dstNode = ((ResourceNode) chToRes2.getDestination()); // Check if the output resource is outside of the channel scope. boolean outsideOutputResource2 = false; + ChannelMember out = null; for (ChannelMember cm: ch2.getOutputChannelMembers()) { - if (dstNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { - outsideOutputResource2 = true; + if (dstNode.getInSideResources().contains(cm.getResource())) { + out = cm; + if (cm.isOutside()) { + outsideOutputResource2 = true; + break; + } } } if ((((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { // PUSH transfer - Map> referredResources = new HashMap<>(); - List params = new ArrayList<>(); + List params = new ArrayList<>(); + // Values of path parameters. + for (Expression pathParam: out.getResource().getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + params.add(pathVar.getName()); + } + } + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(selVar.getName()); + } + } + // Value of the source side (input side) resource. ResourceHierarchy srcRes2 = resourceNode.getResourceHierarchy(); if (generatesComponent(srcRes2)) { params.add(langSpec.getFieldAccessor(fieldOfResourceState)); @@ -1006,6 +1043,7 @@ params.add(langSpec.getFieldAccessor(langSpec.toVariableName(srcRes2.getResourceName()))); srcRes2 = srcRes2.getParent(); } + Map> referredResources = new HashMap<>(); Set referredSet = referredResources.get(update); for (ChannelMember rc: ch2.getReferenceChannelMembers()) { // to get the value of reference member. @@ -1134,32 +1172,36 @@ // Declare an input method in this component. ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); + // The path parameters are not to be passed to the input method of each resource (resInputParams) + // because they are always equal to either channel selectors or message parameters. + + // Channel parameters to specify the context of the collaboration. int v = 1; - if (out.getResource().getLastParam() != null) { - Expression param = out.getResource().getLastParam(); - if (param instanceof Variable) { - Variable var = (Variable) param; - resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; + for (Selector selector: ch.getSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + resInputParams.add(langSpec.newVariableDeclaration(selVar.getType(), selVar.getName())); + mainInputParams.add(langSpec.newVariableDeclaration(selVar.getType(), selVar.getName())); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); resInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); - mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; } - if (out.getResource().getParent() != null) { - for (Expression param: out.getResource().getParent().getPathParams()) { - if (param instanceof Variable) { - Variable var = (Variable) param; - mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); + if (ch.getParent() != null) { + for (Selector selector: ch.getParent().getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + mainInputParams.add(langSpec.newVariableDeclaration(selVar.getType(), selVar.getName())); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); + mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; } } + // Message parameters to carry the data-flows. for (Map.Entry varEnt: message.getVariables().entrySet()) { Variable var = varEnt.getValue(); String refVarName = null; @@ -1345,6 +1387,14 @@ resExp = ((Term) resExp).getChild(0); } String resourceAccess = resExp.toImplementation(new String[] {null}); + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + args.add(selVar.getName()); + } + } + // Values of message parameters. if (message instanceof Term) { for (Map.Entry varEnt: message.getVariables().entrySet()) { String refVarName = null; @@ -1452,15 +1502,35 @@ ResourceNode dstNode = ((ResourceNode) chToRes.getDestination()); // Check if the output resource is outside of the channel scope. boolean outsideOutputResource2 = false; + ChannelMember out2 = null; for (ChannelMember cm: ch2.getOutputChannelMembers()) { - if (dstNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { - outsideOutputResource2 = true; + if (dstNode.getInSideResources().contains(cm.getResource())) { + out2 = cm; + if (cm.isOutside()) { + outsideOutputResource2 = true; + break; + } } } if ((((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { // PUSH transfer Map> referredResources = new HashMap<>(); List params = new ArrayList<>(); + // Values of path parameters. + for (Expression pathParam: out2.getResource().getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + params.add(pathVar.getName()); + } + } + // Values of channel parameters. + for (Selector selector: ch2.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(selVar.getName()); + } + } + // Value of the source side (input side) resource. ResourceHierarchy srcRes = resourceNode.getResourceHierarchy(); if (generatesComponent(srcRes)) { params.add(langSpec.getFieldAccessor(fieldOfResourceState)); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 502b883..00efe62 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -11,6 +11,7 @@ import java.util.Set; import java.util.Stack; +import code.ast.Annotation; import code.ast.Block; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; @@ -311,39 +312,6 @@ if (component == null) { // Declare reference fields for push/pull data transfer. boolean noPullTransfer = true; -// for (Edge resToCh : resourceNode.getOutEdges()) { -// DataFlowEdge re = (DataFlowEdge) resToCh; -// DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); -// for (Edge chToRes: re.getDestination().getOutEdges()) { -// ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); -// // Check if the output resource is outside of the channel scope. -// boolean outsideOutputResource = false; -// for (ChannelMember cm: ch.getOutputChannelMembers()) { -// if (cm.getResource().getResourceHierarchy().equals(dstRes.getResourceHierarchy()) && cm.isOutside()) { -// outsideOutputResource = true; // Regarded as push transfer. -// break; -// } -// } -// if (outsideOutputResource) { // This logic may be incorrect. (ToDo) -// // Declare a field in the parent component to refer to the destination resource of push transfer. -// if (!generatesComponent(dstRes.getResourceHierarchy())) { -// dstRes = dstRes.getParent(); -// } -// String dstResName = getComponentName(dstRes.getResourceHierarchy()); -// FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); -// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); -// if (dstRes.getParent() != null) { -// // Reference to root resource. -// ResourcePath dstRootRes = dstRes.getRoot(); -// String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); -// Type dstRootResType = new Type(dstRootResName, dstRootResName); -// FieldDeclaration refRootFieldForPush = new FieldDeclaration(dstRootResType, toVariableName(dstRootResName)); -// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPush)); -// constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), new VariableDeclaration(dstRootResType, toVariableName(dstRootResName)))); -// } -// } -// } -// } for (Edge chToRes : resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; @@ -367,22 +335,6 @@ } if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { noPullTransfer = false; -// // Declare a field in the parent component to refer to the source resource of pull transfer. -// if (!generatesComponent(srcRes.getResourceHierarchy())) { -// srcRes = srcRes.getParent(); -// } -// String srcResName = getComponentName(srcRes.getResourceHierarchy()); -// FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); -// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); -// if (srcRes.getParent() != null) { -// // Reference to root resource. -// ResourcePath srcRootRes = srcRes.getRoot(); -// String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); -// Type srcRootResType = new Type(srcRootResName, srcRootResName); -// FieldDeclaration refRootFieldForPull = new FieldDeclaration(srcRootResType, toVariableName(srcRootResName)); -// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPull)); -// constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), new VariableDeclaration(srcRootResType, toVariableName(srcRootResName)))); -// } } } } @@ -434,7 +386,6 @@ } } - // Declare reference fields and update methods in the type of each resource. // Declare reference fields for push data transfer. for (Edge resToCh : resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; @@ -505,7 +456,7 @@ } } } - // Declare reference fields for pull data transfer. + // Declare update methods for push data transfer and reference fields for pull data transfer. for (Edge chToRes : resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; @@ -521,10 +472,14 @@ } // 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()); @@ -577,18 +532,31 @@ } } else { // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - vars.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); - DataTransferChannel c = ((ChannelNode) resToCh.getDestination()).getChannel(); - for (ResourcePath ref: c.getReferenceResources()) { + ArrayList params = new ArrayList<>(); + for (Expression exp: out.getResource().getPathParams()) { + if (exp instanceof Variable) { + Variable pathVar = (Variable) exp; + VariableDeclaration pathParam = new VariableDeclaration(pathVar.getType(), pathVar.getName()); + params.add(pathParam); // A path parameter to identify the self resource. + } + } + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); + params.add(chParam); // A channel parameter to specify the context of the collaboration. + } + } + params.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); // The state of the source resource to carry the data-flow. + for (ResourcePath ref: ch.getReferenceResources()) { if (!ref.equals(resourceNode.getOutSideResource())) { - vars.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); + params.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); } } MethodDeclaration update = null; if (component != null) { // A component is created for this resource. - update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, vars); + update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, params); component.addMethod(update); } else { // No component is created for this resource. @@ -600,7 +568,7 @@ updates.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); } if (nameToMethod.get(updateMethodName) == null) { - update = new MethodDeclaration(updateMethodName, false, typeVoid, vars); + update = new MethodDeclaration(updateMethodName, false, typeVoid, params); nameToMethod.put(updateMethodName, update); } } @@ -663,32 +631,36 @@ // In each resource. ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); + // The path parameters are not to be passed to the input method of each resource (resInputParams) + // because they are always equal to either channel selectors or message parameters. + + // Channel parameters to specify the context of the collaboration. int v = 1; - if (cm.getResource().getLastParam() != null) { - Expression param = cm.getResource().getLastParam(); - if (param instanceof Variable) { - Variable var = (Variable) param; - resInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; + for (Selector selector: ch.getSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + resInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName())); + mainInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName())); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); resInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); - mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); + mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); } v++; } - if (cm.getResource().getParent() != null) { - for (Expression param: cm.getResource().getParent().getPathParams()) { - if (param instanceof Variable) { - Variable var = (Variable) param; - mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); + if (ch.getParent() != null) { + for (Selector selector: ch.getParent().getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + mainInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName())); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); + mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); } v++; } } + // Message parameters to carry the data-flows. for (Map.Entry varEnt: message.getVariables().entrySet()) { Variable var = varEnt.getValue(); String refVarName = null; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 9cb1c6c..36ef35d 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -1,5 +1,6 @@ package generators; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -32,6 +33,7 @@ import models.dataConstraintModel.JsonAccessor; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; @@ -233,6 +235,23 @@ srcResName = srcResourceName; } for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent, srcResName)) { + ResourcePath dstRes = out.getResource(); + // Values of path parameters. + String pathParams = ""; + for (Expression pathParam: dstRes.getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams += pathVar.getName() + ", "; + } + } + // Values of channel parameters. + String chParams = ""; + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + chParams += selVar.getName() + ", "; + } + } String refParams = ""; Set referredSet = referredResources.get(srcUpdate); for (ChannelMember rc: ch.getReferenceChannelMembers()) { @@ -261,6 +280,7 @@ } else { updateMethodName = "update" + dstResourceName + "From" + srcResourceName; } + // Value of the source side (input side) resource. String srcFieldName = "value"; if (!JavaCodeGenerator.generatesComponent(src.getResourceHierarchy())) { srcFieldName = JavaCodeGenerator.toVariableName(srcResourceName); @@ -268,16 +288,33 @@ if (!outsideOutputResource) { // The destination resource is not outside. if (srcComponent != dstComponent) { - srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); + srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); } else { - srcUpdate.addStatement("this." + updateMethodName + "(" + srcFieldName + refParams + ");"); + srcUpdate.addStatement("this." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); } } else { // Use the reference field to refer to outside destination resource. - srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); + srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); } } for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { + ResourcePath dstRes = out.getResource(); + // Values of path parameters. + String pathParams = ""; + for (Expression pathParam: dstRes.getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams += pathVar.getName() + ", "; + } + } + // Values of channel parameters. + String chParams = ""; + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + chParams += selVar.getName() + ", "; + } + } String refParams = ""; Set referredSet = referredResources.get(srcInput); for (ChannelMember rc: ch.getReferenceChannelMembers()) { @@ -313,13 +350,13 @@ if (!outsideOutputResource) { // The destination resource is not outside. if (srcComponent != dstComponent) { - srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); + srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); } else { - srcInput.addStatement("this." + updateMethodName + "(" + srcFieldName + refParams + ");"); + srcInput.addStatement("this." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); } } else { // Use the reference field to refer to outside destination resource. - srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + srcFieldName + refParams + ");"); + srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); } } } else if ((pushPull.getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { @@ -587,22 +624,23 @@ Map> ioChannelsAndMembers = getIOChannelsAndMembers(resource, model); for (Map.Entry> entry: ioChannelsAndMembers.entrySet()) { Set outs = entry.getValue(); + DataTransferChannel ch = entry.getKey(); for (ChannelMember out: outs) { MethodDeclaration input = null; if (JavaCodeGenerator.generatesComponent(resource)) { // A component is generated for this resource. - input = getInputMethod(component, out, entry.getKey().getOutputChannelMembers().size()); + input = getInputMethod(component, out, ch.getOutputChannelMembers().size()); } else { // No component is generated for this resource. ResourceHierarchy parent = resource.getParent(); if (parent != null) { TypeDeclaration parentType = componentMap.get(JavaCodeGenerator.getComponentName(parent)); - input = getInputMethod(parentType, out, entry.getKey().getOutputChannelMembers().size()); + input = getInputMethod(parentType, out, ch.getOutputChannelMembers().size()); } } if (input != null) { // In each resource - Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JavaCodeGenerator.refAccessor); + Expression updateExp = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.refAccessor); // Replace Json constructor with a constructor of the child resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { @@ -669,7 +707,7 @@ MethodDeclaration inputAccessor = getMethod(mainComponent, inputAccessorName); if (inputAccessor != null) { Set referredSet = referredResources.get(input); - for (ChannelMember rc: entry.getKey().getReferenceChannelMembers()) { + for (ChannelMember rc: ch.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) { @@ -700,10 +738,19 @@ resExp = ((Term) resExp).getChild(0); } String resourceAccess = resExp.toImplementation(new String[] {null}); + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + args += delimiter + selVar.getName(); + delimiter = ", "; + } + } + // Values of message parameters. if (message instanceof Term) { for (Map.Entry varEnt: message.getVariables().entrySet()) { String refVarName = null; - for (ChannelMember rc: entry.getKey().getReferenceChannelMembers()) { + for (ChannelMember rc: ch.getReferenceChannelMembers()) { Expression varExp = rc.getStateTransition().getMessageExpression().getSubTerm(varEnt.getKey()); if (varExp != null && rc.getStateTransition().getCurStateExpression().contains(varExp)) { refVarName = rc.getResource().getResourceName(); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 18c8b1b..bb2c4b4 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -570,30 +570,39 @@ } } // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); + ArrayList params = new ArrayList<>(); + getUpdateResourcePathAndPathParams(out.getResource(), params, isRestAPI); // Path parameters to identify the self resource. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); + if (isRestAPI) chParam.addAnnotation(new Annotation("FormParam", "\"" + selVar.getName() + "\"")); + params.add(chParam); // A channel parameter to specify the context of the collaboration. + } + } String srcName = toVariableName(srcResName); VariableDeclaration param = new VariableDeclaration(srcType, srcName); if (isRestAPI) param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); - vars.add(param); - for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { + params.add(param); // The state of the source resource to carry the data-flow. + for (ResourcePath refRes: ch.getReferenceResources()) { if (!refRes.equals(resourceNode.getOutSideResource())) { param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); if (isRestAPI) param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); - vars.add(param); + params.add(param); } } MethodDeclaration update = null; if (component != null) { // A component is created for this resource. - update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, vars); + update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, params); } else { // No component is created for this resource. String resourceName = getComponentName(resourceNode.getResourceHierarchy()); - update = new MethodDeclaration("update" + resourceName + "From" + srcResName, false, typeVoid, vars); + update = new MethodDeclaration("update" + resourceName + "From" + srcResName, false, typeVoid, params); } // Determine whether the update method is put or post. boolean isPut = false; - for (ChannelMember cm: ((ChannelNode) re.getDestination()).getChannel().getOutputChannelMembers()) { + for (ChannelMember cm: ch.getOutputChannelMembers()) { if (resourceNode.getInSideResources().contains(cm.getResource())) { if (cm.getStateTransition().isRightUnary()) { isPut = true; @@ -655,19 +664,27 @@ 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); + params = new ArrayList<>(); + String resourcePath = getUpdateResourcePathAndPathParams(out.getResource(), params, true); // Path parameters to identify the self resource. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); + chParam.addAnnotation(new Annotation("FormParam", "\"" + selVar.getName() + "\"")); + params.add(chParam); // A channel parameter to specify the context of the collaboration. + } + } param = new VariableDeclaration(srcType, srcName); param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); - vars.add(param); - for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { + params.add(param); // The state of the source resource to carry the data-flow. + for (ResourcePath refRes: ch.getReferenceResources()) { if (!refRes.equals(resourceNode.getOutSideResource())) { param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); - vars.add(param); + params.add(param); } } - MethodDeclaration updateAccessor = new MethodDeclaration(updateMethodName, false, typeVoid, vars); + MethodDeclaration updateAccessor = new MethodDeclaration(updateMethodName, false, typeVoid, params); if (isPut) { updateAccessor.addAnnotation(new Annotation("PUT")); } else { @@ -707,12 +724,24 @@ // In each resource. ArrayList resInputParams = new ArrayList<>(); ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = getInputMethodResourcePathAndPathParams(cm.getResource(), resInputParams, rootInputParams); + String resourcePath = getInputMethodResourcePathAndPathParams(cm.getResource(), resInputParams, rootInputParams); // Path parameters for the input REST API. if (resourcePath.indexOf('/') > 0) { resourcePath = resourcePath.substring(resourcePath.indexOf('/')); } else { resourcePath = ""; } + // The path parameters are not to be passed to the input method of each resource (resInputParams) + // because they are always equal to either channel selectors or message parameters. + + // Channel parameters to specify the context of the collaboration. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); + resInputParams.add(chParam); + } + } + // Message parameters to carry the data-flows. for (Map.Entry varEnt: message.getVariables().entrySet()) { Variable var = varEnt.getValue(); String refVarName = null; @@ -1024,7 +1053,7 @@ return resPath.getResourceHierarchy().toResourcePath(params); } - private static String getUpdateAccessorResourcePathAndPathParams(ResourcePath resPath, ArrayList rootParams) { + private static String getUpdateResourcePathAndPathParams(ResourcePath resPath, ArrayList rootParams, boolean isRestAPI) { int v = 1; List params = new ArrayList<>(); for (Expression pathParam: resPath.getPathParams()) { @@ -1033,14 +1062,14 @@ String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + if (isRestAPI) 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 + "\"")); + if (isRestAPI) param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); rootParams.add(param); } v++; @@ -1048,8 +1077,7 @@ return resPath.getResourceHierarchy().toResourcePath(params); } - private static String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList resInputParams, - ArrayList rootInputParams) { + private static String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList resInputParams, ArrayList rootInputParams) { int v = 1; List params = new ArrayList<>(); if (resPath.getLastParam() != null) { @@ -1059,8 +1087,6 @@ String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - resInputParams.add(param); - param = new VariableDeclaration(var.getType(), paramName); param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); rootInputParams.add(param); } else if (pathParam instanceof Term) { @@ -1068,8 +1094,6 @@ String paramName = "v" + v; params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - resInputParams.add(param); - param = new VariableDeclaration(var.getType(), paramName); param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); rootInputParams.add(param); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index fffca54..c6d6a5d 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -35,6 +35,7 @@ import models.dataConstraintModel.JsonAccessor; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.PushPullAttribute; @@ -347,6 +348,22 @@ for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent, srcName)) { if (srcUpdate != null) { List>> params = new ArrayList<>(); + ResourcePath dstRes = out.getResource(); + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), + new AbstractMap.SimpleEntry<>(selVar.getName(), selVar.getName()))); + } + } + // Value of the source side (input side) resource. + String srcFieldName = "this.value"; + if (!JerseyCodeGenerator.generatesComponent(src.getResourceHierarchy())) { + srcFieldName = JerseyCodeGenerator.toVariableName(srcResourceName); + } + params.add(new AbstractMap.SimpleEntry<>(src.getResourceStateType(), + new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); Set referredSet = referredResources.get(srcUpdate); if (ch.getReferenceChannelMembers().size() > 0) { for (ChannelMember rc: ch.getReferenceChannelMembers()) { @@ -384,14 +401,6 @@ } } } - 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); - } - 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[] {""}; @@ -430,6 +439,15 @@ } String callParams = ""; String delimiter = ""; + // Values of path parameters. + for (Expression pathParam: dstRes.getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + callParams += delimiter + pathVar.getName(); + delimiter = ", "; + } + } + // Values of other parameters. for (Map.Entry> paramEnt: params) { callParams += delimiter + paramEnt.getValue().getValue(); delimiter = ", "; @@ -455,6 +473,22 @@ } for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { List>> params = new ArrayList<>(); + ResourcePath dstRes = out.getResource(); + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), + new AbstractMap.SimpleEntry<>(selVar.getName(), selVar.getName()))); + } + } + // Value of the source side (input side) resource. + String srcFieldName = "this.value"; + if (!JerseyCodeGenerator.generatesComponent(src.getResourceHierarchy())) { + srcFieldName = JerseyCodeGenerator.toVariableName(srcResourceName); + } + params.add(new AbstractMap.SimpleEntry<>(src.getResourceStateType(), + new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); Set referredSet = referredResources.get(srcInput); for (ChannelMember rc: ch.getReferenceChannelMembers()) { // For each reference channel member, get the current state of the reference side resource by pull data transfer. @@ -490,14 +524,6 @@ params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); } } - 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); - } - 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[] {""}; @@ -536,6 +562,15 @@ } String callParams = ""; String delimiter = ""; + // Values of path parameters. + for (Expression pathParam: dstRes.getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + callParams += delimiter + pathVar.getName(); + delimiter = ", "; + } + } + // Values of other parameters. for (Map.Entry> paramEnt: params) { callParams += delimiter + paramEnt.getValue().getValue(); delimiter = ", "; @@ -722,24 +757,25 @@ // methods for input events Map> ioChannelsAndMembers = getIOChannelsAndMembers(resource, model); for (Map.Entry> entry: ioChannelsAndMembers.entrySet()) { + DataTransferChannel ch = entry.getKey(); Set outs = entry.getValue(); for (ChannelMember out: outs) { MethodDeclaration input = null; if (JerseyCodeGenerator.generatesComponent(resource)) { // A component is generated for this resource. - input = getInputMethod(component, out, entry.getKey().getOutputChannelMembers().size()); + input = getInputMethod(component, out, ch.getOutputChannelMembers().size()); } else { // No component is generated for this resource. ResourceHierarchy parent = resource.getParent(); if (parent != null) { TypeDeclaration parentType = componentMap.get(JerseyCodeGenerator.getComponentName(parent)); - input = getInputMethod(parentType, out, entry.getKey().getOutputChannelMembers().size()); + input = getInputMethod(parentType, out, ch.getOutputChannelMembers().size()); } } if (input != null) { // In each resource Set referredSet = referredResources.get(input); - for (ChannelMember rc: entry.getKey().getReferenceChannelMembers()) { + for (ChannelMember rc: ch.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) { @@ -771,7 +807,7 @@ } } } - Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JerseyCodeGenerator.refAccessor); + Expression updateExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.refAccessor); // Replace Json constructor with a constructor of the child resource. ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { @@ -837,6 +873,7 @@ } MethodDeclaration inputAccessor = getMethod(componentMap.get(JerseyCodeGenerator.getComponentName(resource.getRoot())), inputAccessorName); if (inputAccessor != null) { + // The expression of the receiver (resource) of the input method. Expression resExp = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(out.getResource(), out.getResource().getRoot()); String args = ""; String delimiter = ""; @@ -849,9 +886,18 @@ resExp = ((Term) resExp).getChild(0); } String resourceAccess = resExp.toImplementation(new String[] {null}); + // Values of channel parameters. + for (Selector selector: ch.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable selVar = (Variable) selector.getExpression(); + args += delimiter + selVar.getName(); + delimiter = ", "; + } + } + // Values of message parameters. if (message instanceof Term) { - for (Variable var: message.getVariables().values()) { - args += delimiter + var.getName(); + for (Variable mesVar: message.getVariables().values()) { + args += delimiter + mesVar.getName(); delimiter = ", "; } }