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/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 9750602..72aac50 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -8,6 +8,7 @@ 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 +23,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 +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.dataConstraintModel.Selector; @@ -51,18 +54,13 @@ TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { Map resourceComponents = new HashMap<>(); Map resourceConstructors = new HashMap<>(); - List> getters = new ArrayList<>(); - List> inputs = new ArrayList<>(); - List> updates = new ArrayList<>(); - List> fields = new ArrayList<>(); 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. @@ -94,6 +92,19 @@ 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()) { @@ -103,71 +114,44 @@ // Declare the getter methods in this resource to obtain the children resources. declareChildGetterMethod(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.Entry, List>> updatesAndCacheFieldsAndInitStatements = declareCacheFieldsAndUpdateMethods(resourceNode, component, langSpec); + Map.Entry, Map>> initStatementsAndUpdateUpdates = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, langSpec); if (component == null) { - // updates were not added to any component because no component had been generated. - for (MethodDeclaration update: updatesAndCacheFieldsAndInitStatements.getKey()) { - updates.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), update)); - } - // Cache fields were not added to any component because no component had been generated. - for (FieldDeclaration field: updatesAndCacheFieldsAndInitStatements.getValue().getKey()) { - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), field)); - } // Constructor statements were not added to any component because no component had been generated. - for (String statement: updatesAndCacheFieldsAndInitStatements.getValue().getValue()) { + 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, constructorParams, 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. - Map.Entry, List> inputMethodsAndInitStatements = 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: inputMethodsAndInitStatements.getKey()) { - inputs.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), in)); - } // Constructor statements were not added to any component because no component had been generated. - for (String statement: inputMethodsAndInitStatements.getValue()) { + for (String statement: initStatementsAndInputUpdates.getKey()) { constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); } } - } - - // Add leaf getter methods to the parent components. - for (Map.Entry entry: getters) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); - } - - // Add leaf input methods to the parent components. - for (Map.Entry entry: inputs) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); - } - - // Add leaf update methods to the parent components. - for (Map.Entry entry: updates) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); - } - - // Add leaf reference fields to the parent components. - for (Map.Entry entry: fields) { - resourceComponents.get(entry.getKey()).addField(entry.getValue()); + for (Map.Entry> entry: initStatementsAndInputUpdates.getValue().entrySet()) { + updateStatements.put(entry.getKey(), entry.getValue()); + } } // Add constructor parameters to the ancestor components. @@ -179,6 +163,14 @@ for (Map.Entry entry: constructorStatements) { resourceConstructors.get(entry.getKey()).addStatement(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, @@ -214,6 +206,35 @@ if (resource.getNumParameters() > 0) params.clear(); return params; } + + 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); + for (Entry termEnt: subTerms.entrySet()) { + Term jsonTerm = termEnt.getValue(); + if (jsonTerm.getType() == 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() + "\"")); + params.add(jsonMember.reduce().toImplementation(new String[] {""})); + } + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); + } + } + 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, List depends, ILanguageSpecific langSpec) { // Declare a constructor in each component. @@ -322,7 +343,7 @@ } } - private void declareFieldsInParentComponent(ResourceNode resourceNode, List> fields, List> constructorParams, 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()) { @@ -346,12 +367,12 @@ } dstResName = getComponentName(dstRes.getResourceHierarchy(), langSpec); FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(new Type(dstResName, dstResName), langSpec.toVariableName(dstResName)); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); + 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)); + parentComponent.addField(refRootFieldForPush); } } } @@ -377,12 +398,12 @@ } srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec); FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(new Type(srcResName, srcResName), langSpec.toVariableName(srcResName)); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); + 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)); + parentComponent.addField(refRootFieldForPull); } noPullTransfer = false; } @@ -393,12 +414,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) { @@ -425,6 +446,9 @@ } else { stateGetter = new MethodDeclaration(getterPrefix + resCompName, false, resStateType, getterParams); } + if (parentComponent != null) { + parentComponent.addMethod(stateGetter); + } } if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { @@ -525,12 +549,11 @@ } } - private Map.Entry, Map.Entry, 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 cacheFields = 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(); @@ -561,8 +584,8 @@ MethodDeclaration update = langSpec.newMethodDeclaration(updateMethodName + srcResComponentName, false, null, vars); if (component != null) { component.addMethod(update); - } else { - updateMethods.add(update); + } else if (parentComponent != null) { + parentComponent.addMethod(update); } // Add a statement to update the state field @@ -571,6 +594,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; @@ -602,8 +636,8 @@ langSpec.getFieldInitializer(srcRes.getResourceStateType(), srcRes.getResourceHierarchy().getInitialValue())); if (component != null) { component.addField(cacheField); - } else { - cacheFields.add(cacheField); + } else if (parentComponent != null){ + parentComponent.addField(cacheField); } } @@ -660,7 +694,7 @@ if (component != null) { MethodDeclaration constructor = getConstructor(component); constructor.addStatement(updateReference); // Initialize the reference field. - } else { + } else if (parentComponent != null){ constructorStatements.add(updateReference); } } @@ -765,7 +799,7 @@ if (component != null) { MethodDeclaration constructor = getConstructor(component); constructor.addStatement(updateReference); // Initialize the reference field. - } else { + } else if (parentComponent != null) { constructorStatements.add(updateReference); } } @@ -785,16 +819,16 @@ } } } - return new AbstractMap.SimpleEntry<>(updateMethods, new AbstractMap.SimpleEntry<>(cacheFields, constructorStatements)); + return new AbstractMap.SimpleEntry<>(constructorStatements, updateStatements); } - private Map.Entry, 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())) { @@ -838,9 +872,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. @@ -900,9 +934,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. @@ -941,47 +975,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 (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 = langSpec.toVariableName(getComponentName(resource, langSpec)); - 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); + } } } } @@ -1104,6 +1150,6 @@ } } } - return new AbstractMap.SimpleEntry<>(inputMethods, constructorStatements); + return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements); } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 8a1ad5d..425052f 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -20,6 +20,7 @@ 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,6 +30,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; @@ -103,6 +105,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; @@ -482,8 +496,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; @@ -563,6 +589,27 @@ return codes; } + private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration childComponent) { + Map subTerms = ((Term) exp).getSubTerms(Term.class); + for (Entry termEnt: subTerms.entrySet()) { + Term jsonTerm = termEnt.getValue(); + if (jsonTerm.getType() == 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() + "\"")); + constructorInvocation = constructorInvocation + jsonMember.reduce().toImplementation(new String[] {""}) + delimiter; + delimiter = ", "; + } + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); + } + } + } + private static MethodDeclaration getConstructor(TypeDeclaration component) { for (MethodDeclaration m: component.getMethods()) { if (m.isConstructor()) return m; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index ecb3daf..0aff98c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -22,6 +22,7 @@ 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; @@ -492,6 +506,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 +598,27 @@ return codes; } + private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration childComponent) { + Map subTerms = ((Term) exp).getSubTerms(Term.class); + for (Entry termEnt: subTerms.entrySet()) { + Term jsonTerm = termEnt.getValue(); + if (jsonTerm.getType() == 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() + "\"")); + constructorInvocation = constructorInvocation + jsonMember.reduce().toImplementation(new String[] {""}) + delimiter; + delimiter = ", "; + } + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); + } + } + } + private static void generatePullDataTransfer(MethodDeclaration methodBody, String fromResourceName, String fromResourcePath, Type fromResourceType) { String varName = new String(fromResourceName); String respTypeName = fromResourceType.getInterfaceTypeName(); @@ -754,6 +801,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/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) {