diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 9984ce0..e3919b5 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -409,6 +409,13 @@ } } + protected MethodDeclaration getConstructor(TypeDeclaration component) { + for (MethodDeclaration m: component.getMethods()) { + if (m.isConstructor()) return m; + } + return null; + } + protected MethodDeclaration getUpdateMethod(Edge inEdge, TypeDeclaration component, Map>> dataFlowInform, ILanguageSpecific langSpec) { List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 11096e4..767a3a0 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -50,9 +50,12 @@ public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList components, TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { Map resourceComponents = new HashMap<>(); + Map resourceConstructors = new HashMap<>(); List> getters = new ArrayList<>(); List> inputs = new ArrayList<>(); List> fields = new ArrayList<>(); + List> constructorParams = new ArrayList<>(); + List> constructorStatements = new ArrayList<>(); // For each components. for (Node componentNode: components) { @@ -86,12 +89,14 @@ if (constructor.getParameters() == null) { component.removeMethod(constructor); + } else { + resourceConstructors.put(resourceNode.getResourceHierarchy(), constructor); } } // Declare the field in this resource to store the state. if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - declareStateField(resourceNode, component, resStateType, langSpec); + declareStateField(resourceNode, resourceName, component, resStateType, constructorParams, langSpec); } // Declare the getter methods in this resource to obtain the children resources. @@ -103,25 +108,29 @@ // Declare the state field and reference fields in the parent component. if (component == null) { - declareFieldsInParentComponent(resourceNode, fields, langSpec); + declareFieldsInParentComponent(resourceNode, fields, constructorParams, langSpec); } // Declare the getter method in this resource to obtain the state. MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType, langSpec); if (component == null) { // stateGetter was not added to any component because no component had been generated. - getters.add(new AbstractMap.SimpleEntry(resourceNode.getResourceHierarchy().getParent(), stateGetter)); + getters.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), stateGetter)); } // Declare the accessor method in the main component to call the getter method. declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, langSpec); // Declare input methods in this component and the main component. - List inputMethods = declareInputMethodsInThisAndMainComponents(resourceNode, component, mainComponent, model, langSpec); + Map.Entry, List> inputMethodsAndInitStatements = declareInputMethodsInThisAndMainComponents(resourceNode, component, mainComponent, model, langSpec); if (component == null) { // inputMethods were not added to any component because no component had been generated. - for (MethodDeclaration in: inputMethods) { - inputs.add(new AbstractMap.SimpleEntry(resourceNode.getResourceHierarchy().getParent(), in)); + for (MethodDeclaration in: inputMethodsAndInitStatements.getKey()) { + inputs.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), in)); + } + // Constructor statements were not added to any component because no component had been generated. + for (String statement: inputMethodsAndInitStatements.getValue()) { + constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); } } } @@ -140,8 +149,52 @@ for (Map.Entry entry: fields) { resourceComponents.get(entry.getKey()).addField(entry.getValue()); } + + // Add constructor parameters to the ancestor components. + for (ResourceNode root: flowGraph.getRootResourceNodes()) { + addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams, langSpec); + } + + // Add constructor statements. + for (Map.Entry entry: constructorStatements) { + resourceConstructors.get(entry.getKey()).addStatement(entry.getValue()); + } } - + + private static List addConstructorParameters(ResourceHierarchy resource, Map resourceComponents, + Map resourceConstructors, List> constructorParams, ILanguageSpecific langSpec) { + List params = new ArrayList<>(); + for (ResourceHierarchy child: resource.getChildren()) { + params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams, langSpec)); + } + for (Entry paramEnt: constructorParams) { + if (paramEnt.getKey().equals(resource)) { + params.add(paramEnt.getValue()); + } + } + if (params.size() > 0) { + MethodDeclaration constructor = resourceConstructors.get(resource); + if (constructor == null) { + if (resourceComponents.get(resource) != null) { + String resourceName = getComponentName(resource, langSpec); + constructor = new MethodDeclaration(resourceName, true); + Block body = new Block(); + constructor.setBody(body); + resourceComponents.get(resource).addMethod(constructor); + resourceConstructors.put(resource, constructor); + } + } + if (constructor != null) { + for (VariableDeclaration param: params) { + constructor.addParameter(param); + constructor.getBody().addStatement(langSpec.getFieldAccessor(langSpec.toVariableName(param.getName())) + langSpec.getAssignment() + langSpec.toVariableName(param.getName()) + langSpec.getStatementDelimiter()); + } + } + } + if (resource.getNumParameters() > 0) params.clear(); + return params; + } + private MethodDeclaration declareConstructorAndFieldsToReferToResources(ResourceNode resourceNode, TypeDeclaration component, List depends, ILanguageSpecific langSpec) { // Declare a constructor in each component. MethodDeclaration constructor = component.createConstructor(); @@ -219,12 +272,13 @@ return constructor; } - private void declareStateField(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, ILanguageSpecific langSpec) { + private void declareStateField(ResourceNode resourceNode, String resourceName, TypeDeclaration component, Type resStateType, List> constructorParams, ILanguageSpecific langSpec) { Set children = resourceNode.getResourceHierarchy().getChildren(); if (children == null || children.size() == 0) { // leaf resource. FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue())); component.addField(stateField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), langSpec.newVariableDeclaration(resStateType, langSpec.toVariableName(resourceName)))); } else { ResourceHierarchy child = children.iterator().next(); if (children.size() == 1 && child.getNumParameters() > 0) { @@ -248,7 +302,7 @@ } } - private void declareFieldsInParentComponent(ResourceNode resourceNode, List> fields, ILanguageSpecific langSpec) { + private void declareFieldsInParentComponent(ResourceNode resourceNode, List> fields, List> constructorParams, ILanguageSpecific langSpec) { // Declare reference fields for push/pull data transfer. boolean noPullTransfer = true; for (Edge resToCh : resourceNode.getOutEdges()) { @@ -272,12 +326,12 @@ } dstResName = getComponentName(dstRes.getResourceHierarchy(), langSpec); FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(new Type(dstResName, dstResName), langSpec.toVariableName(dstResName)); - fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); if (dstRes.getParent() != null) { // Reference to root resource. String dstRootResName = getComponentName(dstRes.getRoot().getResourceHierarchy(), langSpec); FieldDeclaration refRootFieldForPush = langSpec.newFieldDeclaration(new Type(dstRootResName, dstRootResName), langSpec.toVariableName(dstRootResName)); - fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPush)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPush)); } } } @@ -303,12 +357,12 @@ } srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec); FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(new Type(srcResName, srcResName), langSpec.toVariableName(srcResName)); - fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); if (srcRes.getParent() != null) { // Reference to root resource. String srcRootResName = getComponentName(srcRes.getRoot().getResourceHierarchy(), langSpec); FieldDeclaration refRootFieldForPull = langSpec.newFieldDeclaration(new Type(srcRootResName, srcRootResName), langSpec.toVariableName(srcRootResName)); - fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPull)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPull)); } noPullTransfer = false; } @@ -319,7 +373,8 @@ 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)); + fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), langSpec.newVariableDeclaration(res.getResourceStateType(), langSpec.toVariableName(resName)))); } } @@ -560,9 +615,20 @@ if (generatesComponent(outsidePath.getResourceHierarchy())) { outsideExp = ((Term) outsideExp).getChild(0); } + Expression nextExp = dependingMember.getStateTransition().getNextStateExpression(); + if (nextExp != null && outsideExp instanceof Term) { + if (nextExp instanceof Variable) { + outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(dependingMember.getResource().getResourceHierarchy())))); + } else { + // ToDo. + } + } String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + // Update constructor. + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // initialize the reference field. } } } @@ -625,9 +691,11 @@ } if (outsideInputMembers2.size() > 0) { if (!generatesComponent(resourceNode.getResourceHierarchy())) { + // srcRes2 does not have a component. ResourcePath srcRes2 = resourceNode.getOutSideResource(); for (ChannelMember out: ch2.getOutputChannelMembers()) { if (!generatesComponent(out.getResource().getResourceHierarchy())) { + // Also dstRes2 does not have a component. ResourcePath dstRes2 = out.getResource(); if (srcRes2.getParent().equals(dstRes2.getParent())) { Map>> resourcePaths = null; @@ -647,9 +715,20 @@ if (generatesComponent(outsidePath.getResourceHierarchy())) { outsideExp = ((Term) outsideExp).getChild(0); } + Expression nextExp = dependingMember.getStateTransition().getNextStateExpression(); + if (nextExp != null && outsideExp instanceof Term) { + if (nextExp instanceof Variable) { + outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(dependingMember.getResource().getResourceHierarchy())))); + } else { + // ToDo. + } + } String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + // Update constructor. + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // initialize the reference field. } } } @@ -670,12 +749,13 @@ return updateMethods; } - private List declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, + private Map.Entry, List> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration mainComponent, DataTransferModel model, ILanguageSpecific langSpec) { // Declare input methods. String resName = resourceNode.getResourceName(); String resComponentName = langSpec.toComponentName(resName); List inputMethods = new ArrayList<>(); + List constructorStatements = new ArrayList<>(); for (Channel ch : model.getIOChannels()) { for (ChannelMember out : ((DataTransferChannel) ch).getOutputChannelMembers()) { if (resourceNode.getInSideResources().contains(out.getResource())) { @@ -948,9 +1028,25 @@ if (generatesComponent(outsidePath.getResourceHierarchy())) { outsideExp = ((Term) outsideExp).getChild(0); } + Expression nextExp = dependingMember.getStateTransition().getNextStateExpression(); + if (nextExp != null && outsideExp instanceof Term) { + if (nextExp instanceof Variable) { + outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(langSpec.toVariableName(getComponentName(dependingMember.getResource().getResourceHierarchy(), langSpec)))); + } else { + // ToDo. + } + } String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); input.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + // Update constructor. + String initializingStatement = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); + if (component != null) { + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(initializingStatement); // initialize the reference field. + } else { + constructorStatements.add(initializingStatement); // initialize the reference field. + } } } } @@ -969,6 +1065,6 @@ } } } - return inputMethods; + return new AbstractMap.SimpleEntry<>(inputMethods, constructorStatements); } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 3b7f58c..9e3f723 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -7,6 +7,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.Stack; @@ -126,9 +127,11 @@ ArrayList codes = new ArrayList<>(); ArrayList resources = determineResourceOrder(graph); Map resourceComponents = new HashMap<>(); + Map resourceConstructors = new HashMap<>(); List> getters = new ArrayList<>(); List> inputs = new ArrayList<>(); List> fields = new ArrayList<>(); + List> constructorParams = new ArrayList<>(); TypeDeclaration mainComponent = new TypeDeclaration(mainTypeName); CompilationUnit mainCU = new CompilationUnit(mainComponent); @@ -341,8 +344,10 @@ } } constructor.setBody(block); - if (constructor.getParameters() != null) + if (constructor.getParameters() != null) { component.addMethod(constructor); + resourceConstructors.put(rn.getResourceHierarchy(), constructor); + } } // Declare the field to store the state in the type of each resource. @@ -351,7 +356,9 @@ Set children = rn.getResourceHierarchy().getChildren(); if (children == null || children.size() == 0) { // leaf resource. - component.addField(new FieldDeclaration(getImplStateType(res.getResourceHierarchy()), "value", getInitializer(res))); + Type fieldType = getImplStateType(res.getResourceHierarchy()); + component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); + constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getResourceHierarchy(), new VariableDeclaration(fieldType, toVariableName(resourceName)))); } else { ResourceHierarchy child = children.iterator().next(); if (children.size() == 1 && child.getNumParameters() > 0) { @@ -425,13 +432,13 @@ } String dstResName = getComponentName(dstRes.getResourceHierarchy()); FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); - fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPush)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPush)); if (dstRes.getParent() != null) { // Reference to root resource. ResourcePath dstRootRes = dstRes.getRoot(); String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); FieldDeclaration refRootFieldForPush = new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); - fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refRootFieldForPush)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refRootFieldForPush)); } } } @@ -455,13 +462,13 @@ } String srcResName = getComponentName(srcRes.getResourceHierarchy()); FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); - fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPull)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPull)); if (srcRes.getParent() != null) { // Reference to root resource. ResourcePath srcRootRes = srcRes.getRoot(); String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); FieldDeclaration refRootFieldForPull = new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); - fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refRootFieldForPull)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refRootFieldForPull)); } noPullTransfer = false; } @@ -472,7 +479,8 @@ 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)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(res.getResourceStateType(), toVariableName(resName)))); } } @@ -503,7 +511,7 @@ } else { stateGetter = new MethodDeclaration("get" + resCompName, false, resType, getterParams); } - getters.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), stateGetter)); + getters.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateGetter)); } // Declare the accessor method in the main type to call the getter method. @@ -580,7 +588,7 @@ component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), input)); + inputs.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), input)); } // In the main type. @@ -645,7 +653,7 @@ component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), input)); + inputs.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), input)); } // In the main type. @@ -679,6 +687,11 @@ for (Map.Entry entry: fields) { resourceComponents.get(entry.getKey()).addField(entry.getValue()); } + + // Add constructor parameters to the ancestor components. + for (ResourceNode root: graph.getRootResourceNodes()) { + addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams); + } // Declare the Pair class. boolean isCreatedPair = false; @@ -732,6 +745,42 @@ return codes; } + private static List addConstructorParameters(ResourceHierarchy resource, + Map resourceComponents, + Map resourceConstructors, + List> constructorParams) { + List params = new ArrayList<>(); + for (ResourceHierarchy child: resource.getChildren()) { + params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams)); + } + for (Entry paramEnt: constructorParams) { + if (paramEnt.getKey().equals(resource)) { + params.add(paramEnt.getValue()); + } + } + if (params.size() > 0) { + MethodDeclaration constructor = resourceConstructors.get(resource); + if (constructor == null) { + if (resourceComponents.get(resource) != null) { + String resourceName = getComponentName(resource); + constructor = new MethodDeclaration(resourceName, true); + Block body = new Block(); + constructor.setBody(body); + resourceComponents.get(resource).addMethod(constructor); + resourceConstructors.put(resource, constructor); + } + } + if (constructor != null) { + for (VariableDeclaration param: params) { + constructor.addParameter(param); + constructor.getBody().addStatement("this." + toVariableName(param.getName()) + " = " + toVariableName(param.getName()) + ";"); + } + } + } + if (resource.getNumParameters() > 0) params.clear(); + return params; + } + private static String getInitializer(ResourcePath res) { Type stateType = res.getResourceStateType(); String initializer = null; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 5ff0fc5..8a1ad5d 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -268,6 +268,7 @@ } } if (outsideInputResource) { + // Update fields to refer to outside resources. Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor); if (resourcePaths != null && resourcePaths.size() > 0) { for (ChannelMember outsideMember: resourcePaths.keySet()) { @@ -295,22 +296,32 @@ String dependingParentResourceName = JavaCodeGenerator.getComponentName(dependingRes.getParent().getResourceHierarchy()); dependingComponent = componentMap.get(dependingParentResourceName); } + Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); + if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + Expression nextExp = dependingMember.getStateTransition().getNextStateExpression(); + if (nextExp != null && outsideExp instanceof Term) { + if (nextExp instanceof Variable) { + outsideExp = ((Term) outsideExp).substitute((Variable) nextExp, new Field(JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy())))); + } else { + // ToDo. + } + } if (dstComponent == dependingComponent) { // In the common parent. - if (dependingNode != null) { - // Inspect further dependency. + if (dependingNode != null) { // Inspect further dependency. for (Edge chToRes2: dependingNode.getInEdges()) { DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); if (ch2.getInputChannelMembers().size() == 0) { - // In an input method. + // In an input method of the parent component. MethodDeclaration input = getInputMethod(dependingComponent, ch2.getOutputChannelMembers().iterator().next()); - Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); - if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); input.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. + // Update constructor. + MethodDeclaration constructor = getConstructor(dependingComponent); + constructor.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // initialize the reference field. } else { boolean isPush = true; for (Edge resToCh2: chToRes2.getSource().getInEdges()) { @@ -320,32 +331,31 @@ } } if (isPush) { + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); for (Edge resToCh2: chToRes2.getSource().getInEdges()) { - // In an update method. + // In an update method of the parent component. ResourceNode dependingResSrc = (ResourceNode) resToCh2.getSource(); MethodDeclaration update = getUpdateMethod(dependingComponent, JavaCodeGenerator.getComponentName(dependingResSrc.getResourceHierarchy())); - Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); - if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. } + // Update constructor. + MethodDeclaration constructor = getConstructor(dependingComponent); + constructor.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // initialize the reference field. } } } } } else { if (pushPull2.getOptions().get(0) == PushPullValue.PUSH) { + // In an update method of the destination component. MethodDeclaration update = getUpdateMethod(dstComponent, JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy())); - Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); - if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. + // Update constructor. + MethodDeclaration constructor = getConstructor(dstComponent); + constructor.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // initialize the reference field. } } } @@ -553,6 +563,13 @@ return codes; } + private static MethodDeclaration getConstructor(TypeDeclaration component) { + for (MethodDeclaration m: component.getMethods()) { + if (m.isConstructor()) return m; + } + return null; + } + private static MethodDeclaration getUpdateMethod(TypeDeclaration component, String fromResName) { for (MethodDeclaration m: component.getMethods()) { if (m.getName().equals("update" + fromResName)) return m; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index fd97870..a5b6a9f 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -130,11 +130,13 @@ // ArrayList resources = StoreResourceCheck(graph); Collection resources = graph.getResourceNodes(); Map resourceComponents = new HashMap<>(); + Map resourceConstructors = new HashMap<>(); List> getters = new ArrayList<>(); List> inputs = new ArrayList<>(); List> fields = new ArrayList<>(); Map getterAccessors = new HashMap<>(); Map inputAccessors = new HashMap<>(); + List> constructorParams = new ArrayList<>(); // For each resource node. for (Node n : resources) { @@ -305,7 +307,9 @@ Set children = rn.getResourceHierarchy().getChildren(); if (children == null || children.size() == 0) { // leaf resource. - component.addField(new FieldDeclaration(getImplStateType(res.getResourceHierarchy()), "value", getInitializer(res))); + Type fieldType = getImplStateType(res.getResourceHierarchy()); + component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); + constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getResourceHierarchy(), new VariableDeclaration(fieldType, toVariableName(resourceName)))); } else { ResourceHierarchy child = children.iterator().next(); if (children.size() == 1 && child.getNumParameters() > 0) { @@ -386,14 +390,14 @@ 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)); + 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)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPush)); } } } @@ -423,14 +427,14 @@ 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)); + 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)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refFieldForPull)); noPullTransfer = false; } } @@ -441,7 +445,8 @@ 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)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateField)); + constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(res.getResourceStateType(), toVariableName(resName)))); } } @@ -477,7 +482,7 @@ } else { stateGetter = new MethodDeclaration("get" + resCompName, false, resType, pathParams); } - getters.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), stateGetter)); + getters.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), stateGetter)); } // Declare the getter accessor in the root resource. @@ -544,7 +549,7 @@ component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), input)); + inputs.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), input)); } } @@ -586,7 +591,7 @@ component.addMethod(input); } else { // No component is created for this resource. - inputs.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), input)); + inputs.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), input)); } } @@ -630,6 +635,11 @@ resourceComponents.get(entry.getKey()).addField(entry.getValue()); } + // Add constructor parameters to the ancestor components. + for (ResourceNode root: graph.getRootResourceNodes()) { + addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams); + } + // Add accessors. for (ResourceHierarchy rootRes: model.getResourceHierarchies()) { if (rootRes.getParent() == null) { @@ -694,6 +704,42 @@ return codes; } + + private static List addConstructorParameters(ResourceHierarchy resource, + Map resourceComponents, + Map resourceConstructors, + List> constructorParams) { + List params = new ArrayList<>(); + for (ResourceHierarchy child: resource.getChildren()) { + params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams)); + } + for (Map.Entry paramEnt: constructorParams) { + if (paramEnt.getKey().equals(resource)) { + params.add(paramEnt.getValue()); + } + } + if (params.size() > 0) { + MethodDeclaration constructor = resourceConstructors.get(resource); + if (constructor == null) { + if (resourceComponents.get(resource) != null) { + String resourceName = getComponentName(resource); + constructor = new MethodDeclaration(resourceName, true); + Block body = new Block(); + constructor.setBody(body); + resourceComponents.get(resource).addMethod(constructor); + resourceConstructors.put(resource, constructor); + } + } + if (constructor != null) { + for (VariableDeclaration param: params) { + constructor.addParameter(param); + constructor.getBody().addStatement("this." + toVariableName(param.getName()) + " = " + toVariableName(param.getName()) + ";"); + } + } + } + if (resource.getNumParameters() > 0) params.clear(); + return params; + } private static String getGetterResourcePathAndPathParams(ResourceNode rn, List pathParams) { int v = 1;