diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java index 6cfd4e7..69fe530 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java @@ -28,25 +28,26 @@ channels.addAll(model.getChannels()); for (Channel channel: channels) { for (ChannelMember member: ((DataTransferChannel) channel).getOutputChannelMembers()) { - boolean flag = !member.getStateTransition().isRightUnary(); // The state does not need to be stored if the state transition function is right unary. + boolean toBeStored = !member.getStateTransition().isRightUnary(); // The state does not need to be stored if the state transition function is right unary. for (Node node : graph.getResourceNodes()) { if (((ResourceNode) node).getInSideResources().contains(member.getResource())) { - setStoreAttribute((ResourceNode) node, flag); + setStoreAttribute((ResourceNode) node, toBeStored); } } } } - for (Node node : graph.getResourceNodes()) { + for (Node node: graph.getResourceNodes()) { HashSet inChannels = new HashSet<>(); - for(Edge pre : ((ResourceNode) node).getInEdges()) { - if (pre instanceof DataFlowEdge) { - DataFlowEdge dfEdge = (DataFlowEdge) pre; + for(Edge inEdge: ((ResourceNode) node).getInEdges()) { + if (inEdge instanceof DataFlowEdge) { + DataFlowEdge dfEdge = (DataFlowEdge) inEdge; if (dfEdge.isChannelToResource()) { inChannels.add(((ChannelNode) dfEdge.getSource()).getChannel()); } } } if ((inChannels.size() > 1)) { + // If the resource has multiple input channels, then the state of the resource needs to be stored. setStoreAttribute((ResourceNode) node, true); } else if (((ResourceNode) node).getAttribute() == null) { setStoreAttribute((ResourceNode) node, false); @@ -55,15 +56,15 @@ return graph; } - static private void setStoreAttribute(ResourceNode node, boolean flag) { + static private void setStoreAttribute(ResourceNode node, boolean toBeStored) { NodeAttribute attr = node.getAttribute(); StoreAttribute store; if (attr != null && attr instanceof NodeAttribute) { store = (StoreAttribute) attr; - store.setNeeded(store.isNeeded() || flag); + store.setNeeded(store.isNeeded() || toBeStored); } else { store = new StoreAttribute(); - store.setNeeded(flag); + store.setNeeded(toBeStored); node.setAttribute(store); } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index d1cb9de..ae6acca 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -257,18 +257,26 @@ } protected void addReference(TypeDeclaration component, MethodDeclaration constructor, Node dstNode, ILanguageSpecific langSpec) { - String dstNodeName = null; + ResourcePath dstRes = null; + String dstComponentName = null; if (dstNode instanceof ResourceNode) { - dstNodeName = ((ResourceNode) dstNode).getResourceName(); + dstRes = ((ResourceNode) dstNode).getOutSideResource(); + if (generatesComponent(dstRes.getResourceHierarchy())) { + dstComponentName = getComponentName(((ResourceNode) dstNode).getResourceHierarchy(), langSpec); + } else { + dstComponentName = getComponentName(((ResourceNode) dstNode).getResourceHierarchy().getParent(), langSpec); + } } - String dstComponentName = langSpec.toComponentName(dstNodeName); - if (langSpec.declareField()) { - // Declare a field to refer to another component. - component.addField(langSpec.newFieldDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); + if (dstComponentName != null) { + String dstNodeName = langSpec.toVariableName(dstComponentName); + if (langSpec.declareField()) { + // Declare a field to refer to another component. + component.addField(langSpec.newFieldDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); + } + // Initialize the field to refer to another component. + constructor.addParameter(langSpec.newVariableDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); + constructor.getBody().addStatement(langSpec.getFieldAccessor(dstNodeName) + langSpec.getAssignment() + dstNodeName + langSpec.getStatementDelimiter()); } - // Initialize the field to refer to another component. - constructor.addParameter(langSpec.newVariableDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); - constructor.getBody().addStatement(langSpec.getFieldAccessor(dstNodeName) + langSpec.getAssignment() + dstNodeName + langSpec.getStatementDelimiter()); } protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType, ILanguageSpecific langSpec) { @@ -390,13 +398,13 @@ for (Channel ch : model.getChannels()) { DataTransferChannel c = (DataTransferChannel) ch; if (c.getInputResources().contains(resourceNode.getOutSideResource())) { - for (ResourcePath id: c.getReferenceResources()) { - if (!refs.contains(id) && !depends.contains(id)) { - refs.add(id); - String refResName = langSpec.toComponentName(id.getResourceName()); - component.addField(langSpec.newFieldDeclaration(new Type(refResName, refResName), id.getResourceName())); - constructor.addParameter(langSpec.newVariableDeclaration(new Type(refResName, refResName), id.getResourceName())); - constructor.getBody().addStatement(langSpec.getFieldAccessor(id.getResourceName()) + langSpec.getAssignment() + id.getResourceName() + langSpec.getStatementDelimiter()); + for (ResourcePath res: c.getReferenceResources()) { + if (!refs.contains(res) && !depends.contains(res)) { + refs.add(res); + String refResName = langSpec.toComponentName(res.getResourceName()); + component.addField(langSpec.newFieldDeclaration(new Type(refResName, refResName), res.getResourceName())); + constructor.addParameter(langSpec.newVariableDeclaration(new Type(refResName, refResName), res.getResourceName())); + constructor.getBody().addStatement(langSpec.getFieldAccessor(res.getResourceName()) + langSpec.getAssignment() + res.getResourceName() + langSpec.getStatementDelimiter()); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 5e43545..7b4edb8 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -51,6 +51,7 @@ Map resourceComponents = new HashMap<>(); List> getters = new ArrayList<>(); List> inputs = new ArrayList<>(); + List> fields = new ArrayList<>(); // For each components. for (Node componentNode: components) { @@ -70,20 +71,20 @@ CompilationUnit cu = langSpec.newCompilationUnit(component); codes.add(cu); + // Declare the constructor and the fields to refer to other resources. + MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, depends, langSpec); + if (resourceNode.getResourceHierarchy().getParent() == null) { // For each root resource - // Declare the constructor and the fields to refer to other resources. - MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, depends, langSpec); - // Update the main component for this component. updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); - - // Declare the fields to refer to reference resources. - declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); - - if (constructor.getParameters() == null) { - component.removeMethod(constructor); - } + } + + // Declare the fields to refer to reference resources. + declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); + + if (constructor.getParameters() == null) { + component.removeMethod(constructor); } } @@ -98,6 +99,12 @@ // Declare cache fields and update methods in this resource. List updates = declareCacheFieldsAndUpdateMethods(resourceNode, component, langSpec); } + + // Declare the state field and reference fields in the parent component. + if (component == null) { + declareFieldsInParentComponent(resourceNode, fields, langSpec); + } + // Declare the getter method in this resource to obtain the state. MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType, langSpec); if (component == null) { @@ -127,10 +134,14 @@ for (Map.Entry entry: inputs) { resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); } + + // Add leaf reference fields to the parent components. + for (Map.Entry entry: fields) { + resourceComponents.get(entry.getKey()).addField(entry.getValue()); + } } - private MethodDeclaration declareConstructorAndFieldsToReferToResources(ResourceNode resourceNode, TypeDeclaration component, - List depends, ILanguageSpecific langSpec) { + private MethodDeclaration declareConstructorAndFieldsToReferToResources(ResourceNode resourceNode, TypeDeclaration component, List depends, ILanguageSpecific langSpec) { // Declare a constructor in each component. MethodDeclaration constructor = component.createConstructor(); Block block = new Block(); @@ -138,7 +149,22 @@ // Declare fields in each component. (for data-flow graph) for (Edge resToCh: resourceNode.getOutEdges()) { - if (((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + } + if (((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { for (Edge chToRes: resToCh.getDestination().getOutEdges()) { // for PUSH transfer addReference(component, constructor, chToRes.getDestination(), langSpec); @@ -149,10 +175,32 @@ } for (Edge chToRes: resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { - if (((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + ResourcePath srcRes = ((ResourceNode) resToCh.getSource()).getOutSideResource(); + DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); + // Check if the input and output resources are outside of the channel scope. + boolean outsideInputResource = false; + boolean outsideOutputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + if ((((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // for PULL transfer addReference(component, constructor, resToCh.getSource(), langSpec); - ResourcePath srcRes = ((ResourceNode) resToCh.getSource()).getOutSideResource(); if (!depends.contains(srcRes)) depends.add(srcRes); } } @@ -160,8 +208,7 @@ return constructor; } - private void declareStateField(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, - ILanguageSpecific langSpec) { + private void declareStateField(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, ILanguageSpecific langSpec) { Set children = resourceNode.getResourceHierarchy().getChildren(); if (children == null || children.size() == 0) { // leaf resource. @@ -178,21 +225,95 @@ for (ResourceHierarchy c: children) { String childTypeName = getComponentName(c, langSpec); Type childType = null; - if ((c.getChildren() == null || c.getChildren().size() == 0) && c.getNumParameters() == 0) { - // The child does not have a component. - childType = c.getResourceStateType(); - } else { + if (generatesComponent(c)) { // The child has a component. childType = new Type(childTypeName, childTypeName); + String fieldName = langSpec.toVariableName(childTypeName); + FieldDeclaration stateField = langSpec.newFieldDeclaration(childType, fieldName, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue())); + component.addField(stateField); } - String fieldName = langSpec.toVariableName(childTypeName); - FieldDeclaration stateField = langSpec.newFieldDeclaration(childType, fieldName, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue())); - component.addField(stateField); } } } } + private void declareFieldsInParentComponent(ResourceNode resourceNode, List> fields, ILanguageSpecific langSpec) { + // 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 destination resource is outside of the channel scope. + boolean outsideOutputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(dstRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + if (outsideOutputResource) { + // Declare a field in the parent component to refer to the destination resource of push transfer. + String dstResName = null; + if (generatesComponent(dstRes.getResourceHierarchy())) { + dstResName = getComponentName(dstRes.getResourceHierarchy(), langSpec); + } else { + dstResName = getComponentName(dstRes.getResourceHierarchy().getParent(), langSpec); + } + FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(new Type(dstResName, dstResName), langSpec.toVariableName(dstResName)); + fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); + } + } + } + for (Edge chToRes : resourceNode.getInEdges()) { + for (Edge resToCh: chToRes.getSource().getInEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + // Check if the source resource is outside of the channel scope. + boolean outsideInputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + } + if (outsideInputResource) { + // Declare a field in the parent component to refer to the source resource of pull transfer. + String srcResName = null; + if (generatesComponent(srcRes.getResourceHierarchy())) { + srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec); + } else { + srcResName = getComponentName(srcRes.getResourceHierarchy().getParent(), langSpec); + } + FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(new Type(srcResName, srcResName), langSpec.toVariableName(srcResName)); + fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); + noPullTransfer = false; + } + } + } + // Declare the state field in the parent component. + ResourceHierarchy res = resourceNode.getOutSideResource().getResourceHierarchy(); + if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { + String resName = getComponentName(res, langSpec); + FieldDeclaration stateField = langSpec.newFieldDeclaration(res.getResourceStateType(), langSpec.toVariableName(resName)); + fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), stateField)); + } + } + private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, ILanguageSpecific langSpec) { // Declare the getter method of the resource state. MethodDeclaration stateGetter = null; @@ -284,7 +405,7 @@ // Declare the getter methods in this resource to obtain the children resources. for (ResourceNode child: resourceNode.getChildren()) { if (generatesComponent(child.getResourceHierarchy())) { - // A component is generated for the child. + // A component for the child is generated. List params = new ArrayList<>(); int v = 1; for (Selector param: child.getSelectors()) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index d37aa16..2833000 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -128,6 +128,7 @@ Map resourceTypes = new HashMap<>(); List> getters = new ArrayList<>(); List> inputs = new ArrayList<>(); + List> fields = new ArrayList<>(); TypeDeclaration mainType = new TypeDeclaration(mainTypeName); CompilationUnit mainCU = new CompilationUnit(mainType); @@ -222,14 +223,34 @@ depends = new HashSet<>(); for (Edge resToCh : rn.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(rn.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + } + if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { // Declare a field to refer to the destination resource of push transfer. for (Edge chToRes: re.getDestination().getOutEdges()) { ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); - String dstResName = getComponentName(dstRes.getResourceHierarchy()); + String dstResName = null; + if (generatesComponent(dstRes.getResourceHierarchy())) { + dstResName = getComponentName(dstRes.getResourceHierarchy()); + } else { + dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); + } depends.add(dstRes); - type.addField(new FieldDeclaration(new Type(dstResName, dstResName), dstRes.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(dstResName, dstResName), dstRes.getResourceName())); + type.addField(new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); + constructor.addParameter(new VariableDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); block.addStatement("this." + toVariableName(dstResName) + " = " + toVariableName(dstResName) + ";"); } } @@ -238,12 +259,39 @@ for (Edge resToCh: chToRes.getSource().getInEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); - String srcResName = getComponentName(srcRes.getResourceHierarchy()); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + // Check if the input and output resources are outside of the channel scope. + boolean outsideInputResource = false; + boolean outsideOutputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(rn.getOutSideResource().getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + String srcResName = null; + if (generatesComponent(srcRes.getResourceHierarchy())) { + srcResName = getComponentName(srcRes.getResourceHierarchy()); + } else { + srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); + } + if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // Declare a field to refer to the source resource of pull transfer. depends.add(srcRes); - type.addField(new FieldDeclaration(new Type(srcResName, srcResName), srcRes.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(srcResName, srcResName), srcRes.getResourceName())); + type.addField(new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); + constructor.addParameter(new VariableDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); block.addStatement("this." + toVariableName(srcResName) + " = " + toVariableName(srcResName) + ";"); } else { // Declare an update method in the type of the destination resource. @@ -297,15 +345,12 @@ for (ResourceHierarchy c: children) { String childTypeName = getComponentName(c); Type childType = null; - if ((c.getChildren() == null || c.getChildren().size() == 0) && c.getNumParameters() == 0) { - // The child does not have a component. - childType = c.getResourceStateType(); - } else { + if (generatesComponent(c)) { // The child has a component. childType = new Type(childTypeName, childTypeName); + String fieldName = toVariableName(childTypeName); + type.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); } - String fieldName = toVariableName(childTypeName); - type.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); } } } @@ -314,7 +359,7 @@ // Declare the getter methods to obtain the children resources. for (ResourceNode child: rn.getChildren()) { if (generatesComponent(child.getResourceHierarchy())) { - // A component is generated for the child. + // A component for the child is generated. List params = new ArrayList<>(); int v = 1; for (Selector param: child.getSelectors()) { @@ -340,7 +385,83 @@ } } - // Declare the getter method to obtain the resource state in the component of each resource. + // Declare the state field and reference fields in the parent component. + if (type == null) { + // Declare reference fields for push/pull data transfer. + boolean noPullTransfer = true; + for (Edge resToCh : rn.getOutEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + for (Edge chToRes: re.getDestination().getOutEdges()) { + ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); + boolean outsideOutputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(dstRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + if (outsideOutputResource) { + // Declare a field in the parent component to refer to the destination resource of push transfer. + String dstResName = null; + if (generatesComponent(dstRes.getResourceHierarchy())) { + dstResName = getComponentName(dstRes.getResourceHierarchy()); + } else { + dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); + } + FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPush)); + } + } + } + for (Edge chToRes : rn.getInEdges()) { + for (Edge resToCh: chToRes.getSource().getInEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + boolean outsideInputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + } + if (outsideInputResource) { + // Declare a field in the parent component to refer to the source resource of pull transfer. + String srcResName = null; + if (generatesComponent(srcRes.getResourceHierarchy())) { + srcResName = getComponentName(srcRes.getResourceHierarchy()); + } else { + srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); + } + FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPull)); + noPullTransfer = false; + } + } + } + // Declare the state field in the parent component. + ResourceHierarchy res = rn.getOutSideResource().getResourceHierarchy(); + if (((StoreAttribute) rn.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { + String resName = getComponentName(res); + FieldDeclaration stateField = new FieldDeclaration(res.getResourceStateType(), toVariableName(resName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), stateField)); + } + } + + // Declare the getter method in this component to obtain the resource state. if (type != null) { // A component is created for this resource. MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(rn.getResourceHierarchy())); @@ -370,7 +491,7 @@ getters.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), stateGetter)); } - // Declare the getter accessor in the main type. + // Declare the accessor method in the main type to call the getter method. MethodDeclaration accessor = null; List mainGetterParams = new ArrayList<>(); int v = 1; @@ -398,7 +519,7 @@ accessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); mainType.addMethod(accessor); - // Declare the input method in each resource and the main component. + // Declare the input method in this component and the main component. for (Channel ch : model.getIOChannels()) { for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { if (rn.getInSideResources().contains(cm.getResource())) { @@ -538,6 +659,11 @@ for (Map.Entry entry: inputs) { resourceTypes.get(entry.getKey()).addMethod(entry.getValue()); } + + // Add leaf reference fields to the parent components. + for (Map.Entry entry: fields) { + resourceTypes.get(entry.getKey()).addField(entry.getValue()); + } // Declare the Pair class. boolean isCreatedPair = false; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 855de3b..0062119 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -53,6 +53,7 @@ public class JerseyCodeGenerator { public static final Type typeVoid = new Type("Void", "void"); public static final Type typeClient = new Type("Client", "Client"); + public static boolean differentTreesAsDifferentServices = true; private static String defaultMainTypeName = "Main"; static String mainTypeName = defaultMainTypeName; @@ -131,6 +132,7 @@ Map resourceTypes = new HashMap<>(); List> getters = new ArrayList<>(); List> inputs = new ArrayList<>(); + List> fields = new ArrayList<>(); Map getterAccessors = new HashMap<>(); Map inputAccessors = new HashMap<>(); @@ -164,30 +166,94 @@ cu.addImport(new ImportDeclaration("com.fasterxml.jackson.core.JsonProcessingException")); } codes.add(cu); - } - - // Declare a client field and update methods from other resources. - if (rn.getResourceHierarchy().getParent() == null) { - // For a root resource + + // Declare a client field and update methods from other resources. boolean bDeclareClientField = false; for (Edge resToCh: rn.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; - if (!bDeclareClientField && ((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // Declare a client field to connect to the destination resource of push transfer. - type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(rn.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + } + if (!bDeclareClientField && ((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { + for (ChannelMember cm: ch.getOutputChannelMembers()) { + ResourcePath dstRes = cm.getResource(); + String dstResName = null; + if (generatesComponent(dstRes.getResourceHierarchy())) { + dstResName = getComponentName(dstRes.getResourceHierarchy()); + } else { + dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); + } + if (rn.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { + // Inter-service + if (bDeclareClientField) { + // Declare a client field to connect to the destination resource of push transfer. + type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the destination resource of push transfer. + type.addField(new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); + } + } } } for (Edge chToRes : rn.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); - String srcResName = getComponentName(srcRes.getResourceHierarchy()); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - if (!bDeclareClientField) { - // Declare a client field to connect to the source resource of pull transfer. - type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + // Check if the input and output resources are outside of the channel scope. + boolean outsideInputResource = false; + boolean outsideOutputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(rn.getOutSideResource().getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + String srcResName = null; + if (generatesComponent(srcRes.getResourceHierarchy())) { + srcResName = getComponentName(srcRes.getResourceHierarchy()); + } else { + srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); + } + if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { + if (rn.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { + // Inter-service + if (!bDeclareClientField) { + // Declare a client field to connect to the source resource of pull transfer. + type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the source resource of pull transfer. + type.addField(new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); } } else { // Declare an update method in the type of the destination resource. @@ -262,15 +328,12 @@ for (ResourceHierarchy c: children) { String childTypeName = getComponentName(c); Type childType = null; - if ((c.getChildren() == null || c.getChildren().size() == 0) && c.getNumParameters() == 0) { - // The child does not have a component. - childType = c.getResourceStateType(); - } else { + if (generatesComponent(c)) { // The child has a component. childType = new Type(childTypeName, childTypeName); + String fieldName = toVariableName(childTypeName); + type.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); } - String fieldName = toVariableName(childTypeName); - type.addField(new FieldDeclaration(childType, fieldName, getInitializer(res))); } } } @@ -305,6 +368,107 @@ } } + // Declare the state field and reference fields in the parent component. + if (type == null) { + // Declare reference fields for push/pull data transfer. + boolean bDeclareClientField = false; + boolean noPullTransfer = true; + for (Edge resToCh : rn.getOutEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + for (Edge chToRes: re.getDestination().getOutEdges()) { + ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); + boolean outsideOutputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(dstRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + } + if (outsideOutputResource) { + // Declare a field in the parent component to refer to the destination resource of push transfer. + String dstResName = null; + if (generatesComponent(dstRes.getResourceHierarchy())) { + dstResName = getComponentName(dstRes.getResourceHierarchy()); + } else { + dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); + } + if (rn.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { + // Inter-service + if (!bDeclareClientField) { + // Declare a client field to connect to the destination resource of push transfer. + FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), clientField)); + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the destination resource of push transfer. + FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPush)); + } + } + } + } + for (Edge chToRes : rn.getInEdges()) { + for (Edge resToCh: chToRes.getSource().getInEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + boolean outsideInputResource = false; + if (ch.getAllSelectors().size() > 0) { + Set params = new HashSet<>(); + for (Selector s: ch.getAllSelectors()) { + params.add(s.getExpression()); + } + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && !params.containsAll(cm.getResource().getPathParams())) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + } + if (outsideInputResource) { + // Declare a field in the parent component to refer to the source resource of pull transfer. + String srcResName = null; + if (generatesComponent(srcRes.getResourceHierarchy())) { + srcResName = getComponentName(srcRes.getResourceHierarchy()); + } else { + srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); + } + if (rn.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { + // Inter-service + if (!bDeclareClientField) { + // Declare a client field to connect to the source resource of pull transfer. + FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), clientField)); + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the source resource of pull transfer. + FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPull)); + noPullTransfer = false; + } + } + } + } + // Declare the state field in the parent component. + ResourceHierarchy res = rn.getOutSideResource().getResourceHierarchy(); + if (((StoreAttribute) rn.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { + String resName = getComponentName(res); + FieldDeclaration stateField = new FieldDeclaration(res.getResourceStateType(), toVariableName(resName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), stateField)); + } + } + // Declare the getter method to obtain the resource state in the component of each resource. if (type != null) { // A component is created for this resource. @@ -345,27 +509,12 @@ // For a non-root resource MethodDeclaration getterAccessor = null; List mainGetterParams = new ArrayList<>(); - String resourcePath = "\""; - int v = 1; - for (Selector pathParam: rn.getAllSelectors()) { - if (pathParam.getExpression() instanceof Variable) { - Variable var = (Variable) pathParam.getExpression(); - String paramName = var.getName(); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - mainGetterParams.add(param); - resourcePath += "/{" + paramName + "}"; - } else if (pathParam.getExpression() instanceof Term) { - Term var = (Term) pathParam.getExpression(); - String paramName = "v" + v; - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - mainGetterParams.add(param); - resourcePath += "/{" + paramName + "}"; - } - v++; + String resourcePath = getGetterResourcePathAndPathParams(rn, mainGetterParams); + if (resourcePath.indexOf('/') > 0) { + resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; + } else { + resourcePath = "\"" + resourcePath + "\""; } - resourcePath += "\""; if (mainGetterParams.size() > 0) { getterAccessor = new MethodDeclaration("get" + getComponentName(rn.getResourceHierarchy()) + "Value", false, @@ -381,7 +530,7 @@ getterAccessor.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); getterAccessor.addAnnotation(new Annotation("GET")); - if (rn.getSelectors().size() > 0) { + if (rn.getAllSelectors().size() > 0) { getterAccessor.addAnnotation(new Annotation("Path", resourcePath)); } getterAccessors.put(rn.getResourceHierarchy(), getterAccessor); @@ -396,51 +545,12 @@ // In each resource. ArrayList resInputParams = new ArrayList<>(); ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = "\""; - int v = 1; - for (Selector selector: rn.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); - String paramName = var.getName(); - 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); - resourcePath += "/{" + paramName + "}"; - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); - String paramName = "v" + v; - 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); - resourcePath += "/{" + paramName + "}"; - } - v++; + String resourcePath = getInputMethodResourcePathaAndPathParams(rn, resInputParams, rootInputParams); + if (resourcePath.indexOf('/') > 0) { + resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; + } else { + resourcePath = "\"" + resourcePath + "\""; } - if (rn.getParent() != null) { - for (Selector selector: rn.getParent().getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); - String paramName = var.getName(); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - resourcePath += "/{" + paramName + "}"; - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); - String paramName = "v" + v; - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - resourcePath += "/{" + paramName + "}"; - } - v++; - } - } - resourcePath += "\""; for (Variable var: message.getVariables().values()) { String paramName = var.getName(); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); @@ -506,27 +616,12 @@ // For the root resource. ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = "\""; - v = 1; - for (Selector selector: rn.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); - String paramName = var.getName(); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - resourcePath += "/{" + paramName + "}"; - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); - String paramName = "v" + v; - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - resourcePath += "/{" + paramName + "}"; - } - v++; + String resourcePath = getGetterResourcePathAndPathParams(rn, rootInputParams); + if (resourcePath.indexOf('/') > 0) { + resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; + } else { + resourcePath = "\"" + resourcePath + "\""; } - resourcePath += "\""; String str = ((Term) cm.getStateTransition().getMessageExpression()).getSymbol().getImplName(); MethodDeclaration inputAccessor = new MethodDeclaration(str, false, typeVoid, rootInputParams); if (cm.getStateTransition().isRightUnary()) { @@ -554,6 +649,11 @@ resourceTypes.get(entry.getKey()).addMethod(entry.getValue()); } + // Add leaf reference fields to the parent components. + for (Map.Entry entry: fields) { + resourceTypes.get(entry.getKey()).addField(entry.getValue()); + } + // Add accessors. for (ResourceHierarchy rootRes: model.getResourceHierarchies()) { if (rootRes.getParent() == null) { @@ -619,6 +719,79 @@ return codes; } + private static String getGetterResourcePathAndPathParams(ResourceNode rn, List pathParams) { + int v = 1; + List params = new ArrayList<>(); + for (Selector selector: rn.getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable var = (Variable) selector.getExpression(); + String paramName = var.getName(); + params.add(paramName); + VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); + param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + pathParams.add(param); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); + String paramName = "v" + v; + params.add(paramName); + VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); + param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + pathParams.add(param); + } + v++; + } + return rn.getResourceHierarchy().toResourcePath(params); + } + + private static String getInputMethodResourcePathaAndPathParams(ResourceNode rn, ArrayList resInputParams, + ArrayList rootInputParams) { + int v = 1; + List params = new ArrayList<>(); + for (Selector selector: rn.getSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable var = (Variable) selector.getExpression(); + 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 (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); + 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); + } + v++; + } + if (rn.getParent() != null) { + for (Selector selector: rn.getParent().getAllSelectors()) { + if (selector.getExpression() instanceof Variable) { + Variable var = (Variable) selector.getExpression(); + String paramName = var.getName(); + params.add(paramName); + VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); + param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + rootInputParams.add(param); + } else if (selector.getExpression() instanceof Term) { + Term var = (Term) selector.getExpression(); + String paramName = "v" + v; + params.add(paramName); + VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); + param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); + rootInputParams.add(param); + } + v++; + } + } + return rn.getResourceHierarchy().toResourcePath(params); + } + private static String getInitializer(ResourcePath resId) { Type stateType = resId.getResourceStateType(); String initializer = null; diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index 81b24ed..a0f34eb 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -325,7 +325,7 @@ return "(" + children.get(implParamOrder[0]).toImplementation(sideEffects) + symbol.toImplementation() + children.get(implParamOrder[1]).toImplementation(sideEffects) + ")"; } } - if (getArity() >= 1 && symbol.isImplMethod()) { + if ((getArity() >= 1 || getArity() == -1) && symbol.isImplMethod()) { if (implParamOrder == null) { String exp = null; if (children.get(0) != null) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java index 0994c0a..be87686 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourceHierarchy.java @@ -228,4 +228,15 @@ return parent.toString(pathParams) + ".{" + lastParam +"}"; } } + + public String toResourcePath(List pathParams) { + if (parent == null) return resourceName; + if (resourceName != null) { + return parent.toResourcePath(pathParams) + "/" + resourceName; + } else { + String lastParam = pathParams.get(pathParams.size() - 1); + pathParams = pathParams.subList(0, pathParams.size() - 1); + return parent.toResourcePath(pathParams) + "/{" + lastParam +"}"; + } + } } \ No newline at end of file