diff --git a/AlgebraicDataflowArchitectureModel/models/Citrus.model b/AlgebraicDataflowArchitectureModel/models/Citrus.model new file mode 100644 index 0000000..a4cd25b --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Citrus.model @@ -0,0 +1,69 @@ +channel Signup { + out accounts(accDB:Map, signup(aid:Str)) = insert(accDB, aid, {"favorites": nil, "books": nil}) +} + +channel CreateBook(aid:Str) { + out accounts.{aid}.books(bookList:List, createBook(title:Str)) = append(bookList, {"title": title, "todos": nil, "favorited": nil}) +} + +channel DeleteAccount { + out accounts(accDB:Map, deleteAccount(aid:Str)) = if(contains(accDB, aid), delete(accDB, aid), accDB) +} + +channel ChangeAccountName { + out accounts(accDB:Map, changeAccountId(aid:Str, newAid:Str)) = if(aid == newAid, accDB, delete(insert(accDB, newAid, lookup(accDB, aid)), aid)) +} + +channel ChangeBookName(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.title(title:Str, changeBookName(newTitle)) = newTitle +} + +channel DeleteBook(aid:Str) { + out accounts.{aid}.books(bookList:List, deleteBook(bid:int)) = if(bid < length(bookList), remove(bookList, bid), bookList) +} + +channel CreateToDo(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.todos(toDoDB:Map, createtodo(year:Str, month:Str, day:Str, title:Str)) = insert(toDoDB, + year, + insert(lookup(toDoDB, year), + month, + insert(lookup(lookup(toDoDB, year), month), + day, + append(lookup(lookup(lookup(toDoDB, year), month), day), + {"title": title, "check": false})))) +} + +channel ChangeToDoName(aid:Str, bid:Int, year:Str, month:Str, day:Str, tid:Int) { + out accounts.{aid}.books.{bid}.todos.{year}.{month}.{day}.{tid}.title(title:Str, changeToDoName(newTitle)) = newTitle +} + +channel ChangeCheck(aid:Str, bid:Int, year:Str, month:Str, day:Str, tid:Int) { + out accounts.{aid}.books.{bid}.todos.{year}.{month}.{day}.{tid}.check(check:Bool, changeCheck(newCheck)) = newCheck +} + +channel DeleteToDo(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.todos(toDoDB:Map, deleteToDo(year:Str, month:Str, day:Str, tid:int)) = insert(toDoDB, + year, + insert(lookup(toDoDB, year), + month, + insert(lookup(lookup(toDoDB, year), month), + day, + remove(lookup(lookup(lookup(toDoDB, year), month), day), + tid)))) +} + +channel AddFavorited(aid:Str, bid:Int) { + out accounts.{aid}.books.{bid}.favorited(faList:List, addFavorited(o_aid:Str)) = if(aid==o_aid, + faList, + if(contains(faList, o_aid), + remove(faList, indexOf(faList, o_aid)), + append(faList, o_aid))) + out accounts.{o_aid}.favorites(aDB:Map, addFavorited(o_aid:Str)) + = if(aid==o_aid, + aDB, + if(contains(aDB, aid), + if(contains(lookup(aDB, aid), bid), + insert(aDB, aid, remove(lookup(aDB, aid), indexOf(lookup(aDB, aid), bid))), + insert(aDB, aid, append(lookup(aDB, aid), bid))), + insert(aDB, aid, append(nil, bid)))) +} diff --git a/AlgebraicDataflowArchitectureModel/models/TableUI.model b/AlgebraicDataflowArchitectureModel/models/TableUI.model new file mode 100644 index 0000000..defb520 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/TableUI.model @@ -0,0 +1,114 @@ +init { + screenTemplates := { + "000": { + "widgets": { + "001": {"type": "textInput", "text": "", "state": 0, "visible": true}, + "002": {"type": "table", "text": "testTeble", "state": 0, "visible": true, + "data": {"_": {"name": "_", "age": 0}}, + "rowHeight": 40, + "colWidth": 100, + "columns": append(append(nil, "name"), "age"), + "primaryKeyName": "id", + } + }, + "layout": true + } + } + screen1 := "000" + w002 := "002" +} + +native channel ScreenUpdate { + in screen(curSc: Json, update(curSc, nextSc)) = nextSc +} + +native channel SetLayout { + in screen.layout(curLayout: Bool, setLayout(nextLayout)) = nextLayout +} + +native channel SetVisible(wid: Str) { + in screen.widgets.{wid}.visible(curVisible: Bool, setVisible(nextVisible)) = nextVisible +} + +native channel SetText(wid: Str) { + in screen.widgets.{wid}.text(curText: Str, setText(nextText)) = nextText +} + +native channel SetX(wid: Str) { + in screen.widgets.{wid}.x(curX: Int, setX(nextX)) = nextX +} + +native channel SetY(wid: Str) { + in screen.widgets.{wid}.y(curY: Int, setY(nextY)) = nextY +} + +native channel SetWidth(wid: Str) { + in screen.widgets.{wid}.width(curWidth: Int, setWidth(nextWidth)) = nextWidth +} + +native channel SetHeight(wid: Str) { + in screen.widgets.{wid}.height(curHeight: Int, setHeight(nextHeight)) = nextHeight +} + +native channel MouseEvent(wid: Str) { + out screen.widgets.{wid}.state(curState: Int, mouseEvent(nextState)) = nextState +} + +native channel OnTableChanged(wid: Str) { + in screen.widgets.{wid}.data(curData: Map, tableChanged(nextData)) = nextData +} + +native channel TextEvent(wid: Str) { + out screen.widgets.{wid}.text(curText: Str, textEvent(nextText)) = nextText +} + +channel ChangeCurScreen { + out curScreen(curScId: Str, changeCurScreen(nextScId)) = nextScId +} + +channel ScreenTransition { + in curScreen(curScId: Str, transScreen(nextScId, screen)) = nextScId + ref screenTemplates.{nextScId}(screen, transScreen(nextScId, screen)) + out screen(curS, transScreen(nextScId, screen)) = screen +} + +channel EventDispatch(wid: Str) { + in screen.widgets.{wid}.state(curState: Int, dispatchEvent(curScId, wid, nextState)) = nextState + ref curScreen(curScId: Str, dispatchEvent(curScId, wid, nextState)) + out screenTemplates.{curScId}.widgets.{wid}.state(curState: Int, dispatchEvent(curScId, wid, nextState)) = nextState +} + + +channel EventHandler1(scId: Str, wid: Str) { + in screenTemplates.{scId="000"}.widgets.{wid="002"}.state(curState: Int, handleEvent1(nextState)) = nextState + out curScreen(curScId: Str, handleEvent1(nextState)) = if(nextState == 0, "001", curScId) +} + +channel EventHandler2(scId: Str, wid: Str) { + in screenTemplates.{scId="001"}.widgets.{wid="004"}.state(curState: Int, handleEvent2(nextState)) = nextState + out curScreen(curScId: Str, handleEvent2(nextState)) = if(nextState == 0, "000", curScId) +} + +channel EventHandler3(curScId: Str, wid: Str) { + in screenTemplates.{curScId="000"}.widgets.{wid="002"}.data(curData: Map, handleEvent3(nextData, wid)) = nextData + out screen.widgets.{wid="002"}.data(curData: Map, handleEvent3(nextData, wid)) = nextData +} + +channel addAccount { + out accounts(accounts: Map, addAccount(id: Str, name: Str, age: Int)) = insert(accounts, id, {"name": name, "age": age}) +} + +channel changeNameOfAccount(id: Str) { + out accounts.{id}.name(curName: Str, changeName(nextName: Str)) = nextName +} + +channel changeNameOfAccount(id: Str) { + out accounts.{id}.age(curAge: Int, changeAge(nextAge: Int)) = nextAge +} + +channel sendAccountToTable { + in accounts(cur: Map, sendAccount(next: Map, scId:Str, wid:Str)) = next + ref screen1(scId:Str, sendAccount(next, scId, wid)) + ref w002(wid: Str, sendAccount(next, scId, wid)) + out screenTemplates.{scId}.widgets.{wid}.data(cur: Map, sendAccount(next, scId, wid)) = next +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index fe86c0c..7792b4f 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -98,14 +98,14 @@ if (generatesComponent(child)) { return langSpec.newListType(getComponentName(child, langSpec)); } else { - return langSpec.newListType(getImplStateType(child, langSpec).getImplementationTypeName()); + return langSpec.newListType(getImplStateType(child, langSpec).getInterfaceTypeName()); } } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType())) { // map. if (generatesComponent(child)) { return langSpec.newMapType(DataConstraintModel.typeString, getComponentName(child, langSpec)); } else { - return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getImplementationTypeName()); + return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getInterfaceTypeName()); } } return null; @@ -117,9 +117,11 @@ } public static boolean generatesComponent(ResourceHierarchy res) { - return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); -// Type resType = res.getResourceStateType(); -// return DataConstraintModel.typeJson.isAncestorOf(resType) || DataConstraintModel.typeList.isAncestorOf(resType) || DataConstraintModel.typeMap.isAncestorOf(resType); + if (res.getParent() == null) return true; + if (res.getChildren() == null || res.getChildren().size() == 0) return false; + if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false; + return true; +// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); } /** @@ -367,29 +369,37 @@ } } - protected void fillChildGetterMethod(MethodDeclaration childGetter, ResourceHierarchy child, Type parentResourceType, ILanguageSpecific langSpec) { - if (DataConstraintModel.typeList.isAncestorOf(parentResourceType)) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Variable(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); - } else if (DataConstraintModel.typeMap.isAncestorOf(parentResourceType)) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Variable(langSpec.getFieldAccessor(fieldOfResourceState))); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); + protected void fillDescendantGetterMethod(MethodDeclaration descendantGetter, ResourceHierarchy descendant, ResourceHierarchy ancestor, TypeDeclaration ancestorComponent, ILanguageSpecific langSpec) { + Expression selector; + if (DataConstraintModel.typeList.isAncestorOf(ancestor.getResourceStateType())) { + selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); + } else if (DataConstraintModel.typeMap.isAncestorOf(ancestor.getResourceStateType())) { + selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); } else { - String fieldName = langSpec.toVariableName(getComponentName(child, langSpec)); - childGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldName)) + langSpec.getStatementDelimiter()); - } + String fieldName = langSpec.toVariableName(getComponentName(descendant, langSpec)); + selector = new Variable(langSpec.getFieldAccessor(fieldName)); + } + if (descendantGetter.getParameters() != null) { + for (VariableDeclaration param: descendantGetter.getParameters()) { + if (DataConstraintModel.typeInt.isAncestorOf(param.getType())) { + Term newSelector = new Term(DataConstraintModel.get); + newSelector.addChild(selector); + newSelector.addChild(new Variable(param.getName())); + selector = newSelector; + } else if (DataConstraintModel.typeString.isAncestorOf(param.getType())) { + Term newSelector = new Term(DataConstraintModel.lookup); + newSelector.addChild(selector); + newSelector.addChild(new Variable(param.getName())); + selector = newSelector; + } + } + } + if (descendantGetter != null && (descendantGetter.getBody() == null || descendantGetter.getBody().getStatements().size() == 0)) { + String[] sideEffects = new String[] {null}; + String returnValue = selector.toImplementation(sideEffects); + if (sideEffects[0] != null) descendantGetter.addStatement(sideEffects[0]); + descendantGetter.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); + } } protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourceNode accessRes, MethodDeclaration stateGetter, ILanguageSpecific langSpec) { @@ -453,6 +463,16 @@ return null; } + protected static List getGetterMethods(TypeDeclaration component, String resourceName) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith(getterPrefix + resourceName)) { + getters.add(m); + } + } + return getters; + } + protected MethodDeclaration getUpdateMethod(Edge inEdge, TypeDeclaration component, Map>> dataFlowInform, ILanguageSpecific langSpec) { List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); @@ -602,6 +622,7 @@ // iterate from the root resource Term getter = null; int v = 1; + int arity = 2; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy(), langSpec); @@ -610,23 +631,65 @@ String fieldName = langSpec.toVariableName(typeName); getter = new Field(fieldName, new Type(typeName, typeName)); } else { - Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); - newGetter.addChild(getter); - if (curPath.getResourceHierarchy().getNumParameters() > 0) { - Variable var = null; - Expression param = curPath.getLastParam(); - if (param instanceof Variable) { - var = (Variable) param; - } else if (param instanceof Term) { - var = new Variable("v" + v, ((Term) param).getType()); + if (generatesComponent(curPath.getResourceHierarchy())) { + if (arity == 2) { + Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + newGetter.addChild(var); + newGetter.getSymbol().setArity(2); + } + v++; + } + getter = newGetter; + } else { + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + getter.getSymbol().setArity(arity); + getter.addChild(var); + } + v++; + } } - if (var != null) { - newGetter.addChild(var); - newGetter.getSymbol().setArity(2); + arity = 2; + } else { + // to get a descendant resource directly. + if (arity == 2) { + Term newGetter = new Term(new Symbol(getterPrefix + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; } - v++; + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + getter.getSymbol().setArity(arity); + getter.addChild(var); + arity++; + } + v++; + } } - getter = newGetter; } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index fc6b3f4..14182ed 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.Stack; import java.util.AbstractMap.SimpleEntry; import code.ast.Block; @@ -35,6 +36,7 @@ import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -59,7 +61,7 @@ List> constructorParams = new ArrayList<>(); List> constructorStatements = new ArrayList<>(); Map> updateStatements = new HashMap<>(); - Map> childGetters = new HashMap<>(); + Map> descendantGetters = new HashMap<>(); // For each components (1st pass). for (Node componentNode: components) { @@ -108,8 +110,8 @@ declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, langSpec); } if (component != null) { - // Declare the getter methods in this resource to obtain the children resources. - declareChildGetterMethod(resourceNode, component, childGetters, langSpec); + // Declare the getter methods in this resource to obtain the descendant resources. + declareDescendantGetterMethods(resourceNode, component, descendantGetters, langSpec); } } } @@ -143,9 +145,9 @@ // Declare the fields to refer to other resources in the parent/this component, and the state field in the parent component. declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent, constructorParams, langSpec); - // Declare the getter method in this resource to obtain the state. + // Declare the getter method to obtain the resource state in an ancestor resource. if (component == null) { - MethodDeclaration stateGetter = declareStateGetterMethodInParent(resourceNode, parentComponent, resStateType, langSpec); + MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resourceComponents, resStateType, langSpec); if (stateGetter != null) { // Declare the accessor method in the main component to call the getter method. @@ -179,9 +181,14 @@ // 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); + ResourceHierarchy descendantRes = updateStatements.get(method).getValue(); + Set children; + do { + if (JavaCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + TypeDeclaration descendanttComponent = resourceComponents.get(descendantRes); + addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, descendantRes, descendanttComponent, langSpec); } } @@ -239,33 +246,47 @@ Entry termEnt = termEntItr.next(); Term jsonTerm = termEnt.getValue(); if (jsonTerm.getType() != null && 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) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { + 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(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + params.add(param.toImplementation(null)); + } else { + params.add(var.getName()); } - params.add(param.toImplementation(null)); - } 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(); } - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); } } + // Replace the type of the state field. + Type fieldType = getImplStateType(childRes.getParent(), langSpec); + if (exp instanceof Term) { + ((Term) exp).setType(fieldType); + for (Map.Entry varEnt: ((Term) exp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals(fieldOfResourceState)) { + varEnt.getValue().setType(fieldType); + } + } + } else if (exp instanceof Variable) { + ((Variable) exp).setType(fieldType); + } String[] sideEffects = new String[] {""}; String newState = exp.toImplementation(sideEffects); String updateStatement; @@ -622,38 +643,48 @@ return stateGetter; } - private MethodDeclaration declareStateGetterMethodInParent(ResourceNode resourceNode, TypeDeclaration parentComponent, Type resStateType, ILanguageSpecific langSpec) { - // Check duplication. - String getterName = getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec); - for (MethodDeclaration method: parentComponent.getMethods()) { - if (method.getName().equals(getterName)) return null; - } - - // Declare the getter method of the resource state. + private MethodDeclaration declareStateGetterMethodInAncestor(ResourceNode resourceNode, Map resourceComponents, Type resStateType, ILanguageSpecific langSpec) { + // Search an ancestor in which the getter method is declared. + ResourceNode ancestorNode = resourceNode; + Stack ancestors = new Stack<>(); + do { + ancestors.push(ancestorNode); + ancestorNode = ancestorNode.getParent(); + } while (!generatesComponent(ancestorNode.getResourceHierarchy())); + TypeDeclaration ancestorComponent = resourceComponents.get(ancestorNode.getResourceHierarchy()); List getterParams = new ArrayList<>(); int v = 1; - for (Selector param: resourceNode.getSelectors()) { - if (param.getExpression() instanceof Variable) { - Variable var = (Variable) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param.getExpression() instanceof Term) { - Term var = (Term) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), "v" + v)); + while (ancestors.size() > 0) { + ResourceNode curAncestor = ancestors.pop(); + Expression param = curAncestor.getPrimaryResourcePath().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; + getterParams.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + getterParams.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } v++; } + // Check duplication. + String getterName = getterPrefix + getComponentName(resourceNode.getResourceHierarchy(), langSpec); + for (MethodDeclaration method: ancestorComponent.getMethods()) { + if (method.getName().equals(getterName) && method.getParameters().size() == getterParams.size()) return null; + } + + // Declare the getter method of the resource state. MethodDeclaration stateGetter = null; if (getterParams.size() == 0) { - stateGetter = new MethodDeclaration(getterName, resStateType); + stateGetter = langSpec.newMethodDeclaration(getterName, resStateType); } else { - stateGetter = new MethodDeclaration(getterName, false, resStateType, getterParams); + stateGetter = langSpec.newMethodDeclaration(getterName, false, resStateType, getterParams); } - if (parentComponent != null) { - parentComponent.addMethod(stateGetter); + if (ancestorComponent != null) { + ancestorComponent.addMethod(stateGetter); } if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - fillChildGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resourceNode.getResourceHierarchy().getParent().getResourceStateType(), langSpec); + fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent, langSpec); } else { addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, langSpec); } @@ -716,44 +747,51 @@ } } - private void declareChildGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Map> childGetters, ILanguageSpecific langSpec) { - // Declare the getter methods in this resource to obtain the children resources. - Set children = childGetters.get(resourceNode.getResourceHierarchy()); - if (children == null) { - children = new HashSet<>(); - childGetters.put(resourceNode.getResourceHierarchy(), children); + private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters, ILanguageSpecific langSpec) { + // Declare the getter methods in this resource to obtain descendant resources. + Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); + if (descendants == null) { + descendants = new HashSet<>(); + descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); } for (ResourceNode child: resourceNode.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // A component for the child is generated. - if (!children.contains(child.getResourceHierarchy())) { - children.add(child.getResourceHierarchy()); - List params = new ArrayList<>(); - int v = 1; - Expression param = child.getPrimaryResourcePath().getLastParam(); - if (param != null) { - if (param instanceof Variable) { - Variable var = (Variable) param; - params.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - params.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); - } - v++; + // A descendant of the child may generate a component. + List params = new ArrayList<>(); + int v = 1; + ResourceNode descendant = child; + Set childNodes; + do { + Expression param = descendant.getPrimaryResourcePath().getLastParam(); + if (param != null) { + if (param instanceof Variable) { + Variable var = (Variable) param; + params.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + params.add(langSpec.newVariableDeclaration(var.getType(), "v" + v)); } - String childCompName = getComponentName(child.getResourceHierarchy(), langSpec); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (params.size() == 0) { - childGetter = langSpec.newMethodDeclaration(getterPrefix + childCompName, childType); - } else { - childGetter = langSpec.newMethodDeclaration(getterPrefix + childCompName, false, childType, params); - } - - fillChildGetterMethod(childGetter, child.getResourceHierarchy(), resourceNode.getResourceStateType(), langSpec); - component.addMethod(childGetter); + v++; } - } + if (generatesComponent(descendant.getResourceHierarchy())) { + // If the descendant generates a component. + if (!descendants.contains(descendant.getResourceHierarchy())) { + descendants.add(descendant.getResourceHierarchy()); + String descendantCompName = getComponentName(descendant.getResourceHierarchy(), langSpec); + Type descendantType = new Type(descendantCompName, descendantCompName); + MethodDeclaration descendantGetter = null; + if (params.size() == 0) { + descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, descendantType); + } else { + descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, false, descendantType, params); + } + + fillDescendantGetterMethod(descendantGetter, descendant.getResourceHierarchy(), resourceNode.getResourceHierarchy(), component, langSpec); + component.addMethod(descendantGetter); + } + break; + } + childNodes = descendant.getChildren(); + } while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null); } } @@ -1427,7 +1465,7 @@ ResourcePath ref = rc.getResource(); if (!out.getResource().equals(ref)) { String refVarName = ref.getLeafResourceName(); - Expression refGetter = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, null); + Expression refGetter = getPullAccessor().getDirectStateAccessorFor(ref, null); String[] sideEffects = new String[] {""}; String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 8f17c1a..b646911 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -101,14 +101,14 @@ if (generatesComponent(child)) { return new Type("List", "ArrayList<>", "List<" + getComponentName(child) + ">", DataConstraintModel.typeList); } else { - return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getImplementationTypeName() + ">", DataConstraintModel.typeList); + return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getInterfaceTypeName() + ">", DataConstraintModel.typeList); } } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType())) { // map. if (generatesComponent(child)) { return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } else { - return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); + return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } } return null; @@ -120,9 +120,11 @@ } public static boolean generatesComponent(ResourceHierarchy res) { - return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); -// Type resType = res.getResourceStateType(); -// return DataConstraintModel.typeJson.isAncestorOf(resType) || DataConstraintModel.typeList.isAncestorOf(resType) || DataConstraintModel.typeMap.isAncestorOf(resType); + if (res.getParent() == null) return true; + if (res.getChildren() == null || res.getChildren().size() == 0) return false; + if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false; + return true; +// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); } static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { @@ -133,7 +135,7 @@ Map> updates = new HashMap<>(); Map> inputs = new HashMap<>(); List> fields = new ArrayList<>(); - Map> childGetters = new HashMap<>(); + Map> descendantGetters = new HashMap<>(); List> constructorParams = new ArrayList<>(); Map> dependedRootComponentGraph = getDependedRootComponentGraph(model); @@ -275,41 +277,48 @@ declareAccessorMethodInMainComponent(resourceNode, mainComponent); } if (component != null) { - // Declare the getter methods to obtain the children resources. - Set children = childGetters.get(resourceNode.getResourceHierarchy()); - if (children == null) { - children = new HashSet<>(); - childGetters.put(resourceNode.getResourceHierarchy(), children); + // Declare the getter methods in this resource to obtain descendant resources. + Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); + if (descendants == null) { + descendants = new HashSet<>(); + descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); } for (ResourceNode child: resourceNode.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // A component for the child is generated. - if (!children.contains(child.getResourceHierarchy())) { - children.add(child.getResourceHierarchy()); - List params = new ArrayList<>(); - int v = 1; - Expression param = child.getPrimaryResourcePath().getLastParam(); - if (param != null) { - if (param instanceof Variable) { - Variable var = (Variable) param; - params.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - params.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; + // A descendant of the child may generate a component. + List params = new ArrayList<>(); + int v = 1; + ResourceNode descendant = child; + Set childNodes; + do { + Expression param = descendant.getPrimaryResourcePath().getLastParam(); + if (param != null) { + if (param instanceof Variable) { + Variable var = (Variable) param; + params.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + params.add(new VariableDeclaration(var.getType(), "v" + v)); } - String childCompName = getComponentName(child.getResourceHierarchy()); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (params.size() == 0) { - childGetter = new MethodDeclaration("get" + childCompName, childType); - } else { - childGetter = new MethodDeclaration("get" + childCompName, false, childType, params); - } - component.addMethod(childGetter); + v++; } - } + if (generatesComponent(descendant.getResourceHierarchy())) { + // If the descendant generates a component. + if (!descendants.contains(descendant.getResourceHierarchy())) { + descendants.add(descendant.getResourceHierarchy()); + String descendantCompName = getComponentName(descendant.getResourceHierarchy()); + Type descendantType = new Type(descendantCompName, descendantCompName); + MethodDeclaration descendantGetter = null; + if (params.size() == 0) { + descendantGetter = new MethodDeclaration("get" + descendantCompName, descendantType); + } else { + descendantGetter = new MethodDeclaration("get" + descendantCompName, false, descendantType, params); + } + component.addMethod(descendantGetter); + } + break; + } + childNodes = descendant.getChildren(); + } while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null); } } } @@ -354,30 +363,40 @@ } } - // Declare the getter method to obtain the resource state in the parent component. + // Declare the getter method to obtain the resource state in an ancestor component. if (component == null) { // No component is created for this resource. + ResourceNode ancestorNode = resourceNode; + Stack ancestors = new Stack<>(); + do { + ancestors.push(ancestorNode); + ancestorNode = ancestorNode.getParent(); + } while (!generatesComponent(ancestorNode.getResourceHierarchy())); + List getterParams = new ArrayList<>(); + int v = 1; + while (ancestors.size() > 0) { + ResourceNode curAncestor = ancestors.pop(); + Expression param = curAncestor.getPrimaryResourcePath().getLastParam(); + if (param instanceof Variable) { + Variable var = (Variable) param; + getterParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (param instanceof Term) { + Term var = (Term) param; + getterParams.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } String getterName = "get" + getComponentName(resourceNode.getResourceHierarchy()); boolean bExists = false; for (Map.Entry entry: getters) { - if (entry.getKey() == resourceNode.getParent().getResourceHierarchy() && entry.getValue().getName().equals(getterName)) { + ResourceHierarchy r = entry.getKey(); + MethodDeclaration m = entry.getValue(); + if (r == ancestorNode.getResourceHierarchy() && m.getName().equals(getterName) && m.getParameters().size() == getterParams.size()) { bExists = true; break; } } if (!bExists) { - List getterParams = new ArrayList<>(); - int v = 1; - for (Selector param: resourceNode.getSelectors()) { - if (param.getExpression() instanceof Variable) { - Variable var = (Variable) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param.getExpression() instanceof Term) { - Term var = (Term) param.getExpression(); - getterParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } Type resType = getImplStateType(resourceNode.getResourceHierarchy()); MethodDeclaration stateGetter = null; if (getterParams.size() == 0) { @@ -385,7 +404,7 @@ } else { stateGetter = new MethodDeclaration(getterName, false, resType, getterParams); } - getters.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateGetter)); + getters.add(new AbstractMap.SimpleEntry<>(ancestorNode.getResourceHierarchy(), stateGetter)); // Declare the accessor method in the main type to call the getter method. declareAccessorMethodInMainComponent(resourceNode, mainComponent); @@ -1253,6 +1272,7 @@ // iterate from the root resource Term getter = null; int v = 1; + int arity = 2; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy()); @@ -1261,23 +1281,65 @@ String fieldName = toVariableName(typeName); getter = new Field(fieldName, new Type(typeName, typeName)); } else { - Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); - newGetter.addChild(getter); - if (curPath.getResourceHierarchy().getNumParameters() > 0) { - Variable var = null; - Expression param = curPath.getLastParam(); - if (param instanceof Variable) { - var = (Variable) param; - } else if (param instanceof Term) { - var = new Variable("v" + v, ((Term) param).getType()); + if (generatesComponent(curPath.getResourceHierarchy())) { + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + newGetter.addChild(var); + newGetter.getSymbol().setArity(2); + } + v++; + } + getter = newGetter; + } else { + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + getter.getSymbol().setArity(arity); + getter.addChild(var); + } + v++; + } } - if (var != null) { - newGetter.addChild(var); - newGetter.getSymbol().setArity(2); + arity = 2; + } else { + // to get a descendant resource directly. + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; } - v++; + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + getter.getSymbol().setArity(arity); + getter.addChild(var); + arity++; + } + v++; + } } - getter = newGetter; } } if (generatesComponent(targetRes.getResourceHierarchy())) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 8c2337a..41c68e4 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -32,6 +32,7 @@ import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -110,17 +111,34 @@ } updateExp = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor, inputResourceToStateAccessor).getKey(); } - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant 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); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JavaCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JavaCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JavaCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the update method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -563,10 +581,10 @@ } } } + // for source nodes TypeDeclaration mainComponent = componentMap.get(JavaCodeGenerator.mainTypeName); for (ResourceHierarchy resource: model.getResourceHierarchies()) { -// ResourceNode resource = (ResourceNode) n; String resourceName = JavaCodeGenerator.getComponentName(resource); TypeDeclaration component = componentMap.get(resourceName); if (component != null) { @@ -625,36 +643,62 @@ } } - // child getter method + // descendant getter method if (resource.getChildren().size() > 0) { for (ResourceHierarchy child: resource.getChildren()) { - String methodName = "get" + JavaCodeGenerator.getComponentName(child); - MethodDeclaration childGetter = getMethod(component, methodName); - if (childGetter != null && (childGetter.getBody() == null || childGetter.getBody().getStatements().size() == 0)) { - if (DataConstraintModel.typeList.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue + ";"); - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue+ ";"); - } else { - String fieldName = JavaCodeGenerator.getComponentName(child); - String returnValue = JavaCodeGenerator.toVariableName(fieldName); - childGetter.addStatement("return this." + returnValue + ";"); - } + ResourceHierarchy parent = resource; + ResourceHierarchy descendant = child; + Set children; + Expression selector; + int params = 0; + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; + } else { + String fieldName = JavaCodeGenerator.getComponentName(descendant); + selector = new Field(JavaCodeGenerator.toVariableName(fieldName)); } + do { + String methodName = JavaCodeGenerator.getComponentName(descendant); + MethodDeclaration descendantGetter = null; + for (MethodDeclaration getter: getGetterMethods(component, methodName)) { + if ((getter.getParameters() == null && params == 0) || (getter.getParameters() != null && getter.getParameters().size() == params)) { + descendantGetter = getter; + } + } + if (descendantGetter != null) { + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.get); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.lookup); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } + if (descendantGetter != null && (descendantGetter.getBody() == null || descendantGetter.getBody().getStatements().size() == 0)) { + String[] sideEffects = new String[] {null}; + String returnValue = selector.toImplementation(sideEffects); + if (sideEffects[0] != null) descendantGetter.addStatement(sideEffects[0]); + descendantGetter.addStatement("return " + returnValue + ";"); + } + } + if (JavaCodeGenerator.generatesComponent(descendant)) { + // If the descendant generates a component. + break; + } + parent = descendant; + children = descendant.getChildren(); + } while (children != null && children.size() == 1 && (descendant = children.iterator().next()) != null); } } } @@ -680,17 +724,34 @@ if (input != null) { // In each resource Expression updateExp = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.refAccessor).getKey(); - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant 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); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JavaCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JavaCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JavaCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the input method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -833,34 +894,36 @@ Entry termEnt = termEntItr.next(); Term jsonTerm = termEnt.getValue(); if (jsonTerm.getType() != null && 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) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { + 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(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); - } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); + delimiter = ", "; } - delimiter = ", "; + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); } - constructorInvocation += ")"; - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); } } } @@ -906,6 +969,16 @@ return null; } + private static List getGetterMethods(TypeDeclaration component, String resourceName) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith("get" + resourceName)) { + getters.add(m); + } + } + return getters; + } + private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { Map> ioChannelsAndMembers = new HashMap<>(); for (Channel c: model.getInputChannels()) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index 5ced72d..0dc0551 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -102,14 +102,14 @@ if (generatesComponent(child)) { return new Type("List", "ArrayList<>", "List<" + getComponentName(child) + ">", DataConstraintModel.typeList); } else { - return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getImplementationTypeName() + ">", DataConstraintModel.typeList); + return new Type("List", "ArrayList<>", "List<" + getImplStateType(child).getInterfaceTypeName() + ">", DataConstraintModel.typeList); } } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType())) { // map. if (generatesComponent(child)) { return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } else { - return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); + return new Type("Map", "HashMap<>", "Map", DataConstraintModel.typeMap); } } return null; @@ -121,9 +121,11 @@ } public static boolean generatesComponent(ResourceHierarchy res) { - return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); -// Type resType = res.getResourceStateType(); -// return DataConstraintModel.typeJson.isAncestorOf(resType) || DataConstraintModel.typeList.isAncestorOf(resType) || DataConstraintModel.typeMap.isAncestorOf(resType); + if (res.getParent() == null) return true; + if (res.getChildren() == null || res.getChildren().size() == 0) return false; + if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false; + return true; +// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); } static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { @@ -136,7 +138,7 @@ Map> updates = new HashMap<>(); Map> inputs = new HashMap<>(); List> fields = new ArrayList<>(); - Map> childGetters = new HashMap<>(); + Map> descendantGetters = new HashMap<>(); Map getterAccessors = new HashMap<>(); Map inputAccessors = new HashMap<>(); Map> constructorParams = new HashMap<>(); @@ -221,41 +223,48 @@ component.addMethod(stateGetter); } if (component != null) { - // Declare the getter methods to obtain the children resources. - Set children = childGetters.get(resourceNode.getResourceHierarchy()); - if (children == null) { - children = new HashSet<>(); - childGetters.put(resourceNode.getResourceHierarchy(), children); + // Declare the getter methods in this resource to obtain descendant resources. + Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); + if (descendants == null) { + descendants = new HashSet<>(); + descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); } for (ResourceNode child: resourceNode.getChildren()) { - if (generatesComponent(child.getResourceHierarchy())) { - // The child generates a component. - if (!children.contains(child.getResourceHierarchy())) { - children.add(child.getResourceHierarchy()); - List pathParams = new ArrayList<>(); - int v = 1; - Expression pathParam = child.getPrimaryResourcePath().getLastParam(); - if (pathParam != null) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - pathParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; + // A descendant of the child may generate a component. + List pathParams = new ArrayList<>(); + int v = 1; + ResourceNode descendant = child; + Set childNodes; + do { + Expression pathParam = descendant.getPrimaryResourcePath().getLastParam(); + if (pathParam != null) { + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); } - String childCompName = getComponentName(child.getResourceHierarchy()); - Type childType = new Type(childCompName, childCompName); - MethodDeclaration childGetter = null; - if (pathParams.size() == 0) { - childGetter = new MethodDeclaration("get" + childCompName, childType); - } else { - childGetter = new MethodDeclaration("get" + childCompName, false, childType, pathParams); - } - component.addMethod(childGetter); + v++; } - } + if (generatesComponent(descendant.getResourceHierarchy())) { + // If the descendant generates a component. + if (!descendants.contains(descendant.getResourceHierarchy())) { + descendants.add(descendant.getResourceHierarchy()); + String descendantCompName = getComponentName(descendant.getResourceHierarchy()); + Type descendantType = new Type(descendantCompName, descendantCompName); + MethodDeclaration descendantGetter = null; + if (pathParams.size() == 0) { + descendantGetter = new MethodDeclaration("get" + descendantCompName, descendantType); + } else { + descendantGetter = new MethodDeclaration("get" + descendantCompName, false, descendantType, pathParams); + } + component.addMethod(descendantGetter); + } + break; + } + childNodes = descendant.getChildren(); + } while (childNodes != null && childNodes.size() == 1 && (descendant = childNodes.iterator().next()) != null); } } @@ -380,30 +389,40 @@ } } - // Declare the getter method to obtain the resource state in the parent component. + // Declare the getter method to obtain the resource state in an ancestor component. if (component == null) { // No component is created for this resource. + ResourceNode ancestorNode = resourceNode; + Stack ancestors = new Stack<>(); + do { + ancestors.push(ancestorNode); + ancestorNode = ancestorNode.getParent(); + } while (!generatesComponent(ancestorNode.getResourceHierarchy())); + List pathParams = new ArrayList<>(); + int v = 1; + while (ancestors.size() > 0) { + ResourceNode curAncestor = ancestors.pop(); + Expression pathParam = curAncestor.getPrimaryResourcePath().getLastParam(); + if (pathParam instanceof Variable) { + Variable var = (Variable) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), var.getName())); + } else if (pathParam instanceof Term) { + Term var = (Term) pathParam; + pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); + } + v++; + } String getterName = "get" + getComponentName(resourceNode.getResourceHierarchy()); boolean bExists = false; for (Map.Entry entry: getters) { - if (entry.getKey() == resourceNode.getParent().getResourceHierarchy() && entry.getValue().getName().equals(getterName)) { + ResourceHierarchy r = entry.getKey(); + MethodDeclaration m = entry.getValue(); + if (r == ancestorNode.getResourceHierarchy() && m.getName().equals(getterName) && m.getParameters().size() == pathParams.size()) { bExists = true; break; } } if (!bExists) { - List pathParams = new ArrayList<>(); - int v = 1; - for (Selector pathParam: resourceNode.getSelectors()) { - if (pathParam.getExpression() instanceof Variable) { - Variable var = (Variable) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (pathParam.getExpression() instanceof Term) { - Term var = (Term) pathParam.getExpression(); - pathParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } Type resType = getImplStateType(resourceNode.getResourceHierarchy()); MethodDeclaration stateGetter = null; if (pathParams.size() == 0) { @@ -411,7 +430,7 @@ } else { stateGetter = new MethodDeclaration(getterName, false, resType, pathParams); } - getters.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateGetter)); + getters.add(new AbstractMap.SimpleEntry<>(ancestorNode.getResourceHierarchy(), stateGetter)); } } @@ -1288,6 +1307,7 @@ // iterate from the `from' resource Term getter = null; int v = 1; + int arity = 2; while (!pathStack.empty()) { curPath = pathStack.pop(); String typeName = getComponentName(curPath.getResourceHierarchy()); @@ -1296,23 +1316,65 @@ String fieldName = toVariableName(typeName); getter = new Field(fieldName, new Type(typeName, typeName)); } else { - Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); - newGetter.addChild(getter); - if (curPath.getResourceHierarchy().getNumParameters() > 0) { - Variable var = null; - Expression param = curPath.getLastParam(); - if (param instanceof Variable) { - var = (Variable) param; - } else if (param instanceof Term) { - var = new Variable("v" + v, ((Term) param).getType()); + if (generatesComponent(curPath.getResourceHierarchy())) { + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + newGetter.addChild(var); + newGetter.getSymbol().setArity(2); + } + v++; + } + getter = newGetter; + } else { + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + getter.getSymbol().setArity(arity); + getter.addChild(var); + } + v++; + } } - if (var != null) { - newGetter.addChild(var); - newGetter.getSymbol().setArity(2); + arity = 2; + } else { + // to get a descendant resource directly. + if (arity == 2) { + Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); + newGetter.addChild(getter); + getter = newGetter; } - v++; + if (curPath.getResourceHierarchy().getNumParameters() > 0) { + Variable var = null; + Expression param = curPath.getLastParam(); + if (param instanceof Variable) { + var = (Variable) param; + } else if (param instanceof Term) { + var = new Variable("v" + v, ((Term) param).getType()); + } + if (var != null) { + getter.getSymbol().setArity(arity); + getter.addChild(var); + arity++; + } + v++; + } } - getter = newGetter; } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index b50a570..ffcc360 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -34,6 +34,7 @@ import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -130,17 +131,34 @@ } updateExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor, inputResourceToStateAccessor).getKey(); } - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant 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); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JerseyCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JerseyCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JerseyCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the update method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -688,6 +706,7 @@ } } } + // for source nodes for (ResourceHierarchy resource: model.getResourceHierarchies()) { String resourceName = JerseyCodeGenerator.getComponentName(resource); @@ -748,36 +767,62 @@ } } - // child getter method + // descendant getter method if (resource.getChildren().size() > 0) { for (ResourceHierarchy child: resource.getChildren()) { - String methodName = "get" + JerseyCodeGenerator.getComponentName(child); - MethodDeclaration childGetter = getMethod(component, methodName); - if (childGetter != null && (childGetter.getBody() == null || childGetter.getBody().getStatements().size() == 0)) { - if (DataConstraintModel.typeList.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue + ";"); - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getResourceStateType())) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Field("value")); - selector.addChild(new Variable(childGetter.getParameters().get(childGetter.getParameters().size() - 1).getName())); - selector.setType(childGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = selector.toImplementation(sideEffects); - if (sideEffects[0] != null) childGetter.addStatement(sideEffects[0]); - childGetter.addStatement("return " + returnValue+ ";"); - } else { - String fieldName = JerseyCodeGenerator.getComponentName(child); - String returnValue = JerseyCodeGenerator.toVariableName(fieldName); - childGetter.addStatement("return this." + returnValue + ";"); - } + ResourceHierarchy parent = resource; + ResourceHierarchy descendant = child; + Set children; + Expression selector; + int params = 0; + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + selector = new Field("value"); + params++; + } else { + String fieldName = JerseyCodeGenerator.getComponentName(descendant); + selector = new Field(JerseyCodeGenerator.toVariableName(fieldName)); } + do { + String methodName = JerseyCodeGenerator.getComponentName(descendant); + MethodDeclaration descendantGetter = null; + for (MethodDeclaration getter: getGetterMethods(component, methodName)) { + if ((getter.getParameters() == null && params == 0) || (getter.getParameters() != null && getter.getParameters().size() == params)) { + descendantGetter = getter; + } + } + if (descendantGetter != null) { + if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.get); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { + Term newSelector = new Term(DataConstraintModel.lookup); + newSelector.addChild(selector); + newSelector.addChild(new Variable(descendantGetter.getParameters().get(descendantGetter.getParameters().size() - 1).getName())); + newSelector.setType(descendantGetter.getReturnType()); + selector = newSelector; + params++; + } + if (descendantGetter != null && (descendantGetter.getBody() == null || descendantGetter.getBody().getStatements().size() == 0)) { + String[] sideEffects = new String[] {null}; + String returnValue = selector.toImplementation(sideEffects); + if (sideEffects[0] != null) descendantGetter.addStatement(sideEffects[0]); + descendantGetter.addStatement("return " + returnValue + ";"); + } + } + if (JerseyCodeGenerator.generatesComponent(descendant)) { + // If the descendant generates a component. + break; + } + parent = descendant; + children = descendant.getChildren(); + } while (children != null && children.size() == 1 && (descendant = children.iterator().next()) != null); } } } @@ -836,17 +881,34 @@ } } Expression updateExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.refAccessor).getKey(); - // Replace Json constructor with a constructor of the child resource. + // Replace Json constructor with a constructor of a descendant 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); + ResourceHierarchy descendantRes = outRes.getChildren().iterator().next(); + Set children; + do { + if (JerseyCodeGenerator.generatesComponent(descendantRes)) break; + children = descendantRes.getChildren(); + } while (children != null && children.size() == 1 && (descendantRes = children.iterator().next()) != null); + Type descendantStateType = descendantRes.getResourceStateType(); + String descendantComponentName = JerseyCodeGenerator.getComponentName(descendantRes); + TypeDeclaration descendantComponent = componentMap.get(descendantComponentName); + if (DataConstraintModel.typeJson.isAncestorOf(descendantStateType)) { + replaceJsonTermWithConstructorInvocation(updateExp, descendantStateType, descendantComponentName, descendantComponent); } } + // Replace the type of the state field. + Type fieldType = JerseyCodeGenerator.getImplStateType(outRes); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals("value")) { + varEnt.getValue().setType(fieldType); + } + } + } else if (updateExp instanceof Variable) { + ((Variable) updateExp).setType(fieldType); + } // Add statements to the input method. String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -953,34 +1015,36 @@ Entry termEnt = termEntItr.next(); Term jsonTerm = termEnt.getValue(); if (jsonTerm.getType() != null && 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) { - if (param instanceof Term) { - if (((Term) param).getType() == null) { - ((Term) param).setType(var.getType()); + if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { + 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(), DataConstraintModel.typeString)); + Expression param = jsonMember.reduce(); + if (param != null) { + if (param instanceof Term) { + if (((Term) param).getType() == null) { + ((Term) param).setType(var.getType()); + } + } else if (param instanceof Variable) { + if (((Variable) param).getType() == null) { + ((Variable) param).setType(var.getType()); + } } - } else if (param instanceof Variable) { - if (((Variable) param).getType() == null) { - ((Variable) param).setType(var.getType()); - } + constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); + } else { + constructorInvocation = constructorInvocation + delimiter + var.getName(); } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); - } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); + delimiter = ", "; } - delimiter = ", "; + constructorInvocation += ")"; + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); + subTerms = ((Term) exp).getSubTerms(Term.class); + termEntItr = subTerms.entrySet().iterator(); } - constructorInvocation += ")"; - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); } } } @@ -1185,13 +1249,6 @@ return null; } - private static MethodDeclaration getGetterMethod(TypeDeclaration component, String resourceName) { - for (MethodDeclaration m: component.getMethods()) { - if (m.getName().startsWith("get" + resourceName)) return m; - } - return null; - } - private static List getUpdateMethods(TypeDeclaration component, String resName) { List updates = new ArrayList<>(); for (MethodDeclaration m: component.getMethods()) { @@ -1208,6 +1265,23 @@ return updates; } + private static MethodDeclaration getGetterMethod(TypeDeclaration component, String resourceName) { + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith("get" + resourceName)) return m; + } + return null; + } + + private static List getGetterMethods(TypeDeclaration component, String resourceName) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith("get" + resourceName)) { + getters.add(m); + } + } + return getters; + } + private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { Map> ioChannelsAndMembers = new HashMap<>(); for (Channel c: model.getInputChannels()) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java index 6c2073c..d382534 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/ResourceNode.java @@ -160,6 +160,10 @@ return selectors; } + public Selector getLastSelector() { + return selectors.get(resourceHierarchy.getTotalNumParameters() - 1); + } + public List getAllSelectors() { List selectors = new ArrayList<>(); if (parent != null) { diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java index ba514e9..bdd76dd 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/SwingPresenter.java @@ -6,7 +6,10 @@ import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; import javax.swing.JTextField; +import javax.swing.table.DefaultTableModel; import java.util.HashMap; import java.util.HashSet; @@ -17,6 +20,7 @@ import models.algebra.Expression; import models.algebra.Term; import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ListTerm; import models.dataConstraintModel.MapTerm; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferChannel; @@ -38,6 +42,7 @@ public final String setHeightChannelName = "SetHeight"; public final String mouseEventChannelName = "MouseEvent"; public final String textEventChannelName = "TextEvent"; + public final String OnTableChangedChannelName = "OnTableChanged"; protected JPanel mainPanel; protected Simulator simulator; @@ -54,6 +59,7 @@ protected DataTransferChannel setHeightChannel; protected DataTransferChannel mouseEventChannel; protected DataTransferChannel textEventChannel; + protected DataTransferChannel onTableChangedChannel; protected Map> channelAndResourcesForReceiving = new HashMap<>(); @@ -71,6 +77,7 @@ setHeightChannel = (DataTransferChannel) simulator.getModel().getChannel(setHeightChannelName); mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); + onTableChangedChannel = (DataTransferChannel)simulator.getModel().getChannel(OnTableChangedChannelName); simulator.addNativeReceiver(this, screenUpdateChannel); simulator.addNativeReceiver(new SwingLayout(), setLayoutChannel); } @@ -294,6 +301,147 @@ } resources.put(newWid, widgetHeightResource); } + } else if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("table")) { + // Add a label component. + Expression text = widget.get("text"); + Expression x = widget.get("x"); + Expression y = widget.get("y"); + Expression width = widget.get("width"); + Expression height = widget.get("height"); + MapTerm data = (MapTerm)widget.get("data"); + ListTerm columnsList = (ListTerm)widget.get("columns"); + Constant rowNumExp = (Constant)widget.get("rowNum"); + Constant rowHeightExp = (Constant)widget.get("rowHeight"); + Constant primaryKeyNameExp = (Constant) widget.get("primaryKeyName"); + boolean primaryKeyVisible = !primaryKeyNameExp.getValue().equals(""); + +// JLabel label = new JLabel(((String) ((Constant) text).getValue())); + int colNum = columnsList.size() + (primaryKeyVisible ? 1 : 0); + String[] columns = new String[colNum]; + String[][] tableDatas = new String[data.keySet().size()][colNum]; + if(primaryKeyVisible) { + columns[0] = (String)primaryKeyNameExp.getValue(); + for(int i = 1; i < colNum; i++) { + columns[i] = (String)((Constant)columnsList.get(i - 1)).getValue(); + } + } else { + for(int i = 0; i < colNum; i++) { + columns[i] = (String)((Constant)columnsList.get(i)).getValue(); + } + } + int dataCount = 0; + for(String dataKey : data.keySet()) { + JsonTerm rowData = (JsonTerm) data.get(dataKey); + if(primaryKeyVisible) { + tableDatas[dataCount][0] = dataKey; + for(int j = 1; j < columns.length; j++) { + Constant cellValue = (Constant) rowData.get(columns[j]); + if(cellValue == null) { + tableDatas[dataCount][j] = "error"; + } else { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } + } else { + for(int j = 0; j < columns.length; j++) { + Constant cellValue = (Constant) rowData.get(columns[j]); + if(cellValue == null) { + tableDatas[dataCount][j] = "error"; + } else { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } + } + dataCount++; + } + DefaultTableModel tableModel = new DefaultTableModel(tableDatas, columns); + JTable table = new JTable(tableModel) { + @Override + public boolean isCellEditable(int row, int col) { + return false; + } + }; + JScrollPane scroll = new JScrollPane(table); + + if (x != null && y != null) { + scroll.setLocation(Integer.parseInt(x.toString()), Integer.parseInt(y.toString())); + } + if (width != null && height != null) { + scroll.setSize(Integer.parseInt(width.toString()), Integer.parseInt(height.toString())); + } + mainPanel.add(scroll); + components.put(newWid, scroll); + + // Connect swing component and model. + ComponentVisibilityReceiver nativeVisibilityReceiver = new ComponentVisibilityReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeVisibilityReceiver, setVisibleChannel, widgetResource.getChildrenMap().get("visible")); + Map resources = channelAndResourcesForReceiving.get(setVisibleChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setVisibleChannel, resources); + } + resources.put(newWid, widgetResource); + + Resource widgetXResource = widgetResource.getChildrenMap().get("x"); + if (widgetXResource != null) { + ComponentXReceiver nativeXReceiver = new ComponentXReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeXReceiver, setXChannel, widgetXResource); + resources = channelAndResourcesForReceiving.get(setXChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setXChannel, resources); + } + resources.put(newWid, widgetXResource); + } + + Resource widgetYResource = widgetResource.getChildrenMap().get("y"); + if (widgetYResource != null) { + ComponentYReceiver nativeYReceiver = new ComponentYReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeYReceiver, setYChannel, widgetYResource); + resources = channelAndResourcesForReceiving.get(setYChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setYChannel, resources); + } + resources.put(newWid, widgetYResource); + } + + Resource widgetWidthResource = widgetResource.getChildrenMap().get("width"); + if (widgetWidthResource != null) { + ComponentWidthReceiver nativeWidthReceiver = new ComponentWidthReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeWidthReceiver, setWidthChannel, widgetWidthResource); + resources = channelAndResourcesForReceiving.get(setWidthChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setWidthChannel, resources); + } + resources.put(newWid, widgetWidthResource); + } + + Resource widgetHeightResource = widgetResource.getChildrenMap().get("height"); + if (widgetHeightResource != null) { + ComponentHeightReceiver nativeHeightReceiver = new ComponentHeightReceiver(scroll); // widgetResource => label + simulator.addNativeReceiver(nativeHeightReceiver, setHeightChannel, widgetHeightResource); + resources = channelAndResourcesForReceiving.get(setHeightChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setHeightChannel, resources); + } + resources.put(newWid, widgetHeightResource); + } + + Resource widgetDataResource = widgetResource.getChildrenMap().get("data"); + if(widgetDataResource != null ) { + TableDataReceiver tableDataReceiver = new TableDataReceiver(tableModel, columns, (String)((Constant) primaryKeyNameExp).getValue()); + simulator.addNativeReceiver(tableDataReceiver, onTableChangedChannel, widgetDataResource); + resources = channelAndResourcesForReceiving.get(onTableChangedChannel); + if(resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(onTableChangedChannel, resources); + } + resources.put(newWid, widgetDataResource); + } + } else if (type instanceof Constant && ((String)((Constant) type).getValue()).equals("textInput")) { // Add a text input component. Expression x = widget.get("x"); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/TableDataReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/TableDataReceiver.java new file mode 100644 index 0000000..f2ad1c0 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/swing/TableDataReceiver.java @@ -0,0 +1,54 @@ +package simulator.interfaces.swing; +import javax.swing.table.DefaultTableModel; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.MapTerm; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class TableDataReceiver implements INativeReceiver{ + + protected DefaultTableModel tableModel; + protected String[] columns; + protected String primaryKeyName; + protected boolean primaryKeyVisible; + + public TableDataReceiver(DefaultTableModel table, String[] columns, String primaryKeyName) { + this.tableModel = table; + this.columns = columns; + this.primaryKeyName = primaryKeyName; + this.primaryKeyVisible = !primaryKeyName.equals(""); + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + System.out.println(message); + if(message instanceof Term) { + MapTerm data = (MapTerm)((Term) message).getChild(0); + int colNum = columns.length + (primaryKeyVisible ? 1 : 0); + String[][] tableDatas = new String[data.keySet().size()][colNum]; + int dataCount = 0; + for(String dataKey : data.keySet()) { + JsonTerm rowData = (JsonTerm) data.get(dataKey); + if(primaryKeyVisible) { + tableDatas[dataCount][0] = dataKey; + for(int j = 1; j < columns.length; j++) { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } else { + for(int j = 0; j < columns.length; j++) { + tableDatas[dataCount][j] = (String)((Constant) rowData.get(columns[j])).getValue(); + } + } + dataCount++; + } + tableModel.setDataVector(tableDatas, columns); + } + } + +}