diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index ed4339b..6119b8c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -625,6 +625,7 @@ Term getter = null; int v = 1; int arity = 2; + boolean doesChainInvocations = true; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy(), langSpec); @@ -653,6 +654,7 @@ } getter = newGetter; } else { + // add the last path parameter. if (curPath.getResourceHierarchy().getNumParameters() > 0) { Variable var = null; Expression param = curPath.getLastParam(); @@ -669,14 +671,19 @@ } } arity = 2; + doesChainInvocations = true; } else { - // to get a descendant resource directly. - if (arity == 2) { + // to get a descendant resource directly. (e.g, .todos.{year}.{month}.{day}.{id} ==> .getTodos().getTodo(year, month, day, id)) + if (doesChainInvocations) { Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); newGetter.addChild(getter); getter = newGetter; + doesChainInvocations = false; } if (curPath.getResourceHierarchy().getNumParameters() > 0) { + // may change the symbol name + getter.getSymbol().changeName("get" + typeName); + // add a path parameter. Variable var = null; Expression param = curPath.getLastParam(); if (param instanceof Variable) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index e5b3ce5..7513d41 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -110,7 +110,7 @@ declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, langSpec); } if (component != null) { - // Declare the getter methods in this resource to obtain the descendant resources. + // (#1) Declare the getter methods in this resource to obtain the descendant resources. (complementary to #2) declareDescendantGetterMethods(resourceNode, component, descendantGetters, langSpec); } } @@ -145,7 +145,7 @@ // Declare the fields to refer to other resources in the parent/this component, and the state field in the parent component. declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent, constructorParams, langSpec); - // Declare the getter method to obtain the resource state in an ancestor resource. + // (#2) Declare the getter method to obtain the resource state in an ancestor resource. (complementary to #1) if (component == null) { MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resourceComponents, resStateType, langSpec); @@ -247,24 +247,26 @@ if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { MethodDeclaration childConstructor = getConstructor(descendantComponent); List params = new ArrayList<>(); - for (VariableDeclaration var: childConstructor.getParameters()) { - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); - Expression param = jsonMember.reduce(); - if (param != null) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (childConstructor != null) { + for (VariableDeclaration var: childConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + params.add(param.toImplementation(new String[] {""})); + } else { + params.add(var.getName()); } - params.add(param.toImplementation(new String[] {""})); - } else { - params.add(var.getName()); } } ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); @@ -440,18 +442,32 @@ boolean noPullTransfer = true; for (Edge resToCh : resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + ChannelNode directDstChNode = (ChannelNode) re.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); // Check if the source resource is outside of the channel scope. boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (resourceNode.getOutSideResources().contains(cm.getResource()) && cm.isOutside()) { + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { + if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh)) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } } - for (Edge chToRes: re.getDestination().getOutEdges()) { + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes: outEdges) { if (chToRes.getDestination() instanceof ResourceNode) { ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = chNode.getChannel(); // Check if the destination resource is outside of the channel scope. boolean outsideOutputResource = false; for (ChannelMember cm: ch.getOutputChannelMembers()) { @@ -460,6 +476,13 @@ break; } } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // Declare a field in the parent component to refer to the destination resource of push transfer. if (!generatesComponent(dstRes)) { @@ -812,15 +835,30 @@ List constructorStatements = new ArrayList<>(); Map>> updateStatements = new HashMap<>(); for (Edge chToRes: resourceNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { - DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); + ChannelNode directSrcChannel = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = directSrcChannel.getChannel(); + // Should take into account the channel hierarchy. + Set ancestorSrcChannels = directSrcChannel.getAncestors(); + Set descendantSrcChannels = directSrcChannel.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(directSrcChannel.getInEdges()); + for (ChannelNode ancestorSrc: ancestorSrcChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantSrcChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + for (Edge resToCh: inEdges) { + // For each data transfer from srcResPath:ResourcePath to resourceNode:ResourceNode. DataFlowEdge re = (DataFlowEdge) resToCh; - ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(ch); + ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); + DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); + ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); 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()) { + for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { if (cm.getResource().equals(srcResPath) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; @@ -838,6 +876,13 @@ } } } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (ancestorSrcChannels.contains(indirectSrcChNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (descendantSrcChannels.contains(indirectSrcChNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // for push data transfer @@ -1099,13 +1144,14 @@ // Add an invocation to another update method (for a chain of update method invocations). for (Edge resToCh2: resourceNode.getOutEdges()) { DataFlowEdge dOut = (DataFlowEdge) resToCh2; - DataTransferChannel ch2 = ((ChannelNode) resToCh2.getDestination()).getChannel(); + ChannelNode directDstChNode = (ChannelNode) resToCh2.getDestination(); + DataTransferChannel directDstCh = directDstChNode.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 (resourceNode.getOutSideResources().contains(cm.getResource())) { + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { + if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh))) { if (cm.isOutside()) { outsideInputResource2 = true; // Regarded as pull transfer. } @@ -1115,8 +1161,22 @@ outsideInputMembers2.add(cm); } } - for (Edge chToRes2: resToCh2.getDestination().getOutEdges()) { + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes2: outEdges) { + // For each data transfer to dstNode:ResourceNode. ResourceNode dstNode = ((ResourceNode) chToRes2.getDestination()); + ChannelNode chNode2 = (ChannelNode) chToRes2.getSource(); + DataTransferChannel ch2 = chNode2.getChannel(); // Check if the output resource is outside of the channel scope. boolean outsideOutputResource2 = false; ChannelMember out = null; @@ -1129,6 +1189,13 @@ } } } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode2)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode2)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } if ((((PushPullAttribute) dOut.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { // PUSH transfer List params = new ArrayList<>(); @@ -1204,55 +1271,59 @@ if (outsideInputMembers2.size() > 0) { if (!generatesComponent(resourceNode.getResourceHierarchy())) { // srcRes2 does not have a component. - ResourcePath srcRes2 = resourceNode.getOutSideResource(ch2); - for (ChannelMember out: ch2.getOutputChannelMembers()) { - if (!generatesComponent(out.getResource().getResourceHierarchy())) { - // Also dstRes2 does not have a component. - ResourcePath dstRes2 = out.getResource(); - if (srcRes2.getParent().equals(dstRes2.getParent())) { - Map>> resourcePaths = null; - try { - resourcePaths = ch2.fillOutsideResourcePaths(out, getPullAccessor()); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: outsideInputMembers2) { - for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) { - if (dependingMember.getResource().equals(srcRes2)) { - // An outside input resource path depends on srcRes. - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (!generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); - Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null); - if (generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } - Expression nextExp = dependingMember.getStateTransition().getNextStateExpression(); - if (nextExp != null && outsideExp instanceof Term) { - if (nextExp instanceof Variable) { - outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(langSpec.toVariableName(getComponentName(dependingMember.getResource().getResourceHierarchy(), langSpec)))); - } else { - // ToDo. + ResourcePath srcRes2 = resourceNode.getOutSideResource(directDstCh); + for (Edge chToRes2: outEdges) { + ChannelNode chNode2 = (ChannelNode) chToRes2.getSource(); + DataTransferChannel ch2 = chNode2.getChannel(); + for (ChannelMember out: ch2.getOutputChannelMembers()) { + if (!generatesComponent(out.getResource().getResourceHierarchy())) { + // Also dstRes2 does not have a component. + ResourcePath dstRes2 = out.getResource(); + if (srcRes2.getParent().equals(dstRes2.getParent())) { + Map>> resourcePaths = null; + try { + resourcePaths = ch2.fillOutsideResourcePaths(out, getPullAccessor()); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: outsideInputMembers2) { + for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) { + if (dependingMember.getResource().equals(srcRes2)) { + // An outside input resource path depends on srcRes. + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); } - } - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); - update.addStatement(updateReference); // Update the reference field. - // Update constructor. - if (component != null) { - MethodDeclaration constructor = getConstructor(component); - constructor.addStatement(updateReference); // Initialize the reference field. - } else if (parentComponent != null) { - constructorStatements.add(updateReference); + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + Expression nextExp = dependingMember.getStateTransition().getNextStateExpression(); + if (nextExp != null && outsideExp instanceof Term) { + if (nextExp instanceof Variable) { + outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(langSpec.toVariableName(getComponentName(dependingMember.getResource().getResourceHierarchy(), langSpec)))); + } else { + // ToDo. + } + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); + update.addStatement(updateReference); // Update the reference field. + // Update constructor. + if (component != null) { + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(updateReference); // Initialize the reference field. + } else if (parentComponent != null) { + constructorStatements.add(updateReference); + } } } } } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 5dce75b..1091996 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -279,7 +279,7 @@ declareAccessorMethodInMainComponent(resourceNode, mainComponent); } if (component != null) { - // Declare the getter methods in this resource to obtain descendant resources. + // (#1) Declare the getter methods in this resource to obtain descendant resources. (complementary to #2) Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); if (descendants == null) { descendants = new HashSet<>(); @@ -365,7 +365,7 @@ } } - // Declare the getter method to obtain the resource state in an ancestor component. + // (#2) Declare the getter method to obtain the resource state in an ancestor component. (complementary to #1) if (component == null) { // No component is created for this resource. ResourceNode ancestorNode = resourceNode; @@ -417,17 +417,31 @@ // Declare reference fields for push data transfer. for (Edge resToCh : resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + ChannelNode directDstChNode = (ChannelNode) re.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (resourceNode.getOutSideResources().contains(cm.getResource()) && cm.isOutside()) { + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { + if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh)) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } } - for (Edge chToRes: re.getDestination().getOutEdges()) { + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes: outEdges) { ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = chNode.getChannel(); // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = false; for (ChannelMember cm: ch.getOutputChannelMembers()) { @@ -436,6 +450,13 @@ break; } } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // Declare a field to refer to the destination resource of push transfer. if (!generatesComponent(dstRes)) { @@ -484,16 +505,32 @@ } } } - // Declare update methods for push data transfer and reference fields for pull data transfer. + // Declare update methods called by other resources for push data transfer + // and reference fields for pull data transfer. for (Edge chToRes : resourceNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { + ChannelNode directSrcChannel = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = directSrcChannel.getChannel(); + // Should take into account the channel hierarchy. + Set ancestorSrcChannels = directSrcChannel.getAncestors(); + Set descendantSrcChannels = directSrcChannel.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(directSrcChannel.getInEdges()); + for (ChannelNode ancestorSrc: ancestorSrcChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantSrcChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + for (Edge resToCh: inEdges) { + // For each data transfer from srcResPath:ResourcePath to resourceNode:ResourceNode. DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch); + ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); + DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); + ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); // 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()) { + for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { + if (cm.getResource().equals(srcResPath) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } @@ -510,11 +547,18 @@ } } } - String srcResName = getComponentName(srcRes.getResourceHierarchy()); - ResourcePath srcRes2 = srcRes; + // Also take into account the channel hierarchy to determine push/pull transfer. + if (ancestorSrcChannels.contains(indirectSrcChNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (descendantSrcChannels.contains(indirectSrcChNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } + String srcResName = getComponentName(srcResPath.getResourceHierarchy()); + ResourcePath srcRes2 = srcResPath; String srcResName2 = srcResName; - if (!generatesComponent(srcRes.getResourceHierarchy())) { - srcRes2 = srcRes.getParent(); + if (!generatesComponent(srcResPath.getResourceHierarchy())) { + srcRes2 = srcResPath.getParent(); srcResName2 = getComponentName(srcRes2.getResourceHierarchy()); } if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { @@ -579,7 +623,7 @@ params.add(chParam); // A channel parameter to specify the context of the collaboration. } } - params.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getLeafResourceName())); // The state of the source resource to carry the data-flow. + params.add(new VariableDeclaration(srcResPath.getResourceStateType(), srcResPath.getLeafResourceName())); // The state of the source resource to carry the data-flow. for (ResourcePath ref: ch.getReferenceResources()) { if (!ref.equals(resourceNode.getInSideResource(ch))) { params.add(new VariableDeclaration(ref.getResourceStateType(), ref.getLeafResourceName())); @@ -1170,7 +1214,7 @@ : DataConstraintModel.typeInt); } // use the cached value as the current state - return new Field(targetRes.getLeafResourceName(), + return new Field(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1178,7 +1222,7 @@ @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes = target.getResource(); - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1191,7 +1235,7 @@ : DataConstraintModel.typeInt); } // for reference channel member - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1258,7 +1302,7 @@ } // for reference channel member Term getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - getter.addChild(new Field(targetRes.getLeafResourceName(), targetRes.getResourceStateType())); + getter.addChild(new Field(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType())); return getter; } else { // access from the outside of the hierarchy @@ -1272,6 +1316,7 @@ Term getter = null; int v = 1; int arity = 2; + boolean doesChainInvocations = true; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy()); @@ -1300,6 +1345,7 @@ } getter = newGetter; } else { + // add the last path parameter. if (curPath.getResourceHierarchy().getNumParameters() > 0) { Variable var = null; Expression param = curPath.getLastParam(); @@ -1316,14 +1362,19 @@ } } arity = 2; + doesChainInvocations = true; } else { - // to get a descendant resource directly. - if (arity == 2) { + // to get a descendant resource directly. (e.g, .todos.{year}.{month}.{day}.{id} ==> .getTodos().getTodo(year, month, day, id)) + if (doesChainInvocations) { Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); newGetter.addChild(getter); getter = newGetter; + doesChainInvocations = false; } if (curPath.getResourceHierarchy().getNumParameters() > 0) { + // may change the symbol name + getter.getSymbol().changeName("get" + typeName); + // add a path parameter. Variable var = null; Expression param = curPath.getLastParam(); if (param instanceof Variable) { @@ -1362,7 +1413,7 @@ : DataConstraintModel.typeInt); } // for reference channel member - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1370,7 +1421,7 @@ @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes = target.getResource(); - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1383,7 +1434,7 @@ : DataConstraintModel.typeInt); } // for reference channel member - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index affec83..ddaf925 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -66,13 +66,26 @@ if (!resToCh.isChannelToResource()) { PushPullAttribute pushPull = (PushPullAttribute) resToCh.getAttribute(); ResourceNode src = (ResourceNode) resToCh.getSource(); - for (Edge chToRes: resToCh.getDestination().getOutEdges()) { + ChannelNode directDstChNode = (ChannelNode) resToCh.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes: outEdges) { ResourceNode dst = (ResourceNode) chToRes.getDestination(); String srcResourceName = JavaCodeGenerator.getComponentName(src.getResourceHierarchy()); String dstResourceName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy()); TypeDeclaration srcComponent = componentMap.get(srcResourceName); TypeDeclaration dstComponent = componentMap.get(dstResourceName); - DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); +// DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); + DataTransferChannel ch = ((ChannelNode) chToRes.getSource()).getChannel(); for (ChannelMember out: ch.getOutputChannelMembers()) { if (dst.getInSideResources().contains(out.getResource())) { // Check if the input resource is outside of the channel scope. @@ -85,6 +98,13 @@ } // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = out.isOutside(); + // Take into account the channel hierarchy. + if (descendantDstChannels.contains(ch)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(ch)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } if ((pushPull.getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // for push data transfer MethodDeclaration update = null; @@ -221,7 +241,7 @@ } } if (resToCh.getDestination().getIndegree() > 1 - || (resToCh.getDestination().getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + || (resToCh.getDestination().getIndegree() == 1 && directDstCh.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { // update a cache of src side resource (when incoming edges are multiple) String cacheStatement = "this." + JavaCodeGenerator.toVariableName(srcResourceName) + " = " + JavaCodeGenerator.toVariableName(srcResourceName) + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { @@ -319,7 +339,7 @@ referredResources.put(srcUpdate, referredSet); } if (!dst.getInSideResources().contains(ref)) { - String refVarName = ref.getLeafResourceName(); + String refVarName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(ref.getResourceHierarchy())); if (!referredSet.contains(ref)) { referredSet.add(ref); Expression refGetter = JavaCodeGenerator.pullAccessor.getCurrentStateAccessorFor(rc, in); @@ -382,7 +402,7 @@ referredResources.put(srcInput, referredSet); } if (!dst.getInSideResources().contains(ref)) { - String refVarName = ref.getLeafResourceName(); + String refVarName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(ref.getResourceHierarchy())); if (!referredSet.contains(ref)) { referredSet.add(ref); Expression refGetter = JavaCodeGenerator.pullAccessor.getCurrentStateAccessorFor(rc, in); @@ -902,26 +922,28 @@ String constructorInvocation = "new " + replacingClassName + "("; MethodDeclaration descendantConstructor = getConstructor(descendantComponent); String delimiter = ""; - for (VariableDeclaration var: descendantConstructor.getParameters()) { - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); - Expression param = jsonMember.reduce(); - if (param != null) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (descendantConstructor != null) { + for (VariableDeclaration var: descendantConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); - } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); + delimiter = ", "; } - delimiter = ", "; } constructorInvocation += ")"; ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation, descendantType)); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index ce5c62d..d1671ff 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -225,7 +225,7 @@ component.addMethod(stateGetter); } if (component != null) { - // Declare the getter methods in this resource to obtain descendant resources. + // (#1) Declare the getter methods in this resource to obtain descendant resources. (complementary to #2) Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); if (descendants == null) { descendants = new HashSet<>(); @@ -391,7 +391,7 @@ } } - // Declare the getter method to obtain the resource state in an ancestor component. + // (#2) Declare the getter method to obtain the resource state in an ancestor component. (complementary to #1) if (component == null) { // No component is created for this resource. ResourceNode ancestorNode = resourceNode; @@ -470,22 +470,55 @@ getterAccessors.put(resourceNode.getResourceHierarchy(), getterAccessor); } - // Declare a client field and update methods from other resources. + // Declare a client field for push data transfer. for (Edge resToCh: resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + ChannelNode directDstChNode = (ChannelNode) re.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().equals(resourceNode.getOutSideResource(ch)) && cm.isOutside()) { + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { + if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh)) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } } - for (ChannelMember cm: ch.getOutputChannelMembers()) { - ResourcePath dstRes = cm.getResource(); + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes: outEdges) { + // For each data transfer to dstNode:ResourceNode. + ResourceNode dstNode = ((ResourceNode) chToRes.getDestination()); + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = chNode.getChannel(); // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = cm.isOutside(); + boolean outsideOutputResource = false; + ChannelMember out = null; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (dstNode.getInSideResources().contains(cm.getResource())) { + out = cm; + if (cm.isOutside()) { + outsideOutputResource = true; + break; + } + } + } + ResourcePath dstRes = out.getResource(); + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } if (!bDeclareClientField && ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource)) { // For push transfer. if (!generatesComponent(dstRes.getResourceHierarchy())) { @@ -525,15 +558,32 @@ } } } + // Declare update methods called by other resources for push data transfer + // and reference fields for pull data transfer. for (Edge chToRes : resourceNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { + ChannelNode directSrcChannel = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = directSrcChannel.getChannel(); + // Should take into account the channel hierarchy. + Set ancestorSrcChannels = directSrcChannel.getAncestors(); + Set descendantSrcChannels = directSrcChannel.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(directSrcChannel.getInEdges()); + for (ChannelNode ancestorSrc: ancestorSrcChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantSrcChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + for (Edge resToCh: inEdges) { + // For each data transfer from srcResPath:ResourcePath to resourceNode:ResourceNode. DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch); + ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); + DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); + ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); // 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()) { + for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { + if (cm.getResource().equals(srcResPath) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } @@ -550,14 +600,21 @@ } } } - String srcResName = getComponentName(srcRes.getResourceHierarchy()); - Type srcType = srcRes.getResourceStateType(); - if (!generatesComponent(srcRes.getResourceHierarchy())) { - srcRes = srcRes.getParent(); + // Also take into account the channel hierarchy to determine push/pull transfer. + if (ancestorSrcChannels.contains(indirectSrcChNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (descendantSrcChannels.contains(indirectSrcChNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } + String srcResName = getComponentName(srcResPath.getResourceHierarchy()); + Type srcType = srcResPath.getResourceStateType(); + if (!generatesComponent(srcResPath.getResourceHierarchy())) { + srcResPath = srcResPath.getParent(); } if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // For pull transfer. - if (outsideInputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices)) { + if (outsideInputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcResPath) == null && differentTreesAsDifferentServices)) { // Inter-service if (!bDeclareClientField) { // Declare a client field to connect to the source resource of pull transfer. @@ -577,12 +634,12 @@ FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); if (component != null) { // A component is created for this resource. - if (resourceNode.getResourceHierarchy() != srcRes.getResourceHierarchy()) { + if (resourceNode.getResourceHierarchy() != srcResPath.getResourceHierarchy()) { component.addField(srcRefField); } } else { // No component is created for this resource. - if (resourceNode.getParent().getResourceHierarchy() != srcRes.getResourceHierarchy()) { + if (resourceNode.getParent().getResourceHierarchy() != srcResPath.getResourceHierarchy()) { fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField)); } } @@ -591,7 +648,7 @@ // For push transfer. boolean hasRestAPI = false; boolean isRestAPI = false; - if (outsideOutputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices)) { + if (outsideOutputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcResPath) == null && differentTreesAsDifferentServices)) { // Inter-service hasRestAPI = true; if (resourceNode.getParent() == null) { @@ -1350,7 +1407,7 @@ : DataConstraintModel.typeInt); } // use the cached value as the current state - return new Field(targetRes.getLeafResourceName(), + return new Field(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1358,7 +1415,7 @@ @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes = target.getResource(); - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1384,7 +1441,7 @@ } } // for reference channel member - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1398,7 +1455,7 @@ return getDirectStateAccessorFor(targetRes, fromRes); } } - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1412,7 +1469,7 @@ : DataConstraintModel.typeInt); } // for reference channel member - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } else { @@ -1428,6 +1485,7 @@ Term getter = null; int v = 1; int arity = 2; + boolean doesChainInvocations = true; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy()); @@ -1456,6 +1514,7 @@ } getter = newGetter; } else { + // add the last path parameter. if (curPath.getResourceHierarchy().getNumParameters() > 0) { Variable var = null; Expression param = curPath.getLastParam(); @@ -1472,14 +1531,19 @@ } } arity = 2; + doesChainInvocations = true; } else { - // to get a descendant resource directly. - if (arity == 2) { + // to get a descendant resource directly. (e.g, .todos.{year}.{month}.{day}.{id} ==> .getTodos().getTodo(year, month, day, id)) + if (doesChainInvocations) { Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); newGetter.addChild(getter); getter = newGetter; + doesChainInvocations = false; } if (curPath.getResourceHierarchy().getNumParameters() > 0) { + // may change the symbol name + getter.getSymbol().changeName("get" + typeName); + // add a path parameter. Variable var = null; Expression param = curPath.getLastParam(); if (param instanceof Variable) { @@ -1518,7 +1582,7 @@ : DataConstraintModel.typeInt); } // for reference channel member - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } @@ -1526,7 +1590,7 @@ @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourcePath targetRes = target.getResource(); - return new Parameter(targetRes.getLeafResourceName(), + return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() : DataConstraintModel.typeInt); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index ab32c63..bedb738 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -17,6 +17,7 @@ import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; import models.Edge; +import models.Node; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.Field; @@ -71,19 +72,35 @@ if (!resToCh.isChannelToResource()) { PushPullAttribute pushPull = (PushPullAttribute) resToCh.getAttribute(); ResourceNode src = (ResourceNode) resToCh.getSource(); - for (Edge chToRes: resToCh.getDestination().getOutEdges()) { + ChannelNode directDstChNode = (ChannelNode) resToCh.getDestination(); + DataTransferChannel directDstCh = directDstChNode.getChannel(); + // Should take into account the channel hierarchy. + Set ancestorDstChannels = directDstChNode.getAncestors(); + Set descendantDstChannels = directDstChNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(directDstChNode.getOutEdges()); + for (ChannelNode ancestorDst: ancestorDstChannels) { + outEdges.addAll(ancestorDst.getOutEdges()); + } + for (ChannelNode descendantDst: descendantDstChannels) { + outEdges.addAll(descendantDst.getOutEdges()); + } + for (Edge chToRes: outEdges) { + // For each data transfer from src:ResourceNode to dst:ResourceNode. ResourceNode dst = (ResourceNode) chToRes.getDestination(); String srcResourceName = JerseyCodeGenerator.getComponentName(src.getResourceHierarchy()); String dstResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy()); TypeDeclaration srcComponent = componentMap.get(srcResourceName); TypeDeclaration dstComponent = componentMap.get(dstResourceName); - DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); +// DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + DataTransferChannel ch = chNode.getChannel(); for (ChannelMember out: ch.getOutputChannelMembers()) { 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()) { + for (ChannelMember cm: directDstCh.getInputChannelMembers()) { if (src.getOutSideResources().contains(cm.getResource())) { in = cm; if (cm.isOutside()) { @@ -94,6 +111,13 @@ } // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = out.isOutside(); + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantDstChannels.contains(chNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } + if (ancestorDstChannels.contains(chNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } if ((pushPull.getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { // for push data transfer MethodDeclaration update = null; @@ -253,7 +277,7 @@ } int inDegree = inResources.size(); if (inDegree > 1 - || (inDegree == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + || (inDegree == 1 && directDstCh.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)) { @@ -285,7 +309,11 @@ int v = 0; for (VariableDeclaration var: update2.getParameters()) { if (v < out.getResource().getPathParams().size()) { - args += delimiter + ((Variable) out.getResource().getPathParams().get(v)).getName(); + if (out.getResource().getPathParams().get(v) instanceof Variable) { + args += delimiter + ((Variable) out.getResource().getPathParams().get(v)).getName(); + } else if (out.getResource().getPathParams().get(v) instanceof JsonAccessor) { + args += delimiter + ((JsonAccessor) out.getResource().getPathParams().get(v)).toImplementation(new String[] {}); // ToDo. + } } else { args += delimiter + var.getName(); } @@ -436,7 +464,7 @@ referredResources.put(srcUpdate, referredSet); } if (!dst.getInSideResources().contains(ref)) { - String refResourceName = ref.getLeafResourceName(); + String refResourceName = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(ref.getResourceHierarchy())); Type refResourceType = ref.getResourceStateType(); if (!referredSet.contains(ref)) { referredSet.add(ref); @@ -474,21 +502,23 @@ if (inDegree <= 1) { srcResName = null; } + Entry> filledEntry = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor).get(out); + String dstPath = null; + if (filledEntry != null) { + ResourcePath filledDstPath = filledEntry.getKey(); + dstPath = filledDstPath.toString().replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + } else { + dstPath = dstRes.getResourceHierarchy().toResourcePath(pathParams); + } 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)); + srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstPath, 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.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstPath, srcResName, httpMethod)); } srcUpdate.addThrow("JsonProcessingException"); } else { @@ -552,7 +582,7 @@ referredResources.put(srcInput, referredSet); } if (!dst.getInSideResources().contains(ref)) { - String refResourceName = ref.getLeafResourceName(); + String refResourceName = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(ref.getResourceHierarchy())); Type refResourceType = ref.getResourceStateType(); if (!referredSet.contains(ref)) { referredSet.add(ref); @@ -571,7 +601,7 @@ Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, srcRes); String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - srcInput.addFirstStatement(sideEffects[0] + refTypeName + " " + ref.getLeafResourceName() + " = " + refExp + ";"); + srcInput.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); } } // Value of a reference side resource. @@ -589,21 +619,23 @@ if (inDegree <= 1) { srcResName = null; } + Entry> filledEntry = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor).get(out); + String dstPath = null; + if (filledEntry != null) { + ResourcePath filledDstPath = filledEntry.getKey(); + dstPath = filledDstPath.toString().replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); + } else { + dstPath = dstRes.getResourceHierarchy().toResourcePath(pathParams); + } 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)); + srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstPath, 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.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstPath, srcResName, httpMethod)); } srcInput.addThrow("JsonProcessingException"); } else { @@ -1022,27 +1054,29 @@ if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { String constructorInvocation = "new " + replacingClassName + "("; MethodDeclaration descendantConstructor = getConstructor(descendantComponent); - String delimiter = ""; - for (VariableDeclaration var: descendantConstructor.getParameters()) { - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); - Expression param = jsonMember.reduce(); - if (param != null) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (descendantConstructor != null) { + String delimiter = ""; + for (VariableDeclaration var: descendantConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); - } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); + delimiter = ", "; } - delimiter = ", "; } constructorInvocation += ")"; ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java index 980fc53..b358747 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java @@ -117,6 +117,11 @@ public String getName() { return name; } + + public void changeName(String name) { + this.name = name; + this.implName = name; + } public Type getOperatorType() { return operatorType; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java index 30a7465..7b1b6b5 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java @@ -25,19 +25,53 @@ public Expression reduce() { Expression reducedTerm = super.reduce(); if (reducedTerm instanceof Term) { - if ((symbol == DataConstraintModel.dot || symbol == DataConstraintModel.dotParam) && getChildren().size() >= 2) { + if (symbol == DataConstraintModel.dot && getChildren().size() >= 2) { // this term is `json.key`. Expression expJson = getChild(0); Expression expKey = getChild(1); if (expKey instanceof Constant && expJson instanceof Term) { reducedTerm = getValue((Term) expJson, (Constant) expKey); } + } else if (symbol == DataConstraintModel.dotParam && getChildren().size() >= 2) { + // this term is `json.{param}`. + Expression expJson = getChild(0); + Expression expKey = getChild(1); + if (expKey instanceof Variable && expJson instanceof Term) { + reducedTerm = getValue((Term) expJson, (Variable) expKey); + } } } return reducedTerm; } - private Expression getValue(Term json, Constant key) { + private Expression getValue(Term json, Expression key) { + if (json instanceof JsonTerm) { + if (key instanceof Constant) { + return ((JsonTerm) json).get((Constant) key); + } else if (key instanceof Variable) { + return ((JsonTerm) json).get((Variable) key); + } + } + if (key instanceof Constant || key instanceof Variable) { + if (json.getSymbol().equals(DataConstraintModel.addMember) || json.getSymbol().equals(DataConstraintModel.set)) { + if (json.getChild(1).equals(key)) { + Expression value = json.getChild(2); + if (value == null) { + return new Constant(DataConstraintModel.null_); + } + return value; + } + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + return getValue((Term) json.getChild(0), key); + } + } + return new Constant(DataConstraintModel.null_); + } + + private Expression getValue(Term json, Variable key) { if (json instanceof JsonTerm) { return ((JsonTerm) json).get(key); } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java index 8ccdfd5..3998afa 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java @@ -9,6 +9,7 @@ import models.algebra.Expression; import models.algebra.Symbol; import models.algebra.Term; +import models.algebra.Variable; import parser.Parser; public class JsonTerm extends Term { @@ -41,6 +42,11 @@ if (keyToIndex.get(key.getValue()) == null) return null; return getChild(keyToIndex.get(key.getValue())); } + + public Expression get(Variable key) { + if (keyToIndex.get(key.getName()) == null) return null; + return getChild(keyToIndex.get(key.getName())); + } @Override public Expression unify(Expression another) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ChannelNode.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ChannelNode.java index 108bc21..0371ca0 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ChannelNode.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ChannelNode.java @@ -23,6 +23,27 @@ public Set getChildren() { return children; } + + public Set getAncestors(){ + if (parent == null) { + return new HashSet<>(); + } + Set ancestors = parent.getAncestors(); + ancestors.add(parent); + return ancestors; + } + + public Set getDescendants() { + if (children == null) { + return new HashSet<>(); + } + Set descendants = new HashSet<>(); + for (ChannelNode child: children) { + descendants.addAll(child.getDescendants()); + descendants.add(child); + } + return descendants; + } public void addChild(ChannelNode child) { children.add(child);