diff --git a/AlgebraicDataflowArchitectureModel/models/DataStore.model b/AlgebraicDataflowArchitectureModel/models/DataStore.model index b424034..9369d6a 100644 --- a/AlgebraicDataflowArchitectureModel/models/DataStore.model +++ b/AlgebraicDataflowArchitectureModel/models/DataStore.model @@ -19,3 +19,4 @@ in companies.{compId}.address(curName: Str, sendCompAddress(compId: Str, compName: Str)) = compName out customers.{custId}.companyAddress(curName: Str, sendCompAddress(compId, compName)) = compName } + diff --git a/AlgebraicDataflowArchitectureModel/models/Search.model b/AlgebraicDataflowArchitectureModel/models/Search.model new file mode 100644 index 0000000..e401c34 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Search.model @@ -0,0 +1,25 @@ +init { + accounts := {"001": {"name": "Alice", "age": 25, "address": "Kobe"}, + "002": {"name": "Bob", "age": 25, "address": "Osaka"}, + "003": {"name": "Carol", "age": 22, "address": "Kobe"}, + "004": {"name": "Dave", "age": 25, "address": "Kobe"} + } +} + +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str, age:Int, address:Str)) = insert(acDB, aid, {"name": name, "age": age, "address": address}) +} + +channel ChangeName(aid:Str) { + out accounts.{aid}.name(n:Str, changeName(name:Str)) = name +} + +channel Query { + out query(q:Json, enterQuery(age:Int, address:Str)) = {"age": age, "address": address} +} + +channel SearchAccount { + in accounts(acDB:Map, searchAccount(acDB2, q2)) = acDB2 + in query(q:Json, searchAccount(acDB2, q2)) = q2 + out result(resultMap:Map, searchAccount(acDB2, q2)) = search(acDB2, q2) +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 4a498b1..18382a0 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -772,6 +772,90 @@ return null; } }); + public static final Symbol search = new Symbol("search", 2, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { + final int count[] = {0}; + @Override + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + for (String s: childrenSideEffects) { + sideEffect[0] += s; + } + String temp = "temp_search" + count[0]; + String impl = ""; + impl += "Map " + temp + " = new HashMap<>();\n"; + impl += "for (String key: " + childrenImpl[0] + ".keySet()) {\n"; + impl += "\tboolean isMatch = true;\n"; + impl += "\tfor (String qKey: " + childrenImpl[1] + ".keySet()) {\n"; + impl += "\t\tMap value = " + childrenImpl[0] + ".get(key).getValue();\n"; + impl += "\t\tfor (String valKey: value.keySet()) {\n"; + impl += "\t\t\tif (valKey.equals(qKey)) {\n"; + impl += "\t\t\t\tif (value.get(valKey).equals(" + childrenImpl[1] + ".get(qKey))) {\n"; + impl += "\t\t\t\t\tisMatch = false;\n"; + impl += "\t\t\t\t}\n"; + impl += "\t\t\t\tbreak;\n"; + impl += "\t\t\t}\n"; + impl += "\t\t}\n"; + impl += "\t\tif (!isMatch) break;\n"; + impl += "\t}\n"; + impl += "\tif (isMatch) {\n"; + impl += "\t\t" + temp + ".put(key, " + childrenImpl[0] + ".get(key));\n"; + impl += "\t}\n"; + impl += "}\n"; + sideEffect[0] += impl; + + count[0]++; + return temp; + } + }, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (args.size() != 2) + return null; + + Expression arg0 = args.get(0); + if (!(arg0 instanceof MapTerm)) { + return null; + } + MapTerm searchFrom = (MapTerm) arg0; + + Expression arg1 = args.get(1); + if (arg1 instanceof JsonTerm) { + JsonTerm queryTerm = (JsonTerm) arg1; + MapTerm result = new MapTerm(); + + for (String key: searchFrom.keySet()) { + boolean isMatch = true; + if (searchFrom.get(key) instanceof JsonTerm) { + JsonTerm value = (JsonTerm) searchFrom.get(key); + for (String qKey: queryTerm.keySet()) { + for (String valKey: value.keySet()) { + if (value.get(valKey) instanceof Constant) { + Constant valVal = (Constant) value.get(valKey); + if (!(valKey.equals(qKey))) { + continue; + } + if (queryTerm.get(qKey) instanceof Constant) { + Constant qVal = (Constant) queryTerm.get(qKey); + if (!(valVal.getValue().equals(qVal.getValue()))) { + isMatch = false; + } + } + break; + } + } + if (!isMatch) break; + } + if (isMatch) { + result.insert(key, value); + } + } else if (searchFrom.get(key) instanceof MapTerm) { + } else if (searchFrom.get(key) instanceof ListTerm) { + } + } + return result; + } + return null; + } + }); public static final Symbol nil = new Symbol("nil", 0, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { final int count[] = {0}; @Override @@ -797,7 +881,7 @@ count[0]++; return temp; } - } + } return "new ArrayList<" + compType + ">()"; } }, true); @@ -809,7 +893,7 @@ @Override public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { String temp = "temp_if" + count[0]; - String impl = ""; + String impl = ""; impl += type.getInterfaceTypeName() + " " + temp + ";\n"; if (childrenSideEffects[0] != null && childrenSideEffects[0].length() > 0) impl += childrenSideEffects[0]; @@ -888,8 +972,8 @@ if (term instanceof MapTerm) { MapTerm mapTerm = (MapTerm) term.clone(); for (Map.Entry childEnt: appendedChldren) { - if (childEnt.getKey().getClass() == Constant.class) - mapTerm.insert((String) ((Constant) childEnt.getKey()).getValue(), childEnt.getValue()); + if (childEnt.getKey().getClass() == Constant.class) + mapTerm.insert((String) ((Constant) childEnt.getKey()).getValue(), childEnt.getValue()); } return mapTerm.get(key); } @@ -934,7 +1018,7 @@ public static final Symbol exp = new Symbol("exp", 1, Symbol.Type.PREFIX, "Math.exp", Symbol.Type.PREFIX); public static final Symbol log = new Symbol("log", 1, Symbol.Type.PREFIX, "Math.log", Symbol.Type.PREFIX); public static final Symbol abs = new Symbol("abs", 1, Symbol.Type.PREFIX, "Math.abs", Symbol.Type.PREFIX); - + static { add.setInverses(new Symbol[] {sub, sub}); mul.setInverses(new Symbol[] {div, div}); @@ -959,13 +1043,14 @@ tail.setSignature(new Type[] {typeList, typeList}); contains.setSignature(new Type[] {typeBoolean, null, null}); indexOf.setSignature(new Type[] {typeInt, typeList, null}); + search.setSignature(new Type[] {typeMap, typeMap, typeJson}); length.setSignature(new Type[] {typeInt, null}); get.setSignature(new Type[] {null, typeList, typeInt}); set.setSignature(new Type[] {typeList, typeList, typeInt, null}); null_.setSignature(new Type[] {null}); true_.setSignature(new Type[] {typeBoolean}); false_.setSignature(new Type[] {typeBoolean}); - pair.setSignature(new Type[] {typePair,null,null}); + pair.setSignature(new Type[] {typePair, null, null}); pair.setInverses(new Symbol[] {left, right}); left.setSignature(new Type[] {null, typePair}); right.setSignature(new Type[] {null, typePair}); @@ -1041,6 +1126,7 @@ addSymbol(tail); addSymbol(length); addSymbol(contains); + addSymbol(search); addSymbol(indexOf); addSymbol(get); addSymbol(set); @@ -1104,7 +1190,7 @@ do { hierarchy = resourcePath.getResourceHierarchy(); if (hierarchy != null && resourceHierarchies.get(hierarchy.toString()) == null) { - resourceHierarchies.put(hierarchy.toString(), hierarchy); + resourceHierarchies.put(hierarchy.toString(), hierarchy); } else { hierarchy = resourceHierarchies.get(hierarchy.toString()); resourcePath.setResourceHierarchy(hierarchy); @@ -1147,7 +1233,7 @@ public Collection getChannels() { return channels.values(); } - + public Channel getChannel(String channelName) { return channels.get(channelName); } @@ -1216,7 +1302,7 @@ } public boolean isPrimitiveType(Type type) { - if (type == typeInt + if (type == typeInt || type == typeLong || type == typeFloat || type == typeDouble diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java index 3998afa..8dba4c8 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java @@ -91,4 +91,17 @@ } return jsonStr + "}"; } + + public String toImplementation(String[] sideEffects) { + final int count[] = new int[]{0}; + String temp = "temp_json" + count[0]; + String impl = ""; + impl += "Map " + temp + " = new HashMap<>();\n"; + for (String key: keySet()) { + impl += temp + ".put(\"" + key + "\", " + get(key).toImplementation(sideEffects) + ");\n"; + } + sideEffects[0] += impl; + count[0]++; + return temp; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java index 76a1463..a5af5fa 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElement.java @@ -48,6 +48,10 @@ data = newJson; } + public JsonTerm getData() { + return data; + } + public MapTerm toMap() { MapTerm res = new MapTerm(); res.insert("type", new Constant("\"" + type + "\"")); diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTableReceiver.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTableReceiver.java new file mode 100644 index 0000000..37e5173 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlElementTableReceiver.java @@ -0,0 +1,63 @@ +package simulator.interfaces.html; + +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Term; +import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ListTerm; +import models.dataConstraintModel.MapTerm; +import simulator.Event; +import simulator.SystemState; +import simulator.interfaces.INativeReceiver; + +public class HtmlElementTableReceiver implements INativeReceiver { + + protected HtmlElement element; + private final IWebSocketMessageSender ws; + + private final String sessionId; + + public HtmlElementTableReceiver(HtmlElement elem, IWebSocketMessageSender ws, String sessionId) { + this.ws = ws; + this.sessionId = sessionId; + element = elem; + } + + @Override + public void onReceiveFromModel(Event event, SystemState nextSystemState) { + Expression message = event.getMessage(); + if (message instanceof Term) { + Expression table = ((Term) message).getChild(0); + if(table instanceof MapTerm) { + MapTerm nextTable = (MapTerm)table; + ListTerm newTableRows = new ListTerm(); + for(String key : nextTable.keySet()) { + ListTerm row = new ListTerm(); + for(Expression colExp : ((ListTerm)element.getData().get("columns")).getChildren()) { + String col = colExp.toString(); + col = col.substring(1, col.length() - 1); + if (((JsonTerm)nextTable.get(key)).get(col) == null) { + row.addChild(new Constant("\"" + key + "\"")); + } else { + row.addChild(((JsonTerm)nextTable.get(key)).get(col)); + } + } + newTableRows.addChild(row); + } + JsonTerm nextTableData = new JsonTerm(); + nextTableData.addMember("columns", element.getData().get("columns")); + nextTableData.addMember("rows", newTableRows); + + JsonTerm json = new JsonTerm(); + json.addMember("method", new Constant("\"updateTable\"")); + json.addMember("id", new Constant("\"" + element.getId() + "\"")); + MapTerm datas = new MapTerm(); + datas.insert("nextTableData", nextTableData); + json.addMember("datas", datas); + + ws.send(json.toString(), sessionId); + } + } + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java index 436af3c..c620566 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/interfaces/html/HtmlPresenter.java @@ -34,17 +34,21 @@ public class HtmlPresenter implements INativeReceiver{ public final String screenUpdateChannelName = "ScreenUpdate"; + public final String screenTemplateUpdateChannelName = "ScreenTemplateUpdate"; public final String setVisibleChannelName = "SetVisible"; public final String setTextChannelName = "SetText"; + public final String setTableChannelName = "OnTableChanged"; public final String mouseEventChannelName = "MouseEvent"; public final String textEventChannelName = "TextEvent"; protected Simulator simulator; protected DataTransferChannel screenUpdateChannel; + protected DataTransferChannel screenTemplateUpdateChannel; protected DataTransferChannel setVisibleChannel; protected DataTransferChannel mouseEventChannel; protected DataTransferChannel textEventChannel; protected DataTransferChannel setTextChannel; + protected DataTransferChannel setTableChannel; protected Map> channelAndResourcesForReceiving = new HashMap<>(); @@ -60,10 +64,12 @@ this.ws = ws; this.sessionId = sessionId; screenUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenUpdateChannelName); + screenTemplateUpdateChannel = (DataTransferChannel) simulator.getModel().getChannel(screenTemplateUpdateChannelName); setVisibleChannel = (DataTransferChannel) simulator.getModel().getChannel(setVisibleChannelName); mouseEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(mouseEventChannelName); setTextChannel = (DataTransferChannel) simulator.getModel().getChannel(setTextChannelName); textEventChannel = (DataTransferChannel) simulator.getModel().getInputChannel(textEventChannelName); + setTableChannel = (DataTransferChannel) simulator.getModel().getChannel(setTableChannelName); simulator.addNativeReceiver(this, screenUpdateChannel); elements = elems; @@ -112,6 +118,8 @@ JsonTerm nextSc = (JsonTerm) nextScExp; Expression oldWidgets = curSc.get("widgets"); Expression newWidgets = nextSc.get("widgets"); + String nextScId = nextSc.get("screenId").toString(); + nextScId = nextScId.substring(1, nextScId.length() - 1); if (oldWidgets instanceof MapTerm && newWidgets instanceof MapTerm) { @@ -125,7 +133,8 @@ } if (!newWidSet.isEmpty()) { - addNewWidgets(newWidSet, nextSystemState, event.getInputResource().getResourceIdentifier(), newWidgets, addElements); + nextSystemState.getResource("screenTemplates").getChildrenMap().get(nextScId).getResourceIdentifier(); + addNewWidgets(newWidSet, nextSystemState, event.getInputResource().getResourceIdentifier(), newWidgets, addElements, nextSystemState.getResource("screenTemplates").getChildrenMap().get(nextScId).getResourceIdentifier()); } } @@ -138,7 +147,7 @@ } - private void addNewWidgets(Set newWidSet, Resource screenResource, Expression newWidgets, ListTerm addElements) { + private void addNewWidgets(Set newWidSet, Resource screenResource, Expression newWidgets, ListTerm addElements, Resource screenTemplateResource) { Resource widgetsResource = screenResource.getChildrenMap().get("widgets"); for(String newWid: newWidSet) { @@ -158,7 +167,7 @@ addTextInput(widget, newWid, addElements, widgetResource); break; case "\"table\"": - addTable(widget, newWid, addElements, widgetResource); + addTable(widget, newWid, addElements, screenTemplateResource.getChildrenMap().get("widgets").getChildrenMap().get(newWid)); break; } } @@ -166,9 +175,10 @@ } - private void addNewWidgets(Set newWidSet, SystemState nextSystemState, ResourceIdentifier ri, Expression newWidgets, ListTerm addElements) { + private void addNewWidgets(Set newWidSet, SystemState nextSystemState, ResourceIdentifier ri, Expression newWidgets, ListTerm addElements, ResourceIdentifier screenIdentifier) { Resource screenResource = nextSystemState.getResource(ri); - addNewWidgets(newWidSet, screenResource, newWidgets, addElements); + Resource screenTemplateResource = nextSystemState.getResource(screenIdentifier); + addNewWidgets(newWidSet, screenResource, newWidgets, addElements, screenTemplateResource); } private void addButton(JsonTerm widget, String wid, ListTerm addElements, Resource widgetResource) { @@ -413,6 +423,16 @@ } resources.put(wid, widgetResource); + //テーブルのデータが変更されたことを通知 + HtmlElementTableReceiver nativeTableReceiver = new HtmlElementTableReceiver(table, ws, sessionId); + simulator.addNativeReceiver(nativeTableReceiver, setTableChannel, widgetResource.getChildrenMap().get("data")); + resources = channelAndResourcesForReceiving.get(setTableChannel); + if (resources == null) { + resources = new HashMap<>(); + channelAndResourcesForReceiving.put(setTableChannel, resources); + } + resources.put(wid, widgetResource); + elements.put(wid, table); addElements.append(table.toMap()); }