diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 8d981e6..59930d9 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -173,7 +173,7 @@ } // Declare the fields to refer to other resources in the parent/this component, and the state field in the parent component. - declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent, constructorParams, langSpec); + boolean bDeclareClientField = declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent, constructorParams, platformSpec, langSpec); // (#2) Declare the getter method to obtain the resource state in an ancestor resource. (complementary to #1) if (component == null) { @@ -479,10 +479,11 @@ } } - private void declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, - Map> constructorParams, ILanguageSpecific langSpec) { + private boolean declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, + Map> constructorParams, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { // Declare reference fields for push data transfer. boolean noPullTransfer = true; + boolean bDeclareClientField = false; for (Edge resToCh : resourceNode.getOutEdges()) { DataFlowEdge re = (DataFlowEdge) resToCh; ChannelNode directDstChNode = (ChannelNode) re.getDestination(); @@ -616,6 +617,13 @@ } } } + if (!platformSpec.isMonolithic()) { + if (!bDeclareClientField) { + // Declare a client field to connect to the destination resource of push transfer. + platformSpec.addClientFieldDeclaration(parentComponent); + bDeclareClientField = true; + } + } } } } @@ -623,9 +631,23 @@ } // Declare reference fields for pull data transfer. for (Edge chToRes : resourceNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { + ChannelNode directSrcChNode = (ChannelNode) chToRes.getSource(); + DataTransferChannel directSrcCh = directSrcChNode.getChannel(); + // Should take into account the channel hierarchy. + Set ancestorSrcChannels = directSrcChNode.getAncestors(); + Set descendantSrcChannels = directSrcChNode.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(directSrcChNode.getInEdges()); + for (ChannelNode ancestorSrc: ancestorSrcChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantSrcChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + for (Edge resToCh: inEdges) { DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); + ChannelNode chNode = (ChannelNode) re.getDestination(); + DataTransferChannel ch = chNode.getChannel(); ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch); // Check if the source resource is outside of the channel scope. boolean outsideInputResource = false; @@ -643,6 +665,13 @@ break; } } + // Also take into account the channel hierarchy to determine push/pull transfer. + if (descendantSrcChannels.contains(chNode)) { + outsideInputResource = true; // Regarded as (collecting) pull transfer. + } + if (ancestorSrcChannels.contains(chNode)) { + outsideOutputResource = true; // Regarded as (broadcasting) push transfer. + } if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { noPullTransfer = false; // Declare a field in the parent/this component to refer to the source resource of pull transfer. @@ -734,6 +763,13 @@ } } } + if (!platformSpec.isMonolithic()) { + if (!bDeclareClientField) { + // Declare a client field to connect to the destination resource of push transfer. + platformSpec.addClientFieldDeclaration(parentComponent); + bDeclareClientField = true; + } + } } } } @@ -764,6 +800,7 @@ } } } + return bDeclareClientField; } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java index ef8a618..5de330b 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/IPlatformSpecific.java @@ -4,6 +4,7 @@ import code.ast.Annotation; import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; import code.ast.ImportDeclaration; import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; @@ -12,8 +13,9 @@ boolean hasMain(); boolean isMonolithic(); boolean hasComponentAnnotation(); - boolean hasPlatformSpecificImports(); void addComponentAnnotations(TypeDeclaration component, String resourceName); void addGetAnnotations(MethodDeclaration getMethod); + void addClientFieldDeclaration(TypeDeclaration component); + boolean hasPlatformSpecificImports(); void addPlatformSpecificImports(CompilationUnit cu); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java index 885552a..5582fc9 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/RestApiSpecific.java @@ -5,11 +5,14 @@ import code.ast.Annotation; import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; import code.ast.ImportDeclaration; import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; +import models.algebra.Type; public class RestApiSpecific implements IPlatformSpecific { + public static final Type typeClient = new Type("Client", "Client"); @Override public boolean hasMain() { @@ -39,6 +42,12 @@ } @Override + public void addClientFieldDeclaration(TypeDeclaration component) { + FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); + component.addField(clientField); + } + + @Override public boolean hasPlatformSpecificImports() { return true; } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java index 5bb5328..4afd2c8 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/StandaloneSpecific.java @@ -34,6 +34,10 @@ } @Override + public void addClientFieldDeclaration(TypeDeclaration component) { + } + + @Override public boolean hasPlatformSpecificImports() { return false; }