diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index e1bf0ae..ae86204 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -689,32 +689,31 @@ update.addFirstStatement(updateStatement); } } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); + } + if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; } else { - if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(resourceNode.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else { - String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); - updateStatement = sideEffects[0] + langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); - } + String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); + updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); } if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { update.addFirstStatement(updateStatement); @@ -857,9 +856,22 @@ params.add(refVarName); } } - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) chToRes2.getDestination()).getResourceName()), - updateMethodName + resComponentName, - params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + ResourceHierarchy srcRes2 = resourceNode.getResourceHierarchy(); + if (!generatesComponent(srcRes2)) { + srcRes2 = srcRes2.getParent(); + } + ResourceHierarchy dstRes = ((ResourceNode) chToRes2.getDestination()).getResourceHierarchy(); + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); + if (srcRes2 != dstRes) { + update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName + resComponentName, params) + + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + } else { + update.addStatement(langSpec.getMethodInvocation(updateMethodName + resComponentName, params) + + langSpec.getStatementDelimiter()); // this.updateSrc(value, refParams); + } } } if (outsideInputMembers2.size() > 0) { @@ -1165,32 +1177,31 @@ } input.addFirstStatement(updateStatement); } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec)); updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); + } + if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; } else { - if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(resourceNode.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else { - String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec)); - updateStatement = sideEffects[0] + langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); - } + String resourceName = langSpec.toVariableName(getComponentName(resource, langSpec)); + updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); } if (updateStatement != null) { input.addFirstStatement(updateStatement); @@ -1250,9 +1261,22 @@ params.add(refVarName); } } - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) chToRes.getDestination()).getResourceName()), - updateMethodName + resComponentName, - params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + ResourceHierarchy srcRes = resourceNode.getResourceHierarchy(); + if (!generatesComponent(srcRes)) { + srcRes = srcRes.getParent(); + } + ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); + if (srcRes != dstRes) { + input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName + resComponentName, params) + + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + } else { + input.addStatement(langSpec.getMethodInvocation(updateMethodName + resComponentName, params) + + langSpec.getStatementDelimiter()); // this.updateSrc(value, refParams); + } } } if (outsideInputMembers2.size() > 0) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 7d62432..70f6cd0 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -28,8 +28,9 @@ boolean declareField(); String getFieldAccessor(String fieldName); String getMethodInvocation(String methodName); - String getMethodInvocation(String receivertName, String methodName); - String getMethodInvocation(String receivertName, String methodName, List parameters); + String getMethodInvocation(String receiverName, List parameters); + String getMethodInvocation(String receiverName, String methodName); + String getMethodInvocation(String receiverName, String methodName, List parameters); String getConstructorInvocation(String componentName, List parameters); String getReturnStatement(String returnValue); String toComponentName(String name); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 90e8e70..b41d37e 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -129,6 +129,7 @@ Map resourceComponents = new HashMap<>(); Map resourceConstructors = new HashMap<>(); List> getters = new ArrayList<>(); + List> updates = new ArrayList<>(); List> inputs = new ArrayList<>(); List> fields = new ArrayList<>(); List> constructorParams = new ArrayList<>(); @@ -147,6 +148,8 @@ // For each resource node. for (ResourceNode resourceNode: resources) { TypeDeclaration component = null; + Set depends = new HashSet<>(); + Set refs = new HashSet<>(); if (generatesComponent(resourceNode.getResourceHierarchy())) { boolean f = false; String resourceName = getComponentName(resourceNode.getResourceHierarchy()); @@ -161,8 +164,6 @@ codes.add(cu); // Declare the field to refer to each resource in the main type. - Set depends = new HashSet<>(); - Set refs = new HashSet<>(); if (resourceNode.getResourceHierarchy().getParent() == null) { // For a root resource String fieldInitializer = "new " + resourceName + "("; @@ -234,150 +235,6 @@ } mainConstructorBody.addStatement(resourceNode.getResourceName() + " = " + fieldInitializer + ";"); } - - // Declare a constructor, fields and update methods in the type of each resource. - MethodDeclaration constructor = new MethodDeclaration(resourceName, true); - Block block = new Block(); - depends = new HashSet<>(); - for (Edge resToCh : resourceNode.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push 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(); - if (!generatesComponent(dstRes.getResourceHierarchy())) { - dstRes = dstRes.getParent(); - } - String dstResName = getComponentName(dstRes.getResourceHierarchy()); - depends.add(dstRes.getResourceHierarchy()); - component.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) + ";"); - if (outsideOutputResource) { - if (dstRes.getParent() != null) { - // Reference to root resource. - ResourcePath dstRootRes = dstRes.getRoot(); - String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName))); - constructor.addParameter(new VariableDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName))); - block.addStatement("this." + toVariableName(dstRootResName) + " = " + toVariableName(dstRootResName) + ";"); - } - } - } - } - } - 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 input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - String srcResName = null; - ResourcePath srcRes2 = srcRes; - if (generatesComponent(srcRes.getResourceHierarchy())) { - srcResName = getComponentName(srcRes.getResourceHierarchy()); - } else { - srcRes2 = srcRes.getParent(); - srcResName = getComponentName(srcRes2.getResourceHierarchy()); - } - 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(srcRes2.getResourceHierarchy()); - component.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) + ";"); - if (outsideInputResource) { - if (srcRes2.getParent() != null) { - // Reference to root resource. - ResourcePath srcRootRes = srcRes2.getRoot(); - String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName))); - constructor.addParameter(new VariableDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName))); - block.addStatement("this." + toVariableName(srcRootResName) + " = " + toVariableName(srcRootResName) + ";"); - } - } - } else { - // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - vars.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); - DataTransferChannel c = ((ChannelNode) resToCh.getDestination()).getChannel(); - for (ResourcePath ref: c.getReferenceResources()) { - if (!ref.equals(resourceNode.getOutSideResource())) { - vars.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); - } - } - component.addMethod(new MethodDeclaration("update" + srcResName, false, typeVoid, vars)); - } - } - } - // Declare a field to refer to outside resources. - if (resourceNode.getParent() == null) { - for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { - for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { - if (resourceNode.getResourceHierarchy().equals(dependingRes)) { - // Declare a field to refer to outside resources. - depends.add(dependedRes); - String resName = getComponentName(dependedRes); - component.addField(new FieldDeclaration(new Type(resName, resName), toVariableName(resName))); - constructor.addParameter(new VariableDeclaration(new Type(resName, resName), toVariableName(resName))); - block.addStatement("this." + toVariableName(resName) + " = " + toVariableName(resName) + ";"); - } - } - } - } - // Declare a field to refer to the reference resource. - refs = new HashSet<>(); - for (Channel ch : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) ch; - if (c.getInputResources().contains(resourceNode.getOutSideResource())) { - for (ResourcePath res: c.getReferenceResources()) { - if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { - refs.add(res); - String refResName = getComponentName(res.getResourceHierarchy()); - component.addField(new FieldDeclaration(new Type(refResName, refResName), res.getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(refResName, refResName), res.getResourceName())); - block.addStatement("this." + res.getResourceName() + " = " + res.getResourceName() + ";"); - } - } - } - } - constructor.setBody(block); - if (constructor.getParameters() != null) { - component.addMethod(constructor); - resourceConstructors.put(resourceNode.getResourceHierarchy(), constructor); - } } // Declare the field to store the state in the type of each resource. @@ -549,7 +406,7 @@ } // Declare the accessor method in the main type to call the getter method. - MethodDeclaration accessor = null; + MethodDeclaration getterAccessor = null; List mainGetterParams = new ArrayList<>(); int v = 1; for (Selector param: resourceNode.getAllSelectors()) { @@ -563,19 +420,206 @@ v++; } if (mainGetterParams.size() > 0) { - accessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), + getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), false, getImplStateType(resourceNode.getResourceHierarchy()), mainGetterParams); } else { - accessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), + getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), getImplStateType(resourceNode.getResourceHierarchy())); } - accessor.setBody(new Block()); + getterAccessor.setBody(new Block()); Expression getState = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(resourceNode.getOutSideResource(), null); - accessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); - mainComponent.addMethod(accessor); + getterAccessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); + mainComponent.addMethod(getterAccessor); + // Declare fields and update methods in the type of each resource. + for (Edge resToCh : resourceNode.getOutEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push 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(); + if (!generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); + } + String dstResName = getComponentName(dstRes.getResourceHierarchy()); + depends.add(dstRes.getResourceHierarchy()); + FieldDeclaration dstRefField = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + VariableDeclaration dstRefVar = new VariableDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + if (component != null) { + // A component is created for this resource. + component.addField(dstRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefVar)); + } + if (outsideOutputResource) { + if (dstRes.getParent() != null) { + // Reference to root resource. + ResourcePath dstRootRes = dstRes.getRoot(); + String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); + FieldDeclaration dstRootRefField = new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); + VariableDeclaration dstRootRefVar = new VariableDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); + if (component != null) { + // A component is created for this resource. + component.addField(dstRootRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRootRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefVar)); + } + } + } + } + } + } + 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 input resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + String srcResName = getComponentName(srcRes.getResourceHierarchy()); + ResourcePath srcRes2 = srcRes; + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes2 = srcRes.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(srcRes2.getResourceHierarchy()); + FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + VariableDeclaration srcRefVar = new VariableDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + if (component != null) { + // A component is created for this resource. + component.addField(srcRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefVar)); + } + if (outsideInputResource) { + if (srcRes2.getParent() != null) { + // Reference to root resource. + ResourcePath srcRootRes = srcRes2.getRoot(); + String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); + FieldDeclaration srcRootRefField = new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); + VariableDeclaration srcRootRefVar = new VariableDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); + if (component != null) { + // A component is created for this resource. + component.addField(srcRootRefField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRootRefVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefVar)); + } + } + } + } else { + // Declare an update method in the type of the destination resource. + ArrayList vars = new ArrayList<>(); + vars.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); + DataTransferChannel c = ((ChannelNode) resToCh.getDestination()).getChannel(); + for (ResourcePath ref: c.getReferenceResources()) { + if (!ref.equals(resourceNode.getOutSideResource())) { + vars.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); + } + } + MethodDeclaration update = new MethodDeclaration("update" + srcResName, false, typeVoid, vars); + if (component != null) { + // A component is created for this resource. + component.addMethod(update); + } else { + // No component is created for this resource. + updates.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), update)); + } + } + } + } + // Declare a field to refer to outside resources. + if (resourceNode.getParent() == null) { + for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { + for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { + if (resourceNode.getResourceHierarchy().equals(dependingRes)) { + // Declare a field to refer to outside resources. + depends.add(dependedRes); + String resName = getComponentName(dependedRes); + FieldDeclaration refField = new FieldDeclaration(new Type(resName, resName), toVariableName(resName)); + VariableDeclaration refVar = new VariableDeclaration(new Type(resName, resName), toVariableName(resName)); + if (component != null) { + // A component is created for this resource. + component.addField(refField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refVar)); + } + } + } + } + } + // Declare a field to refer to the reference resource. + for (Channel ch : model.getChannels()) { + DataTransferChannel c = (DataTransferChannel) ch; + if (c.getInputResources().contains(resourceNode.getOutSideResource())) { + for (ResourcePath res: c.getReferenceResources()) { + if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { + refs.add(res); + String refResName = getComponentName(res.getResourceHierarchy()); + FieldDeclaration refResField = new FieldDeclaration(new Type(refResName, refResName), res.getResourceName()); + VariableDeclaration refResVar = new VariableDeclaration(new Type(refResName, refResName), res.getResourceName()); + if (component != null) { + // A component is created for this resource. + component.addField(refResField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refResVar)); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResVar)); + } + } + } + } + } + // Declare the input method in this component and the main component. for (Channel ch : model.getIOChannels()) { for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { @@ -742,6 +786,11 @@ resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); } + // Add leaf update methods to the parent components. + for (Map.Entry entry: updates) { + resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); + } + // Add leaf input methods to the parent components. for (Map.Entry entry: inputs) { resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index a089a26..d72ab8b 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -141,30 +141,29 @@ update.addFirstStatement(updateStatement); } } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; - updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes))); + updateStatement = updateStatement.replace(".value", "." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes))); + } + if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; } else { - if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else { - updateStatement = sideEffects[0] + "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; - } + updateStatement += "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; } if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { update.addFirstStatement(updateStatement); @@ -223,6 +222,10 @@ break; } } + if (srcComponent == null) { + String srcParentResourceName = JavaCodeGenerator.getComponentName(src.getResourceHierarchy().getParent()); + srcComponent = componentMap.get(srcParentResourceName); + } for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent)) { String refParams = ""; Set referredSet = referredResources.get(srcUpdate); @@ -246,7 +249,11 @@ refParams += ", " + refVarName; } } - srcUpdate.addStatement("this." + dstResourceName + ".update" + srcComponent.getTypeName() + "(value" + refParams + ");"); + if (srcComponent != dstComponent) { + srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + ".update" + src.getResourceName() + "(value" + refParams + ");"); + } else { + srcUpdate.addStatement("this.update" + src.getResourceName() + "(value" + refParams + ");"); + } } for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { String refParams = ""; @@ -271,7 +278,11 @@ refParams += ", " + refVarName; } } - srcInput.addStatement("this." + dstResourceName + ".update" + srcComponent.getTypeName() + "(value" + refParams + ");"); + if (srcComponent != dstComponent) { + srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + ".update" + src.getResourceName()+ "(value" + refParams + ");"); + } else { + srcInput.addStatement("this.update" + src.getResourceName() + "(value" + refParams + ");"); + } } } else if ((pushPull.getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // for pull (or push/pull) data transfer @@ -567,30 +578,29 @@ input.addFirstStatement(updateStatement); } } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; - updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource))); + updateStatement = updateStatement.replace(".value", "." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource))); + } + if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; } else { - if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else { - updateStatement = sideEffects[0] + "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; - } + updateStatement += "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; } if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { input.addFirstStatement(updateStatement); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index 62743b9..662834a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -131,6 +131,23 @@ } @Override + public String getMethodInvocation(String methodName, List parameters) { + if (parameters == null) return getMethodInvocation( methodName); + String invocation = self + "." + methodName + "("; + if (parameters.size() > 0) { + for (int i = 0; i < parameters.size(); i++) { + if (i < parameters.size() - 1) { + invocation += parameters.get(i) + ", "; + } else { + invocation += parameters.get(i); + } + } + } + invocation += ")"; + return invocation; + } + + @Override public String getMethodInvocation(String receiverName, String methodName) { return receiverName + "." + methodName + "()"; } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 9a47929..f78b8f7 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -133,6 +133,7 @@ Map resourceComponents = new HashMap<>(); Map resourceConstructors = new HashMap<>(); List> getters = new ArrayList<>(); + List> updates = new ArrayList<>(); List> inputs = new ArrayList<>(); List> fields = new ArrayList<>(); Map getterAccessors = new HashMap<>(); @@ -170,122 +171,6 @@ cu.addImport(new ImportDeclaration("com.fasterxml.jackson.core.JsonProcessingException")); } codes.add(cu); - - // Declare a client field and update methods from other resources. - boolean bDeclareClientField = false; - for (Edge resToCh: resourceNode.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && cm.isOutside()) { - 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 (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { - // Inter-service - if (bDeclareClientField) { - // Declare a client field to connect to the destination resource of push transfer. - component.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. - component.addField(new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); - } - } - } - } - 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 input and output resources are outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { - 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 (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { - // Inter-service - if (!bDeclareClientField) { - // Declare a client field to connect to the source resource of pull transfer. - component.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. - component.addField(new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); - } - } else { - // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - String srcName = srcRes.getResourceName(); - Type srcType = srcRes.getResourceStateType(); - VariableDeclaration param = new VariableDeclaration(srcType, srcName); - param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); - vars.add(param); - for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { - if (!refRes.equals(resourceNode.getOutSideResource())) { - param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); - param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); - vars.add(param); - } - } - MethodDeclaration update = new MethodDeclaration("update" + srcResName, false, typeVoid, vars); - for (ChannelMember cm: ((ChannelNode) re.getDestination()).getChannel().getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource())) { - if (cm.getStateTransition().isRightUnary()) { - update.addAnnotation(new Annotation("PUT")); - } else { - update.addAnnotation(new Annotation("POST")); - } - } - } - if (re.getDestination().getIndegree() > 1 - || (re.getDestination().getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { - // Declare a field to cache the state of the source resource in the type of the destination resource. - ResourcePath cacheRes = ((ResourceNode) re.getSource()).getOutSideResource(); - component.addField(new FieldDeclaration(cacheRes.getResourceStateType(), srcName, getInitializer(cacheRes))); - if (re.getDestination().getIndegree() > 1) { - // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); - } - } - component.addMethod(update); - } - } - } } // // Declare a client field to connect to the source resource of reference transfer. @@ -366,9 +251,9 @@ } // Declare the state field and reference fields in the parent component. + boolean bDeclareClientField = false; if (component == null) { // Declare reference fields for push/pull data transfer. - boolean bDeclareClientField = false; boolean noPullTransfer = true; for (Edge resToCh : resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; @@ -498,6 +383,8 @@ String resourcePath = getGetterResourcePathAndPathParams(resourceNode.getOutSideResource(), mainGetterParams); if (resourcePath.indexOf('/') > 0) { resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; } if (mainGetterParams.size() > 0) { getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()) + "Value", @@ -520,6 +407,157 @@ getterAccessors.put(resourceNode.getResourceHierarchy(), getterAccessor); } + // Declare a client field and update methods from other resources. + for (Edge resToCh: resourceNode.getOutEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + // Check if the input resource is outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && cm.isOutside()) { + 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 (resourceNode.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()"); + if (component != null) { + // A component is created for this resource. + component.addField(clientField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); + } + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the destination resource of push transfer. + FieldDeclaration dstRefField = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); + if (component != null) { + // A component is created for this resource. + component.addField(dstRefField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefField)); + } + } + } + } + } + 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 input and output resources are outside of the channel scope. + boolean outsideInputResource = false; + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) { + outsideInputResource = true; // Regarded as pull transfer. + break; + } + } + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } + String srcResName = getComponentName(srcRes.getResourceHierarchy()); + if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { + if (resourceNode.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()"); + if (component != null) { + // A component is created for this resource. + component.addField(clientField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); + } + bDeclareClientField = true; + } + } else { + // Inner-service + // Declare a field to directly refer to the source resource of pull transfer. + FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); + if (component != null) { + // A component is created for this resource. + component.addField(srcRefField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField)); + } + } + } else { + // Declare an update method in the type of the destination resource. + ArrayList vars = new ArrayList<>(); + String srcName = srcRes.getResourceName(); + Type srcType = srcRes.getResourceStateType(); + VariableDeclaration param = new VariableDeclaration(srcType, srcName); + param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); + vars.add(param); + for (ResourcePath refRes: ((ChannelNode) re.getDestination()).getChannel().getReferenceResources()) { + if (!refRes.equals(resourceNode.getOutSideResource())) { + param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); + param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); + vars.add(param); + } + } + MethodDeclaration update = new MethodDeclaration("update" + srcResName, false, typeVoid, vars); + for (ChannelMember cm: ((ChannelNode) re.getDestination()).getChannel().getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(cm.getResource())) { + if (cm.getStateTransition().isRightUnary()) { + update.addAnnotation(new Annotation("PUT")); + } else { + update.addAnnotation(new Annotation("POST")); + } + } + } + if (re.getDestination().getIndegree() > 1 + || (re.getDestination().getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // Declare a field to cache the state of the source resource in the type of the destination resource. + ResourcePath cacheRes = ((ResourceNode) re.getSource()).getOutSideResource(); + FieldDeclaration cacheField = new FieldDeclaration(cacheRes.getResourceStateType(), srcName, getInitializer(cacheRes)); + if (component != null) { + // A component is created for this resource. + component.addField(cacheField); + } else { + // No component is created for this resource. + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), cacheField)); + } + if (re.getDestination().getIndegree() > 1) { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); + } + } + if (component != null) { + // A component is created for this resource. + component.addMethod(update); + } else { + // No component is created for this resource. + updates.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), update)); + } + } + } + } + // Declare the input method in each resource and the root resource. for (Channel ch : model.getIOChannels()) { for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { @@ -539,6 +577,8 @@ String resourcePath = getInputMethodResourcePathAndPathParams(cm.getResource(), resInputParams, rootInputParams); if (resourcePath.indexOf('/') > 0) { resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; } for (Map.Entry varEnt: message.getVariables().entrySet()) { Variable var = varEnt.getValue(); @@ -642,6 +682,8 @@ String resourcePath = getGetterResourcePathAndPathParams(cm.getResource(), rootInputParams); if (resourcePath.indexOf('/') > 0) { resourcePath = resourcePath.substring(resourcePath.indexOf('/')); + } else { + resourcePath = ""; } String messageSymbol = ((Variable) message).getName(); MethodDeclaration inputAccessor = new MethodDeclaration(messageSymbol, false, typeVoid, rootInputParams); @@ -666,6 +708,11 @@ resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); } + // Add leaf update methods to the parent components. + for (Map.Entry entry: updates) { + resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); + } + // Add leaf input methods to the parent components. for (Map.Entry entry: inputs) { resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 921cdeb..6651106 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -95,7 +95,11 @@ } if (pushPull.getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { // for push data transfer - MethodDeclaration update = getUpdateMethod(dstComponent, srcComponent); + if (dstComponent == null) { + String dstParentResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); + dstComponent = componentMap.get(dstParentResourceName); + } + MethodDeclaration update = getUpdateMethod(dstComponent, srcResourceName); if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst side resource (when every incoming edge is in push style) Expression updateExp = null; @@ -149,30 +153,29 @@ update.addFirstStatement(updateStatement); } } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes))); + } + if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; } else { - if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else { - updateStatement = sideEffects[0] + "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; - } + updateStatement += "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; } if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { // add an update statement of the state of dst side resource. @@ -254,10 +257,6 @@ } if (((StoreAttribute) dst.getAttribute()).isStored()) { // returns the state stored in a field. - if (dstComponent == null) { - String dstParentResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); - dstComponent = componentMap.get(dstParentResourceName); - } MethodDeclaration getter = null; if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { getter = getMethod(dstComponent, "getValue"); @@ -289,6 +288,10 @@ } else { httpMethod = "post"; } + if (srcComponent == null) { + String srcParentResourceName = JerseyCodeGenerator.getComponentName(src.getResourceHierarchy().getParent()); + srcComponent = componentMap.get(srcParentResourceName); + } for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent)) { if (srcUpdate != null) { List>> params = new ArrayList<>(); @@ -598,30 +601,29 @@ input.addStatement(updateStatement); } } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + String updateStatement = ""; + if (sideEffects[0] != null) { updateStatement = sideEffects[0]; updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource))); + } + if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Field("value")); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newList = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; + } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Field("value")); + selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); + selector.addChild(new Constant(newState)); + String[] sideEffects2 = new String[] {""}; + String newMap = selector.toImplementation(sideEffects2); + updateStatement += sideEffects2[0]; } else { - if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement = sideEffects[0] + sideEffects2[0]; - } else { - updateStatement = sideEffects[0] + "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; - } + updateStatement += "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; } if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { input.addStatement(updateStatement); @@ -890,9 +892,9 @@ return null; } - private static MethodDeclaration getUpdateMethod(TypeDeclaration component, TypeDeclaration from) { + private static MethodDeclaration getUpdateMethod(TypeDeclaration component, String from) { for (MethodDeclaration m: component.getMethods()) { - if (m.getName().equals("update" + from.getTypeName())) return m; + if (m.getName().equals("update" + from)) return m; } return null; }