diff --git a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model b/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model index 07e5d80..b3ddeb5 100644 --- a/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model +++ b/AlgebraicDataflowArchitectureModel/models/CustomerOffice.model @@ -2,6 +2,10 @@ out customers(db:Map, addCustomer(uid:Str, off:Str)) == insert(db, uid, {"off": off}) } +channel CIO_AddCampany { + out companies(db:Map, addCampany(cid:Str, add:Str)) == insert(db, cid, {"add": add}) +} + channel CIO_SetCustomerOff(uid:Str) { out customers.{uid}.off(cid:Str, setOff(cid2)) == cid2 } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 9984ce0..72f2358 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -132,8 +132,11 @@ CodeGenerator.langSpec = langSpec; ArrayList codes = new ArrayList<>(); + // Get the dependency among root nodes. + Map> dependedRootComponentGraph = getDependedRootComponentGraph(model); + // Sort the all components. - ArrayList components = determineComponentOrder(flowGraph); + ArrayList components = determineComponentOrder(flowGraph, dependedRootComponentGraph); // Add the main component. if (mainTypeName == null) { @@ -145,46 +148,89 @@ codes.add(mainCU); // Generate the other components. - generateCodeFromFlowGraph(model, flowGraph, components, mainComponent, mainConstructor, codes, langSpec); + generateCodeFromFlowGraph(model, flowGraph, components, dependedRootComponentGraph, mainComponent, mainConstructor, codes, langSpec); return codes; } - public abstract void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList components, + public abstract void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList components, Map> dependedRootComponentGraph, TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec); - private static ArrayList determineComponentOrder(DataFlowGraph graph) { + private static Map> getDependedRootComponentGraph(DataTransferModel model) { + Map> dependedComponentGraph = new HashMap<>(); + for (Channel ch: model.getChannels()) { + DataTransferChannel dtCh = (DataTransferChannel) ch; + Set inRes = new HashSet<>(); + Set outRes = new HashSet<>(); + for (ChannelMember cm: dtCh.getChannelMembers()) { + if (cm.isOutside()) { + outRes.add(cm.getResource().getResourceHierarchy()); + } else { + inRes.add(cm.getResource().getResourceHierarchy()); + } + } + if (outRes.size() > 0 && inRes.size() > 0) { + for (ResourceHierarchy out: outRes) { + for (ResourceHierarchy in: inRes) { + Set dependings = dependedComponentGraph.get(out.getRoot()); + if (dependings == null) { + dependings = new HashSet<>(); + dependedComponentGraph.put(out.getRoot(), dependings); + } + dependings.add(in.getRoot()); + } + } + } + } + return dependedComponentGraph; + } + + private static ArrayList determineComponentOrder(DataFlowGraph graph, Map> dependedRootComponentGraph) { ArrayList objects = new ArrayList<>(); Set visited = new HashSet<>(); Collection allNodes = graph.getResourceNodes(); for (ResourceNode resNode: allNodes) { - topologicalSort(allNodes, resNode, visited, objects); + topologicalSort(resNode, allNodes, dependedRootComponentGraph, visited, objects); } return objects; } - private static void topologicalSort(Collection allNodes, ResourceNode curResNode, Set visited, List orderedList) { + private static void topologicalSort(ResourceNode curResNode, Collection allNodes, Map> dependedRootComponentGraph, Set visited, List orderedList) { if (visited.contains(curResNode)) return; visited.add(curResNode); - // a caller is before the callee + // A caller is before the callee + + // For each incoming PUSH transfer. for (Edge chToRes: curResNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { if (!(resToCh instanceof DataFlowEdge) || ((PushPullAttribute)((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - topologicalSort(allNodes, (ResourceNode) resToCh.getSource(), visited, orderedList); + topologicalSort((ResourceNode) resToCh.getSource(), allNodes, dependedRootComponentGraph, visited, orderedList); } } } + // For each outgoing PULL transfer. if (curResNode instanceof ResourceNode) { for (Edge resToCh: curResNode.getOutEdges()) { DataFlowEdge de = (DataFlowEdge) resToCh; if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { for (Edge chToRes : resToCh.getDestination().getOutEdges()) { - topologicalSort(allNodes, (ResourceNode) chToRes.getDestination(), visited, orderedList); + topologicalSort((ResourceNode) chToRes.getDestination(), allNodes, dependedRootComponentGraph, visited, orderedList); } } } } - // For reference resources. + // For each depending root node. + if (curResNode instanceof ResourceNode && dependedRootComponentGraph.get(curResNode.getResourceHierarchy()) != null) { + for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(curResNode.getResourceHierarchy())) { + for (ResourceNode rootNode: allNodes) { + ResourceHierarchy rootRes = rootNode.getResourceHierarchy(); + if (rootRes.getParent() == null && rootRes.equals(dependingRes)) { + topologicalSort(rootNode, allNodes, dependedRootComponentGraph, visited, orderedList); + } + } + } + } + // For each reference resource. ResourceNode cn = null; if (curResNode instanceof ResourceNode) { cn = (ResourceNode) curResNode; @@ -200,7 +246,7 @@ ChannelNode chNode = (ChannelNode) resToCh.getDestination(); for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) { if (m.getResource().equals(curResNode.getOutSideResource())) { - topologicalSort(allNodes, resNode, visited, orderedList); + topologicalSort(resNode, allNodes, dependedRootComponentGraph, visited, orderedList); } } } @@ -211,7 +257,7 @@ } protected void updateMainComponent(DataTransferModel model, TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, - final List depends, ILanguageSpecific langSpec) { + final List depends, ILanguageSpecific langSpec) { // Declare the field to refer to each object in the main type. ResourceNode resNode = null; String nodeName = null; @@ -227,7 +273,7 @@ } // Add a statement to instantiate each object to the main constructor. List parameters = new ArrayList<>(); - for (ResourcePath res: depends) { + for (ResourceHierarchy res: depends) { // For the callee objects (the destination resource of push transfer or the source resource of pull transfer). parameters.add(res.getResourceName()); } @@ -237,10 +283,10 @@ for (Channel cg : model.getChannels()) { DataTransferChannel ch = (DataTransferChannel) cg; if (ch.getInputResources().contains(resNode.getOutSideResource())) { - for (ResourcePath id: ch.getReferenceResources()) { - if (!refs.contains(id) && !depends.contains(id)) { - refs.add(id); - String refResName = id.getResourceName(); + for (ResourcePath resPath: ch.getReferenceResources()) { + if (!refs.contains(resPath) && !depends.contains(resPath.getResourceHierarchy())) { + refs.add(resPath); + String refResName = resPath.getResourceName(); parameters.add(refResName); } } @@ -256,11 +302,11 @@ mainConstructorBody.addStatement(langSpec.getFieldAccessor(nodeName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(componentName, parameters) + langSpec.getStatementDelimiter()); } - protected ResourcePath addReference(TypeDeclaration component, MethodDeclaration constructor, ResourcePath dstRes, ILanguageSpecific langSpec) { - if (!generatesComponent(dstRes.getResourceHierarchy())) { + protected ResourceHierarchy addReference(TypeDeclaration component, MethodDeclaration constructor, ResourceHierarchy dstRes, ILanguageSpecific langSpec) { + if (!generatesComponent(dstRes)) { dstRes = dstRes.getParent(); } - String dstComponentName = getComponentName(dstRes.getResourceHierarchy(), langSpec); + String dstComponentName = getComponentName(dstRes, langSpec); if (dstComponentName != null) { String dstNodeName = langSpec.toVariableName(dstComponentName); if (langSpec.declareField()) { @@ -304,7 +350,8 @@ Term childGetter = null; if ((child.getChildren() == null || child.getChildren().size() == 0) && child.getNumParameters() == 0) { // the child is not a class - childGetter = new Field(fieldName, getImplStateType(child, langSpec)); + childGetter = new Term(new Symbol("get" + childTypeName, 1, Symbol.Type.METHOD)); + childGetter.addChild(new Constant("this")); } else { // the child is a class childGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); @@ -391,13 +438,13 @@ } protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, - final List depends, ILanguageSpecific langSpec) { + final List depends, ILanguageSpecific langSpec) { Set 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)) { + if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { refs.add(res); String refResName = langSpec.toComponentName(res.getResourceName()); component.addField(langSpec.newFieldDeclaration(new Type(refResName, refResName), res.getResourceName())); @@ -409,6 +456,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..cf3f036 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -4,10 +4,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.AbstractMap.SimpleEntry; import code.ast.Block; import code.ast.CompilationUnit; @@ -22,6 +24,7 @@ import models.algebra.Field; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Position; import models.algebra.Term; import models.algebra.Type; import models.algebra.UnificationFailed; @@ -30,6 +33,7 @@ import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonAccessor; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -47,24 +51,23 @@ public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { - public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList components, + public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, ArrayList components, Map> dependedRootComponentGraph, TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { Map resourceComponents = new HashMap<>(); - List> getters = new ArrayList<>(); - List> inputs = new ArrayList<>(); - List> fields = new ArrayList<>(); + Map resourceConstructors = new HashMap<>(); + List> constructorParams = new ArrayList<>(); + List> constructorStatements = new ArrayList<>(); + Map> updateStatements = new HashMap<>(); - // For each components. + // For each components (1st pass). for (Node componentNode: components) { - // Declare this resource. ResourceNode resourceNode = (ResourceNode) componentNode; - Type resStateType = getImplStateType(resourceNode.getResourceHierarchy(), langSpec); TypeDeclaration component = null; if (generatesComponent(resourceNode.getResourceHierarchy())) { // A component will be generated for this resource. String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); component = resourceComponents.get(resourceNode.getResourceHierarchy()); - List depends = new ArrayList<>(); + List depends = new ArrayList<>(); if (component == null) { // Add compilation unit for this component. component = langSpec.newTypeDeclaration(resourceName); @@ -73,7 +76,7 @@ codes.add(cu); // Declare the constructor and the fields to refer to other resources. - MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, depends, langSpec); + MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, dependedRootComponentGraph, depends, langSpec); if (resourceNode.getResourceHierarchy().getParent() == null) { // For each root resource @@ -86,63 +89,176 @@ if (constructor.getParameters() == null) { component.removeMethod(constructor); + } else { + resourceConstructors.put(resourceNode.getResourceHierarchy(), constructor); } } + } + } + + // For each components (2nd pass). + for (Node componentNode: components) { + // Declare this resource. + ResourceNode resourceNode = (ResourceNode) componentNode; + Type resStateType = getImplStateType(resourceNode.getResourceHierarchy(), langSpec); + TypeDeclaration component = null; + TypeDeclaration parentComponent = null; + if (generatesComponent(resourceNode.getResourceHierarchy())) { + String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); + component = resourceComponents.get(resourceNode.getResourceHierarchy()); // 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. declareChildGetterMethod(resourceNode, component, langSpec); - - // Declare cache fields and update methods in this resource. - List updates = declareCacheFieldsAndUpdateMethods(resourceNode, component, langSpec); + } + if (resourceNode.getResourceHierarchy().getParent() != null) { + parentComponent = resourceComponents.get(resourceNode.getResourceHierarchy().getParent()); + } + + // Declare cache fields and update methods in this resource. + Map.Entry, Map>> initStatementsAndUpdateUpdates = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, langSpec); + if (component == null) { + // Constructor statements were not added to any component because no component had been generated. + for (String statement: initStatementsAndUpdateUpdates.getKey()) { + constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); + } + } + for (Map.Entry> entry: initStatementsAndUpdateUpdates.getValue().entrySet()) { + updateStatements.put(entry.getKey(), entry.getValue()); } // Declare the state field and reference fields in the parent component. if (component == null) { - declareFieldsInParentComponent(resourceNode, fields, langSpec); + declareFieldsInParentComponent(resourceNode, parentComponent, 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)); - } + MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, parentComponent, resStateType, langSpec); // 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, Map>> initStatementsAndInputUpdates = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, 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)); + // Constructor statements were not added to any component because no component had been generated. + for (String statement: initStatementsAndInputUpdates.getKey()) { + constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); } } + for (Map.Entry> entry: initStatementsAndInputUpdates.getValue().entrySet()) { + updateStatements.put(entry.getKey(), entry.getValue()); + } } - // Add leaf getter methods to the parent components. - for (Map.Entry entry: getters) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); + // Add constructor parameters to the ancestor components. + for (ResourceNode root: flowGraph.getRootResourceNodes()) { + addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams, langSpec); } - // Add leaf input methods to the parent components. - for (Map.Entry entry: inputs) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); + // Add constructor statements. + for (Map.Entry entry: constructorStatements) { + resourceConstructors.get(entry.getKey()).addStatement(entry.getValue()); } - // Add leaf reference fields to the parent components. - for (Map.Entry entry: fields) { - resourceComponents.get(entry.getKey()).addField(entry.getValue()); + // Add update statements. + for (MethodDeclaration method: updateStatements.keySet()) { + Expression updateExp = updateStatements.get(method).getKey(); + ResourceHierarchy childRes = updateStatements.get(method).getValue(); + TypeDeclaration childComponent = resourceComponents.get(childRes); + addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, childRes, childComponent, langSpec); } } + + 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) { + boolean existsParam = false; + if (constructor.getParameters() != null) { + for (VariableDeclaration constParam: constructor.getParameters()) { + if (constParam.getName().equals(param.getName())) { + existsParam = true; + break; + } + } + } + if (!existsParam) { + 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) { + private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy childRes, TypeDeclaration childComponent, ILanguageSpecific langSpec) { + Type replacedJsonType = childRes.getResourceStateType(); + String replacingClassName = getComponentName(childRes, langSpec); + Map subTerms = ((Term) exp).getSubTerms(Term.class); + Iterator> termEntItr = subTerms.entrySet().iterator(); + while (termEntItr.hasNext()) { + Entry termEnt = termEntItr.next(); + Term jsonTerm = termEnt.getValue(); + if (jsonTerm.getType().equals(replacedJsonType)) { + MethodDeclaration childConstructor = getConstructor(childComponent); + List params = new ArrayList<>(); + for (VariableDeclaration var: childConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant("\"" + var.getName() + "\"")); + Expression param = jsonMember.reduce(); + if (param != null) { + params.add(param.toImplementation(new String[] {""})); + } else { + params.add(var.getName()); + } + } + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); + } + } + String[] sideEffects = new String[] {""}; + String newState = exp.toImplementation(sideEffects); + String updateStatement; + if (exp instanceof Term && ((Term) exp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + } else { + updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + method.addFirstStatement(updateStatement); + } + + private MethodDeclaration declareConstructorAndFieldsToReferToResources(ResourceNode resourceNode, TypeDeclaration component, Map> dependedRootComponentGraph, + List depends, ILanguageSpecific langSpec) { // Declare a constructor in each component. MethodDeclaration constructor = component.createConstructor(); Block block = new Block(); @@ -171,7 +287,7 @@ for (Edge chToRes: resToCh.getDestination().getOutEdges()) { // for PUSH transfer if (chToRes.getDestination() instanceof ResourceNode) { - ResourcePath dstRes = addReference(component, constructor, ((ResourceNode) chToRes.getDestination()).getOutSideResource(), langSpec); + ResourceHierarchy dstRes = addReference(component, constructor, ((ResourceNode) chToRes.getDestination()).getOutSideResource().getResourceHierarchy(), langSpec); if (outsideOutputResource) { if (dstRes != null && dstRes.getParent() != null) { // Reference to root resource. @@ -185,12 +301,12 @@ } for (Edge chToRes: resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { - ResourcePath srcRes = ((ResourceNode) resToCh.getSource()).getOutSideResource(); + ResourceHierarchy srcRes = ((ResourceNode) resToCh.getSource()).getOutSideResource().getResourceHierarchy(); DataTransferChannel ch = ((ChannelNode) resToCh.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()) { + if (cm.getResource().getResourceHierarchy().equals(srcRes) && cm.isOutside()) { outsideInputResource = true; // Regarded as pull transfer. break; } @@ -205,7 +321,7 @@ } if ((((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // for PULL transfer - srcRes = addReference(component, constructor, ((ResourceNode) resToCh.getSource()).getOutSideResource(), langSpec); + srcRes = addReference(component, constructor, ((ResourceNode) resToCh.getSource()).getOutSideResource().getResourceHierarchy(), langSpec); if (outsideInputResource) { if (srcRes != null & srcRes.getParent() != null) { // Reference to root resource. @@ -216,15 +332,28 @@ } } } + // 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); + addReference(component, constructor, dependedRes, langSpec); + } + } + } + } 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 +377,7 @@ } } - private void declareFieldsInParentComponent(ResourceNode resourceNode, List> fields, ILanguageSpecific langSpec) { + private void declareFieldsInParentComponent(ResourceNode resourceNode, TypeDeclaration parentComponent, List> constructorParams, ILanguageSpecific langSpec) { // Declare reference fields for push/pull data transfer. boolean noPullTransfer = true; for (Edge resToCh : resourceNode.getOutEdges()) { @@ -272,12 +401,24 @@ } 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)); + parentComponent.addField(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)); + Type dstRootResType = new Type(dstRootResName, dstRootResName); + dstRootResName = langSpec.toVariableName(dstRootResName); + FieldDeclaration refRootFieldForPush = langSpec.newFieldDeclaration(dstRootResType, dstRootResName); + boolean existsField = false; + for (FieldDeclaration field: parentComponent.getFields()) { + if (dstRootResName.equals(field.getName())) { + existsField = true; + break; + } + } + if (!existsField) { + parentComponent.addField(refRootFieldForPush); + } + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), langSpec.newVariableDeclaration(dstRootResType, dstRootResName))); } } } @@ -303,12 +444,24 @@ } 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)); + parentComponent.addField(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)); + Type srcRootResType = new Type(srcRootResName, srcRootResName); + srcRootResName = langSpec.toVariableName(srcRootResName); + FieldDeclaration refRootFieldForPull = langSpec.newFieldDeclaration(srcRootResType, srcRootResName); + boolean existsField = false; + for (FieldDeclaration field: parentComponent.getFields()) { + if (srcRootResName.equals(field.getName())) { + existsField = true; + break; + } + } + if (!existsField) { + parentComponent.addField(refRootFieldForPull); + } + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), langSpec.newVariableDeclaration(srcRootResType, srcRootResName))); } noPullTransfer = false; } @@ -319,11 +472,12 @@ 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)); + parentComponent.addField(stateField); + constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), langSpec.newVariableDeclaration(res.getResourceStateType(), langSpec.toVariableName(resName)))); } } - private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, ILanguageSpecific langSpec) { + private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, Type resStateType, ILanguageSpecific langSpec) { // Declare the getter method of the resource state. MethodDeclaration stateGetter = null; if (component != null) { @@ -350,6 +504,9 @@ } else { stateGetter = new MethodDeclaration(getterPrefix + resCompName, false, resStateType, getterParams); } + if (parentComponent != null) { + parentComponent.addMethod(stateGetter); + } } if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { @@ -450,10 +607,11 @@ } } - private List declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, ILanguageSpecific langSpec) { + private Map.Entry, Map>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, ILanguageSpecific langSpec) { // Declare cash fields and update methods in the component. String resComponentName = langSpec.toComponentName(resourceNode.getResourceName()); - List updateMethods = new ArrayList<>(); + List constructorStatements = new ArrayList<>(); + Map> updateStatements = new HashMap<>(); for (Edge chToRes: resourceNode.getInEdges()) { for (Edge resToCh: chToRes.getSource().getInEdges()) { DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); @@ -482,8 +640,11 @@ } } MethodDeclaration update = langSpec.newMethodDeclaration(updateMethodName + srcResComponentName, false, null, vars); - component.addMethod(update); - updateMethods.add(update); + if (component != null) { + component.addMethod(update); + } else if (parentComponent != null) { + parentComponent.addMethod(update); + } // Add a statement to update the state field if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { @@ -491,6 +652,17 @@ for (ChannelMember out: ch.getOutputChannelMembers()) { if (resourceNode.getInSideResources().contains(out.getResource())) { Expression updateExp = ch.deriveUpdateExpressionOf(out, getPushAccessor()); + // Replace Json constructor with a constructor of the child resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy childRes = outRes.getChildren().iterator().next(); + Type childStateType = childRes.getResourceStateType(); + if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { + updateStatements.put(update, new AbstractMap.SimpleEntry<>(updateExp, childRes)); + break; + } + } + // Add statements to the input method. String[] sideEffects = new String[] {""}; String curState = updateExp.toImplementation(sideEffects); String updateStatement; @@ -520,7 +692,11 @@ srcRes.getResourceStateType(), srcRes.getResourceName(), langSpec.getFieldInitializer(srcRes.getResourceStateType(), srcRes.getResourceHierarchy().getInitialValue())); - component.addField(cacheField); + if (component != null) { + component.addField(cacheField); + } else if (parentComponent != null){ + parentComponent.addField(cacheField); + } } // Update the cache field. @@ -560,9 +736,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); - update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); + update.addStatement(updateReference); // Update the reference field. + // Update constructor. + if (component != null) { + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(updateReference); // Initialize the reference field. + } else if (parentComponent != null){ + constructorStatements.add(updateReference); + } } } } @@ -625,9 +817,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 +841,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); - update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + String updateReference = langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter(); + update.addStatement(updateReference); // Update the reference field. + // Update constructor. + if (component != null) { + MethodDeclaration constructor = getConstructor(component); + constructor.addStatement(updateReference); // Initialize the reference field. + } else if (parentComponent != null) { + constructorStatements.add(updateReference); + } } } } @@ -667,15 +877,16 @@ } } } - return updateMethods; + return new AbstractMap.SimpleEntry<>(constructorStatements, updateStatements); } - private List declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, - TypeDeclaration mainComponent, DataTransferModel model, ILanguageSpecific langSpec) { + private Map.Entry, Map>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, + TypeDeclaration parentComponent, 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<>(); + Map> inputStatements = new HashMap<>(); for (Channel ch : model.getIOChannels()) { for (ChannelMember out : ((DataTransferChannel) ch).getOutputChannelMembers()) { if (resourceNode.getInSideResources().contains(out.getResource())) { @@ -687,25 +898,26 @@ ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); int v = 1; - for (Selector selector: resourceNode.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (out.getResource().getLastParam() != null) { + Expression param = out.getResource().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; resInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; } - if (resourceNode.getParent() != null) { - for (Selector selector: resourceNode.getParent().getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (out.getResource().getParent() != null) { + for (Expression param: out.getResource().getParent().getPathParams()) { + if (param instanceof Variable) { + Variable var = (Variable) param; mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; @@ -719,9 +931,9 @@ if (component != null) { // A component is created for this resource. component.addMethod(input); - } else { + } else if (parentComponent != null) { // No component is created for this resource. - inputMethods.add(input); + parentComponent.addMethod(input); } // Declare the accessor in the main component to call the input method. @@ -749,25 +961,26 @@ ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); int v = 1; - for (Selector selector: resourceNode.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (out.getResource().getLastParam() != null) { + Expression param = out.getResource().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; resInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; resInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; } - if (resourceNode.getResourceHierarchy().getParent() != null) { - for (Selector selector: resourceNode.getParent().getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (out.getResource().getParent() != null) { + for (Expression param: out.getResource().getParent().getPathParams()) { + if (param instanceof Variable) { + Variable var = (Variable) param; mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; mainInputParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; @@ -781,9 +994,9 @@ if (component != null) { // A component is created for this resource. component.addMethod(input); - } else { + } else if (parentComponent != null) { // No component is created for this resource. - inputMethods.add(input); + parentComponent.addMethod(input); } // Declare the accessor in the main component to call the input method. @@ -822,47 +1035,59 @@ if (input != null) { // Add a statement to update the state field to the input method. try { - String[] sideEffects = new String[] {""}; - Expression updateExp; - updateExp = ((DataTransferChannel) ch).deriveUpdateExpressionOf(out, getPullAccessor()); - String newState = updateExp.toImplementation(sideEffects); - ResourceHierarchy resource = resourceNode.getResourceHierarchy(); - if (JavaCodeGenerator.generatesComponent(resource)) { - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - } else { - updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + Expression updateExp = ((DataTransferChannel) ch).deriveUpdateExpressionOf(out, getPullAccessor()); + // Replace Json constructor with a constructor of the child resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy childRes = outRes.getChildren().iterator().next(); + Type childStateType = childRes.getResourceStateType(); + if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { + inputStatements.put(input, new AbstractMap.SimpleEntry<>(updateExp, childRes)); + updateExp = null; } - input.addFirstStatement(updateStatement); - } else { - String updateStatement = null; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - // ToDo. - updateStatement = sideEffects[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]; + } + // Add statements to the input method. + if (updateExp != null) { + String[] sideEffects = new String[] {""}; + String newState = updateExp.toImplementation(sideEffects); + ResourceHierarchy resource = resourceNode.getResourceHierarchy(); + if (generatesComponent(resource)) { + String updateStatement; + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; } else { - String resourceName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource)); - updateStatement = sideEffects[0] + langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); } - if (updateStatement != null) { - input.addFirstStatement(updateStatement); + input.addFirstStatement(updateStatement); + } else { + String updateStatement = null; + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + // ToDo. + updateStatement = sideEffects[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(); + } + if (updateStatement != null) { + input.addFirstStatement(updateStatement); + } } } } @@ -948,9 +1173,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 +1210,6 @@ } } } - return inputMethods; + return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements); } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 3b7f58c..b383fb1 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; @@ -124,12 +125,15 @@ static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { 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<>(); + Map> dependedRootComponentGraph = getDependedRootComponentGraph(model); + ArrayList resources = determineResourceOrder(graph, dependedRootComponentGraph); TypeDeclaration mainComponent = new TypeDeclaration(mainTypeName); CompilationUnit mainCU = new CompilationUnit(mainComponent); mainCU.addImport(new ImportDeclaration("java.util.*")); @@ -156,7 +160,7 @@ codes.add(cu); // Declare the field to refer to each resource in the main type. - Set depends = new HashSet<>(); + Set depends = new HashSet<>(); Set refs = new HashSet<>(); if (rn.getResourceHierarchy().getParent() == null) { // For a root resource @@ -167,7 +171,7 @@ for (Edge chToRes: re.getDestination().getOutEdges()) { ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); String resName = getComponentName(dstRes.getResourceHierarchy()); - depends.add(dstRes); + depends.add(dstRes.getResourceHierarchy()); fieldInitializer += toVariableName(resName) + ","; f = true; } @@ -179,7 +183,7 @@ ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); String resName = getComponentName(srcRes.getResourceHierarchy()); if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - depends.add(srcRes); + depends.add(srcRes.getResourceHierarchy()); fieldInitializer += toVariableName(resName) + ","; f = true; } else { @@ -192,11 +196,22 @@ } } } + for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { + for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { + if (rn.getResourceHierarchy().equals(dependingRes)) { + // Declare a field to refer to outside resources. + depends.add(dependedRes); + String resName = getComponentName(dependedRes); + fieldInitializer += toVariableName(resName) + ","; + f = true; + } + } + } for (Channel ch : model.getChannels()) { DataTransferChannel c = (DataTransferChannel) ch; if (c.getInputResources().contains(rn.getOutSideResource())) { for (ResourcePath res: c.getReferenceResources()) { - if (!refs.contains(res) && !depends.contains(res)) { + if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { refs.add(res); String refResName = res.getResourceName(); fieldInitializer += toVariableName(refResName) + ","; @@ -248,7 +263,7 @@ dstRes = dstRes.getParent(); } String dstResName = getComponentName(dstRes.getResourceHierarchy()); - depends.add(dstRes); + 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) + ";"); @@ -296,7 +311,7 @@ } 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); + 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) + ";"); @@ -324,13 +339,28 @@ } } } + // Declare a field to refer to outside resources. + if (rn.getParent() == null) { + for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { + for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { + if (rn.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(rn.getOutSideResource())) { for (ResourcePath res: c.getReferenceResources()) { - if (!refs.contains(res) && !depends.contains(res)) { + 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())); @@ -341,8 +371,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 +383,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 +459,15 @@ } 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)); + Type dstRootResType = new Type(dstRootResName, dstRootResName); + FieldDeclaration refRootFieldForPush = new FieldDeclaration(dstRootResType, toVariableName(dstRootResName)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refRootFieldForPush)); + constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(dstRootResType, toVariableName(dstRootResName)))); } } } @@ -455,13 +491,15 @@ } 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)); + Type srcRootResType = new Type(srcRootResName, srcRootResName); + FieldDeclaration refRootFieldForPull = new FieldDeclaration(srcRootResType, toVariableName(srcRootResName)); + fields.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), refRootFieldForPull)); + constructorParams.add(new AbstractMap.SimpleEntry<>(rn.getParent().getResourceHierarchy(), new VariableDeclaration(srcRootResType, toVariableName(srcRootResName)))); } noPullTransfer = false; } @@ -472,7 +510,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 +542,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. @@ -544,25 +583,26 @@ ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); v = 1; - for (Selector selector: rn.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (cm.getResource().getLastParam() != null) { + Expression param = cm.getResource().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; resInputParams.add(new VariableDeclaration(var.getType(), var.getName())); mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; resInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); } v++; } - if (rn.getParent() != null) { - for (Selector selector: rn.getParent().getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (cm.getResource().getParent() != null) { + for (Expression param: cm.getResource().getParent().getPathParams()) { + if (param instanceof Variable) { + Variable var = (Variable) param; mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); } v++; @@ -580,7 +620,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. @@ -606,25 +646,26 @@ ArrayList resInputParams = new ArrayList<>(); ArrayList mainInputParams = new ArrayList<>(); v = 1; - for (Selector selector: rn.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (cm.getResource().getLastParam() != null) { + Expression param = cm.getResource().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; resInputParams.add(new VariableDeclaration(var.getType(), var.getName())); mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; resInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); } v++; } - if (rn.getResourceHierarchy().getParent() != null) { - for (Selector selector: rn.getParent().getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (cm.getResource().getParent() != null) { + for (Expression param: cm.getResource().getParent().getPathParams()) { + if (param instanceof Variable) { + Variable var = (Variable) param; mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (param instanceof Term) { + Term var = (Term) param; mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); } v++; @@ -645,7 +686,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. @@ -677,7 +718,21 @@ // Add leaf reference fields to the parent components. for (Map.Entry entry: fields) { - resourceComponents.get(entry.getKey()).addField(entry.getValue()); + boolean existsField = false; + for (FieldDeclaration field: resourceComponents.get(entry.getKey()).getFields()) { + if (field.getName().equals(entry.getValue().getName())) { + existsField = true; + break; + } + } + if (!existsField) { + 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. @@ -732,6 +787,138 @@ return codes; } + private static Map> getDependedRootComponentGraph(DataTransferModel model) { + Map> dependedComponentGraph = new HashMap<>(); + for (Channel ch: model.getChannels()) { + DataTransferChannel dtCh = (DataTransferChannel) ch; + Set inRes = new HashSet<>(); + Set outRes = new HashSet<>(); + for (ChannelMember cm: dtCh.getChannelMembers()) { + if (cm.isOutside()) { + outRes.add(cm.getResource().getResourceHierarchy()); + } else { + inRes.add(cm.getResource().getResourceHierarchy()); + } + } + if (outRes.size() > 0 && inRes.size() > 0) { + for (ResourceHierarchy out: outRes) { + for (ResourceHierarchy in: inRes) { + Set dependings = dependedComponentGraph.get(out.getRoot()); + if (dependings == null) { + dependings = new HashSet<>(); + dependedComponentGraph.put(out.getRoot(), dependings); + } + dependings.add(in.getRoot()); + } + } + } + } + return dependedComponentGraph; + } + + static private ArrayList determineResourceOrder(DataFlowGraph graph, Map> dependedRootComponentGraph) { + ArrayList resources = new ArrayList<>(); + Set visited = new HashSet<>(); + for (Node n : graph.getResourceNodes()) { + ResourceNode resNode = (ResourceNode) n; + topologicalSort(resNode, graph, dependedRootComponentGraph, visited, resources); + } + return resources; + } + + static private void topologicalSort(ResourceNode curResNode, DataFlowGraph graph, Map> dependedRootComponentGraph, Set visited, List orderedList) { + if (visited.contains(curResNode)) return; + visited.add(curResNode); + // For each incoming PUSH transfer. + for (Edge chToRes: curResNode.getInEdges()) { + for (Edge resToCh: chToRes.getSource().getInEdges()) { + DataFlowEdge re = (DataFlowEdge) resToCh; + if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + topologicalSort((ResourceNode) re.getSource(), graph, dependedRootComponentGraph, visited, orderedList); + } + } + } + // For each outgoing PULL transfer. + for (Edge resToCh: curResNode.getOutEdges()) { + DataFlowEdge de = (DataFlowEdge) resToCh; + if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + for (Edge chToRes : resToCh.getDestination().getOutEdges()) { + topologicalSort((ResourceNode) chToRes.getDestination(), graph, dependedRootComponentGraph, visited, orderedList); + } + } + } + // For each depending root node. + if (dependedRootComponentGraph.get(curResNode.getResourceHierarchy()) != null) { + for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(curResNode.getResourceHierarchy())) { + for (ResourceNode root: graph.getRootResourceNodes()) { + if (root.getResourceHierarchy().equals(dependingRes)) { + topologicalSort(root, graph, dependedRootComponentGraph, visited, orderedList); + } + } + } + } + // For each reference resource. + for (Node n: graph.getResourceNodes()) { + ResourceNode resNode = (ResourceNode) n; + for (Edge resToCh : resNode.getOutEdges()) { + ChannelNode chNode = (ChannelNode) resToCh.getDestination(); + for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) { + if (m.getResource().equals(curResNode.getOutSideResource())) { + topologicalSort(resNode, graph, dependedRootComponentGraph, visited, orderedList); + } + } + } + } + orderedList.add(0, curResNode); + } + + 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) { + boolean existsParam = false; + if (constructor.getParameters() != null) { + for (VariableDeclaration constParam: constructor.getParameters()) { + if (constParam.getName().equals(param.getName())) { + existsParam = true; + break; + } + } + } + if (!existsParam) { + 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; @@ -792,49 +979,6 @@ return codes; } - static private ArrayList determineResourceOrder(DataFlowGraph graph) { - ArrayList resources = new ArrayList<>(); - Set visited = new HashSet<>(); - for (Node n : graph.getResourceNodes()) { - ResourceNode resNode = (ResourceNode) n; - topologicalSort(graph, resNode, visited, resources); - } - return resources; - } - - static private void topologicalSort(DataFlowGraph graph, ResourceNode curResNode, Set visited, List orderedList) { - if (visited.contains(curResNode)) return; - visited.add(curResNode); - for (Edge chToRes: curResNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - topologicalSort(graph, (ResourceNode) re.getSource(), visited, orderedList); - } - } - } - for (Edge resToCh: curResNode.getOutEdges()) { - DataFlowEdge de = (DataFlowEdge) resToCh; - if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - for (Edge chToRes : resToCh.getDestination().getOutEdges()) { - topologicalSort(graph, (ResourceNode) chToRes.getDestination(), visited, orderedList); - } - } - } - for (Node n: graph.getResourceNodes()) { // for reference resources. - ResourceNode resNode = (ResourceNode) n; - for (Edge resToCh : resNode.getOutEdges()) { - ChannelNode chNode = (ChannelNode) resToCh.getDestination(); - for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) { - if (m.getResource().equals(curResNode.getOutSideResource())) { - topologicalSort(graph, resNode, visited, orderedList); - } - } - } - } - orderedList.add(0, curResNode); - } - private static MethodDeclaration getMethod(TypeDeclaration type, String methodName, List params) { for (MethodDeclaration m: type.getMethods()) { if (m.getName().equals(methodName)) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 5ff0fc5..b4fde5e 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -1,9 +1,9 @@ package generators; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -14,12 +14,12 @@ import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; import models.Edge; -import models.Node; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.Field; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Position; import models.algebra.Symbol; import models.algebra.Term; import models.algebra.Type; @@ -29,9 +29,9 @@ import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonAccessor; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; -import models.dataConstraintModel.Selector; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; @@ -103,6 +103,18 @@ if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst side resource (when every incoming edge is in push style) Expression updateExp = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor); + // Replace Json constructor with a constructor of the child resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy childRes = outRes.getChildren().iterator().next(); + Type childStateType = childRes.getResourceStateType(); + String childComponentName = JavaCodeGenerator.getComponentName(childRes); + TypeDeclaration childComponent = componentMap.get(childComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + } + } + // Add statements to the update method. String[] sideEffects = new String[] {""}; String curState = updateExp.toImplementation(sideEffects); String updateStatement; @@ -268,6 +280,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 +308,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 +343,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. } } } @@ -393,7 +415,8 @@ Term childGetter = null; if ((child.getChildren() == null || child.getChildren().size() == 0) && child.getNumParameters() == 0) { // the child is not a class - childGetter = new Field(fieldName, JavaCodeGenerator.getImplStateType(child)); + childGetter = new Term(new Symbol("get" + childTypeName, 1, Symbol.Type.METHOD)); + childGetter.addChild(new Constant("this")); } else { // the child is a class childGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); @@ -472,8 +495,20 @@ } if (input != null) { // In each resource - String[] sideEffects = new String[] {""}; Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor); + // Replace Json constructor with a constructor of the child resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy childRes = outRes.getChildren().iterator().next(); + Type childStateType = childRes.getResourceStateType(); + String childComponentName = JavaCodeGenerator.getComponentName(childRes); + TypeDeclaration childComponent = componentMap.get(childComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + } + } + // Add statements to the input method. + String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); if (JavaCodeGenerator.generatesComponent(resource)) { String updateStatement; @@ -553,6 +588,43 @@ return codes; } + private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration childComponent) { + Map subTerms = ((Term) exp).getSubTerms(Term.class); + Iterator> termEntItr = subTerms.entrySet().iterator(); + while (termEntItr.hasNext()) { + Entry termEnt = termEntItr.next(); + Term jsonTerm = termEnt.getValue(); + if (jsonTerm.getType().equals(replacedJsonType)) { + String constructorInvocation = "new " + replacingClassName + "("; + MethodDeclaration childConstructor = getConstructor(childComponent); + String delimiter = ""; + for (VariableDeclaration var: childConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant("\"" + var.getName() + "\"")); + Expression param = jsonMember.reduce(); + if (param != null) { + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(new String[] {""}); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); + } + delimiter = ", "; + } + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); + } + } + } + + 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..9aa4b39 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. @@ -485,7 +490,7 @@ // For a non-root resource MethodDeclaration getterAccessor = null; List mainGetterParams = new ArrayList<>(); - String resourcePath = getGetterResourcePathAndPathParams(rn, mainGetterParams); + String resourcePath = getGetterResourcePathAndPathParams(rn.getOutSideResource(), mainGetterParams); if (resourcePath.indexOf('/') > 0) { resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; } else { @@ -521,7 +526,7 @@ // In each resource. ArrayList resInputParams = new ArrayList<>(); ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = getInputMethodResourcePathaAndPathParams(rn, resInputParams, rootInputParams); + String resourcePath = getInputMethodResourcePathaAndPathParams(cm.getResource(), resInputParams, rootInputParams); if (resourcePath.indexOf('/') > 0) { resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; } else { @@ -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)); } } @@ -564,21 +569,22 @@ // In each resource. ArrayList resInputParams = new ArrayList<>(); int v = 1; - for (Selector selector: rn.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (cm.getResource().getLastParam() != null) { + Expression pathParam = cm.getResource().getLastParam(); + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; String paramName = var.getName(); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); resInputParams.add(param); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; String paramName = "v" + v; VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); resInputParams.add(param); } v++; } - if (rn.getResourceHierarchy().getParent() != null && rn.getResourceHierarchy().getParent().getParent() != null) { + if (cm.getResource().getResourceHierarchy().getParent() != null && cm.getResource().getResourceHierarchy().getParent().getParent() != null) { MethodDeclaration input = new MethodDeclaration(((Variable) cm.getStateTransition().getMessageExpression()).getName(), false, typeVoid, null); if (component != null) { @@ -586,13 +592,13 @@ 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<>(cm.getResource().getParent().getResourceHierarchy(), input)); } } // For the root resource. ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = getGetterResourcePathAndPathParams(rn, rootInputParams); + String resourcePath = getGetterResourcePathAndPathParams(cm.getResource(), rootInputParams); if (resourcePath.indexOf('/') > 0) { resourcePath = "\"" + resourcePath.substring(resourcePath.indexOf('/')) + "\""; } else { @@ -630,6 +636,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,20 +705,56 @@ 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) { + private static String getGetterResourcePathAndPathParams(ResourcePath resPath, List pathParams) { int v = 1; List params = new ArrayList<>(); - for (Selector selector: rn.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + for (Expression pathParam: resPath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); pathParams.add(param); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; String paramName = "v" + v; params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); @@ -716,16 +763,17 @@ } v++; } - return rn.getResourceHierarchy().toResourcePath(params); + return resPath.getResourceHierarchy().toResourcePath(params); } - private static String getInputMethodResourcePathaAndPathParams(ResourceNode rn, ArrayList resInputParams, + private static String getInputMethodResourcePathaAndPathParams(ResourcePath resPath, ArrayList resInputParams, ArrayList rootInputParams) { int v = 1; List params = new ArrayList<>(); - for (Selector selector: rn.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (resPath.getLastParam() != null) { + Expression pathParam = resPath.getLastParam(); + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); @@ -733,8 +781,8 @@ param = new VariableDeclaration(var.getType(), paramName); param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); rootInputParams.add(param); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; String paramName = "v" + v; params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); @@ -745,17 +793,17 @@ } v++; } - if (rn.getParent() != null) { - for (Selector selector: rn.getParent().getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable var = (Variable) selector.getExpression(); + if (resPath.getParent() != null) { + for (Expression pathParam: resPath.getParent().getPathParams()) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; String paramName = var.getName(); params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); rootInputParams.add(param); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; String paramName = "v" + v; params.add("{" + paramName + "}"); VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); @@ -765,7 +813,7 @@ v++; } } - return rn.getResourceHierarchy().toResourcePath(params); + return resPath.getResourceHierarchy().toResourcePath(params); } private static String getInitializer(ResourcePath resId) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index ecb3daf..35c57b8 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -16,12 +17,12 @@ import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; import models.Edge; -import models.Node; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.Field; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Position; import models.algebra.Symbol; import models.algebra.Term; import models.algebra.Type; @@ -31,6 +32,7 @@ import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonAccessor; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; @@ -121,6 +123,18 @@ } updateExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor, inputResourceToStateAccessor); } + // Replace Json constructor with a constructor of the child resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy childRes = outRes.getChildren().iterator().next(); + Type childStateType = childRes.getResourceStateType(); + String childComponentName = JerseyCodeGenerator.getComponentName(childRes); + TypeDeclaration childComponent = componentMap.get(childComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + } + } + // Add statements to the update method. String[] sideEffects = new String[] {""}; String curState = updateExp.toImplementation(sideEffects); String updateStatement; @@ -412,7 +426,8 @@ Term childGetter = null; if ((child.getChildren() == null || child.getChildren().size() == 0) && child.getNumParameters() == 0) { // the child is not a class - childGetter = new Field(fieldName, JerseyCodeGenerator.getImplStateType(child)); + childGetter = new Term(new Symbol("get" + childTypeName, 1, Symbol.Type.METHOD)); + childGetter.addChild(new Constant("this")); } else { // the child is a class childGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); @@ -492,6 +507,18 @@ if (input != null) { // In each resource Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor); + // Replace Json constructor with a constructor of the child resource. + ResourceHierarchy outRes = out.getResource().getResourceHierarchy(); + if (outRes.getChildren().size() == 1 && outRes.getChildren().iterator().next().getNumParameters() > 0) { + ResourceHierarchy childRes = outRes.getChildren().iterator().next(); + Type childStateType = childRes.getResourceStateType(); + String childComponentName = JerseyCodeGenerator.getComponentName(childRes); + TypeDeclaration childComponent = componentMap.get(childComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(childStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, childStateType, childComponentName, childComponent); + } + } + // Add statements to the input method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); if (JerseyCodeGenerator.generatesComponent(resource)) { @@ -572,6 +599,36 @@ return codes; } + private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration childComponent) { + Map subTerms = ((Term) exp).getSubTerms(Term.class); + Iterator> termEntItr = subTerms.entrySet().iterator(); + while (termEntItr.hasNext()) { + Entry termEnt = termEntItr.next(); + Term jsonTerm = termEnt.getValue(); + if (jsonTerm.getType().equals(replacedJsonType)) { + String constructorInvocation = "new " + replacingClassName + "("; + MethodDeclaration childConstructor = getConstructor(childComponent); + String delimiter = ""; + for (VariableDeclaration var: childConstructor.getParameters()) { + JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); + jsonMember.addChild(jsonTerm); + jsonMember.addChild(new Constant("\"" + var.getName() + "\"")); + Expression param = jsonMember.reduce(); + if (param != null) { + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(new String[] {""}); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); + } + delimiter = ", "; + } + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); + } + } + } + private static void generatePullDataTransfer(MethodDeclaration methodBody, String fromResourceName, String fromResourcePath, Type fromResourceType) { String varName = new String(fromResourceName); String respTypeName = fromResourceType.getInterfaceTypeName(); @@ -754,6 +811,13 @@ return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(" + responseShortTypeName + ".class);"; } + private static MethodDeclaration getConstructor(TypeDeclaration component) { + for (MethodDeclaration m: component.getMethods()) { + if (m.isConstructor()) return m; + } + return null; + } + private static MethodDeclaration getUpdateMethod(TypeDeclaration component, TypeDeclaration from) { for (MethodDeclaration m: component.getMethods()) { if (m.getName().equals("update" + from.getTypeName())) return m; diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java index eb827bf..e408a54 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java @@ -79,6 +79,17 @@ } return false; } + + @Override + public boolean equals(Object another) { + if (this == another) return true; + if (another == null) return false; + if (!(another instanceof Type)) return false; + if (!typeName.equals(((Type) another).typeName)) return false; + if (!implementationTypeName.equals(((Type) another).implementationTypeName)) return false; + if (!interfaceTypeName.equals(((Type) another).interfaceTypeName)) return false; + return true; + } public Memento createMemento() { return new Memento(implementationTypeName, interfaceTypeName, parentTypes); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index f117ef6..ed01563 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -135,23 +135,24 @@ public static final Symbol left = new Symbol("left", 1, Symbol.Type.PREFIX, "getLeft", Symbol.Type.METHOD); public static final Symbol right = new Symbol("right", 1, Symbol.Type.PREFIX, "getRight", Symbol.Type.METHOD); public static final Symbol insert = new Symbol("insert", 3, Symbol.Type.PREFIX, "put", Symbol.Type.METHOD_WITH_SIDE_EFFECT); - public static final Symbol lookup = new Symbol("lookup", 2, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { - final int count[] = {0}; - @Override - public String generate(Type type, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { - String temp = "temp_get" + count[0]; - String impl = childrenSideEffects[0] + childrenSideEffects[1]; - impl += type.getInterfaceTypeName() + " " + temp + ";\n"; - impl += "if (" + childrenImpl[0] + ".get(" + childrenImpl[1] + ") != null) {\n"; - impl += "\t" + temp + " = " + childrenImpl[0] + ".get(" + childrenImpl[1] + ");\n"; - impl += "} else {\n"; - impl += "\t" + temp + " = " + getDefaultValue(type) + ";\n"; - impl += "}"; - sideEffect[0] = impl; - count[0]++; - return temp; - } - }); + public static final Symbol lookup = new Symbol("lookup", 2, Symbol.Type.PREFIX, "get", Symbol.Type.METHOD); +// public static final Symbol lookup = new Symbol("lookup", 2, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { +// final int count[] = {0}; +// @Override +// public String generate(Type type, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { +// String temp = "temp_get" + count[0]; +// String impl = childrenSideEffects[0] + childrenSideEffects[1]; +// impl += type.getInterfaceTypeName() + " " + temp + ";\n"; +// impl += "if (" + childrenImpl[0] + ".get(" + childrenImpl[1] + ") != null) {\n"; +// impl += "\t" + temp + " = " + childrenImpl[0] + ".get(" + childrenImpl[1] + ");\n"; +// impl += "} else {\n"; +// impl += "\t" + temp + " = " + getDefaultValue(type) + ";\n"; +// impl += "}"; +// sideEffect[0] = impl; +// count[0]++; +// return temp; +// } +// }); public static final Symbol addMember = new Symbol("addMember", 3, Symbol.Type.PREFIX, "put", Symbol.Type.METHOD_WITH_SIDE_EFFECT); public static final Symbol dot = new Symbol(Parser.DOT, 2, Symbol.Type.INFIX, "get", Symbol.Type.METHOD); public static final Symbol dotParam = new Symbol(Parser.DOT, 2, Symbol.Type.INFIX, "get", Symbol.Type.METHOD); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java index 5d9c4fb..c84207e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java @@ -34,6 +34,30 @@ return super.getType(); } + @Override + public Expression reduce() { + Expression reducedTerm = super.reduce(); + if (reducedTerm instanceof Term) { + if (symbol.equals(DataConstraintModel.dot) && getChildren().size() >= 2) { + // this term is `json.key`. + Expression expJson = getChild(0); + Expression expKey = getChild(1); + if (expKey instanceof Constant && expJson instanceof Term) { + reducedTerm = getValue((Term) expJson, (Constant) expKey); + } + } + } + return reducedTerm; + } + + private Expression getValue(Term json, Constant key) { + if (!json.getSymbol().equals(DataConstraintModel.addMember)) return null; + if (json.getChild(1).equals(key)) { + return json.getChild(2); + } + if (json.getChild(0) == null || json.getChild(0).equals(DataConstraintModel.nil)) return null; + return getValue((Term) json.getChild(0), key); + } @Override public Expression getInverseMap(Expression outputValue, Position targetPos) {