diff --git a/AlgebraicDataflowArchitectureModel/models/StockManagement.model b/AlgebraicDataflowArchitectureModel/models/StockManagement.model index d3ed3f2..131b7ef 100644 --- a/AlgebraicDataflowArchitectureModel/models/StockManagement.model +++ b/AlgebraicDataflowArchitectureModel/models/StockManagement.model @@ -2,46 +2,45 @@ stock := nil shortage := nil } + +channel CIO_enter { + out arrival(s:Tuple, arrive(item:Str, num:Int)) == tuple(item, num) +} + channel CIO_req { out request(r:Tuple, req(item:Str, num:Int)) == tuple(item, num) } -channel CIO_enter { - out entering(e:Tuple, enter(item:Str, num:Int)) == tuple(item, num) -} - channel C1 { - in request(r, update1(r2)) == r2 - out stock(st:Map, update1(r2)) == if(le(snd(r2), lookup(st, fst(r2))), - insert(st, fst(r2), lookup(st, fst(r2)) - snd(r2)), - st) - out shortage(sh:Map, update1(r2)) == if(le(snd(r2), lookup(sh, fst(r2))), - sh, - insert(sh, fst(r2), lookup(sh, fst(r2)) + snd(r2))) + in arrival(ar, update1(ar2, st)) == ar2 + ref stock(st:Map, update1(ar2, st)) + out available(av:Tuple, update1(ar2, st)) == tuple(fst(ar2), snd(ar2) + lookup(st, fst(ar2))) } channel C2 { - in entering(e, update2(e2, st)) == e2 - ref stock(st, update2(e2, st)) - out shortage(sh, update2(e2, st)) == if(ge(snd(e2) + lookup(st, fst(e2)), lookup(sh, fst(e2))), - insert(sh, fst(e2), 0), - sh) + in available(av, update2(av2, sh)) == av2 + ref shortage(sh, update2(av2, sh)) + out deriver(dr:Tuple, update2(av2, sh)) == if(ge(snd(av2), lookup(sh, fst(av2))), + tuple(fst(av2), lookup(sh, fst(av2)), snd(av2) - lookup(sh, fst(av2))), + tuple(fst(av2), 0, snd(av2))) + out shortage(s, update2(av2, sh)) == if(ge(snd(av2), lookup(s, fst(av2))), + insert(s, fst(av2), 0), + s) } channel C3 { - in entering(e, update3(e2, sh)) == e2 - ref shortage(sh, update3(e2, sh)) - out stock(st, update3(e2, sh)) == if(ge(snd(e2) + lookup(st, fst(e2)), lookup(sh, fst(e2))), - insert(st, fst(e2), snd(e2) + lookup(st, fst(e2)) - lookup(sh, fst(e2))), - insert(st, fst(e2), snd(e2) + lookup(st, fst(e2)))) + in deriver(dr, update3(dr2)) == dr2 + out stock(st, update3(dr2)) == insert(st, fst(dr2), snd(snd(dr2))) + out shipping(sp:Tuple, update3(dr2)) == tuple(fst(dr2), fst(snd(dr2))) } channel C4 { - in entering(e, update4(e2, sh, st)) == e2 - ref shortage(sh, update4(e2, sh, st)) - ref stock(st, update4(e2, sh, st)) - out dispatching(d:Tuple, update4(e2, sh, st)) == if(and(gt(lookup(sh, fst(e2)), 0), ge(snd(e2) + lookup(st, fst(e2)), lookup(sh, fst(e2)))), - tuple(fst(e2), lookup(sh, fst(e2))), - null) -} - + in request(rq, update4(rq2, st)) == rq2 + ref stock(st, update4(rq2, st)) + out deriver(dr, update4(rq2, st)) == if(ge(lookup(st, fst(rq2)), snd(rq2)), + tuple(fst(rq2), snd(rq2), lookup(st, fst(rq2)) - snd(rq2)), + tuple(fst(rq2), 0, lookup(st, fst(rq2)))) + out shortage(sh, update4(rq2, st)) == if(ge(lookup(st, fst(rq2)), snd(rq2)), + sh, + insert(sh, fst(rq2), lookup(sh, fst(rq2)) + snd(rq2))) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java index 6f0b0f5..d75e568 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java @@ -80,25 +80,26 @@ + rn.getIdentifierTemplate().getResourceName().substring(1); TypeDeclaration type = new TypeDeclaration(resourceName); - // Declare the field to refer each resource in the main type. + // Declare the field to refer to each resource in the main type. String fieldInitializer = "new " + resourceName + "("; + Set depends = new HashSet<>(); for (Edge e : rn.getOutEdges()) { ResourceDependency re = (ResourceDependency) e; - String rename = ((ResourceNode) re.getDestination()).getIdentifierTemplate().getResourceName() - .substring(0, 1).toUpperCase() - + ((ResourceNode) re.getDestination()).getIdentifierTemplate().getResourceName().substring(1); + IdentifierTemplate dstRes = ((ResourceNode) re.getDestination()).getIdentifierTemplate(); + String resName = dstRes.getResourceName().substring(0, 1).toUpperCase() + dstRes.getResourceName().substring(1); if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - fieldInitializer += rename.toLowerCase() + ","; + depends.add(dstRes); + fieldInitializer += resName.toLowerCase() + ","; f = true; } } for (Edge e : rn.getInEdges()) { ResourceDependency re = (ResourceDependency) e; - String rename = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName() - .substring(0, 1).toUpperCase() - + ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName().substring(1); + IdentifierTemplate srcRes = ((ResourceNode) re.getSource()).getIdentifierTemplate(); + String resName = srcRes.getResourceName().substring(0, 1).toUpperCase() + srcRes.getResourceName().substring(1); if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - fieldInitializer += rename.toLowerCase() + ","; + depends.add(srcRes); + fieldInitializer += resName.toLowerCase() + ","; f = true; } else { if (rn.getIndegree() > 1) { @@ -112,9 +113,9 @@ Set refs = new HashSet<>(); for (ChannelGenerator cg : model.getChannelGenerators()) { DataflowChannelGenerator c = (DataflowChannelGenerator) cg; - if (c.getOutputIdentifierTemplates().contains(rn.getIdentifierTemplate())) { + if (c.getInputIdentifierTemplates().contains(rn.getIdentifierTemplate())) { for (IdentifierTemplate id: c.getReferenceIdentifierTemplates()) { - if (!refs.contains(id)) { + if (!refs.contains(id) && !depends.contains(id)) { refs.add(id); String refResName = id.getResourceName(); fieldInitializer += refResName.toLowerCase() + ","; @@ -123,11 +124,9 @@ } } } - if (f) - fieldInitializer = fieldInitializer.substring(0, fieldInitializer.length() - 1); + if (f) fieldInitializer = fieldInitializer.substring(0, fieldInitializer.length() - 1); fieldInitializer += ")"; - FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), - rn.getIdentifierTemplate().getResourceName()); + FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), rn.getIdentifierTemplate().getResourceName()); mainType.addField(field); Block manConstructorBody = mainConstructor.getBody(); if (manConstructorBody == null) { @@ -139,38 +138,39 @@ // Declare a constructor, fields and update methods in the type of each resource. MethodDeclaration constructor = new MethodDeclaration(resourceName, true); Block block = new Block(); + depends = new HashSet<>(); for (Edge e : rn.getOutEdges()) { ResourceDependency re = (ResourceDependency) e; - String dstResName = ((ResourceNode) re.getDestination()).getIdentifierTemplate().getResourceName() - .substring(0, 1).toUpperCase() - + ((ResourceNode) re.getDestination()).getIdentifierTemplate().getResourceName().substring(1); + IdentifierTemplate dstRes = ((ResourceNode) re.getDestination()).getIdentifierTemplate(); + String dstResName = dstRes.getResourceName().substring(0, 1).toUpperCase() + dstRes.getResourceName().substring(1); if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { // Declare a field to refer to the destination resource of push transfer. - type.addField(new FieldDeclaration(new Type(dstResName, dstResName), - ((ResourceNode) re.getDestination()).getIdentifierTemplate().getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(dstResName, dstResName), - ((ResourceNode) re.getDestination()).getIdentifierTemplate().getResourceName())); + depends.add(dstRes); + type.addField(new FieldDeclaration(new Type(dstResName, dstResName), dstRes.getResourceName())); + constructor.addParameter(new VariableDeclaration(new Type(dstResName, dstResName), dstRes.getResourceName())); block.addStatement("this." + dstResName.toLowerCase() + " = " + dstResName.toLowerCase() + ";"); } } for (Edge e : rn.getInEdges()) { ResourceDependency re = (ResourceDependency) e; - String srcResName = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName() - .substring(0, 1).toUpperCase() - + ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName().substring(1); + IdentifierTemplate srcRes = ((ResourceNode) re.getSource()).getIdentifierTemplate(); + String srcResName = srcRes.getResourceName().substring(0, 1).toUpperCase() + srcRes.getResourceName().substring(1); if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { // Declare a field to refer to the source resource of pull transfer. - type.addField(new FieldDeclaration(new Type(srcResName, srcResName), - ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName())); - constructor.addParameter(new VariableDeclaration(new Type(srcResName, srcResName), - ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName())); + depends.add(srcRes); + type.addField(new FieldDeclaration(new Type(srcResName, srcResName), srcRes.getResourceName())); + constructor.addParameter(new VariableDeclaration(new Type(srcResName, srcResName), srcRes.getResourceName())); block.addStatement("this." + srcResName.toLowerCase() + " = " + srcResName.toLowerCase() + ";"); } else { // Declare an update method in the type of the destination resource. ArrayList vars = new ArrayList<>(); - vars.add(new VariableDeclaration( - ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceStateType(), - ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName())); + vars.add(new VariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); + DataflowChannelGenerator c = (DataflowChannelGenerator) re.getChannelGenerator(); + for (IdentifierTemplate ref: c.getReferenceIdentifierTemplates()) { + if (ref != rn.getIdentifierTemplate()) { + vars.add(new VariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); + } + } type.addMethod(new MethodDeclaration("update" + srcResName, false, typeVoid, vars)); } } @@ -178,15 +178,15 @@ refs = new HashSet<>(); for (ChannelGenerator cg : model.getChannelGenerators()) { DataflowChannelGenerator c = (DataflowChannelGenerator) cg; - if (c.getOutputIdentifierTemplates().contains(rn.getIdentifierTemplate())) { + if (c.getInputIdentifierTemplates().contains(rn.getIdentifierTemplate())) { for (IdentifierTemplate id: c.getReferenceIdentifierTemplates()) { - if (!refs.contains(id)) { + if (!refs.contains(id) && !depends.contains(id)) { refs.add(id); String refResName = id.getResourceName(); refResName = refResName.substring(0, 1).toUpperCase() + refResName.substring(1); type.addField(new FieldDeclaration(new Type(refResName, refResName), id.getResourceName())); constructor.addParameter(new VariableDeclaration(new Type(refResName, refResName), id.getResourceName())); - block.addStatement("this." + refResName.toLowerCase() + " = " + refResName.toLowerCase() + ";"); + block.addStatement("this." + id.getResourceName() + " = " + id.getResourceName() + ";"); } } } @@ -411,7 +411,7 @@ } for (Node n: graph.getNodes()) { // for reference resources. ResourceNode rn = (ResourceNode) n; - for (Edge e : rn.getInEdges()) { + for (Edge e : rn.getOutEdges()) { ResourceDependency re = (ResourceDependency) e; for (ChannelMember m: re.getChannelGenerator().getReferenceChannelMembers()) { if (m.getIdentifierTemplate() == curNode.getIdentifierTemplate()) { @@ -438,7 +438,10 @@ target.getResourceStateType() != null ? target.getResourceStateType() : DataConstraintModel.typeInt); } - return null; + // for reference channel member + return new Parameter(target.getResourceName(), + target.getResourceStateType() != null ? target.getResourceStateType() + : DataConstraintModel.typeInt); } @Override diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java index 4e75870..b553446 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java @@ -46,6 +46,7 @@ // Generate the body of each update or getter method. try { + Map> referredResources = new HashMap<>(); for (Edge e: graph.getEdges()) { ResourceDependency d = (ResourceDependency) e; PushPullAttribute pushPull = (PushPullAttribute) d.getAttribute(); @@ -62,21 +63,7 @@ MethodDeclaration update = getUpdateMethod(dstType, srcType); if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst side resource (when every incoming edge is in push style) - Expression updateExp = null; - if (d.getChannelGenerator().getReferenceChannelMembers().size() == 0) { - updateExp = d.getChannelGenerator().deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor); - } else { - // if there exists one or more reference channel member. - HashMap inputIdentifierToStateAccessor = new HashMap<>(); - for (Edge eIn: dst.getInEdges()) { - ResourceDependency dIn = (ResourceDependency) eIn; - inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), JavaCodeGenerator.pushAccessor); - } - for (ChannelMember c: d.getChannelGenerator().getReferenceChannelMembers()) { - inputIdentifierToStateAccessor.put(c.getIdentifierTemplate(), JavaCodeGenerator.pullAccessor); // by pull transfer - } - updateExp = d.getChannelGenerator().deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor, inputIdentifierToStateAccessor); - } + Expression updateExp = d.getChannelGenerator().deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor); String[] sideEffects = new String[] {""}; String curState = updateExp.toImplementation(sideEffects); String updateStatement; @@ -105,10 +92,54 @@ } // src side (for a chain of update method invocations) for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { - srcUpdate.addStatement(dstResourceName + ".update" + srcType.getTypeName() + "(value);"); + String refParams = ""; + Set referredSet = referredResources.get(srcUpdate); + for (ChannelMember rc: d.getChannelGenerator().getReferenceChannelMembers()) { + // to get the value of reference member. + IdentifierTemplate ref = rc.getIdentifierTemplate(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(srcUpdate, referredSet); + } + if (ref != dst.getIdentifierTemplate()) { + String refVarName = ref.getResourceName(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + Expression refGetter = JavaCodeGenerator.pullAccessor.getCurrentStateAccessorFor(ref, src.getIdentifierTemplate()); + String[] sideEffects = new String[] {""}; + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + srcUpdate.addStatement(sideEffects[0] + refTypeName + " " + refVarName + " = " + refExp + ";"); + } + refParams += ", " + refVarName; + } + } + srcUpdate.addStatement("this." + dstResourceName + ".update" + srcType.getTypeName() + "(value" + refParams + ");"); } for (MethodDeclaration srcInput: getInputMethods(srcType, src, model)) { - srcInput.addStatement(dstResourceName + ".update" + srcType.getTypeName() + "(value);"); + String refParams = ""; + Set referredSet = referredResources.get(srcInput); + for (ChannelMember rc: d.getChannelGenerator().getReferenceChannelMembers()) { + // to get the value of reference member. + IdentifierTemplate ref = rc.getIdentifierTemplate(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(srcInput, referredSet); + } + if (ref != dst.getIdentifierTemplate()) { + String refVarName = ref.getResourceName(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + Expression refGetter = JavaCodeGenerator.pullAccessor.getCurrentStateAccessorFor(ref, src.getIdentifierTemplate()); + String[] sideEffects = new String[] {""}; + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + srcInput.addStatement(sideEffects[0] + refTypeName + " " + refVarName + " = " + refExp + ";"); + } + refParams += ", " + refVarName; + } + } + srcInput.addStatement("this." + dstResourceName + ".update" + srcType.getTypeName() + "(value" + refParams + ");"); } } else { // for pull (or push/pull) data transfer diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java index 7c66b96..58cc392 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java @@ -86,9 +86,8 @@ } for (Edge e : rn.getInEdges()) { ResourceDependency re = (ResourceDependency) e; - String srcResName = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName() - .substring(0, 1).toUpperCase() - + ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName().substring(1); + IdentifierTemplate srcRes = ((ResourceNode) re.getSource()).getIdentifierTemplate(); + String srcResName = srcRes.getResourceName().substring(0, 1).toUpperCase() + srcRes.getResourceName().substring(1); if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { if (!bDeclareClientField) { // Declare a client field to connect to the source resource of pull transfer. @@ -98,11 +97,18 @@ } else { // Declare an update method in the type of the destination resource. ArrayList vars = new ArrayList<>(); - String srcName = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName(); - Type srcType = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceStateType(); + String srcName = srcRes.getResourceName(); + Type srcType = srcRes.getResourceStateType(); VariableDeclaration param = new VariableDeclaration(srcType, srcName); param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); vars.add(param); + for (IdentifierTemplate refRes: re.getChannelGenerator().getReferenceIdentifierTemplates()) { + if (refRes != rn.getIdentifierTemplate()) { + param = new VariableDeclaration(refRes.getResourceStateType(), refRes.getResourceName()); + param.addAnnotation(new Annotation("FormParam", "\"" + refRes.getResourceName() + "\"")); + vars.add(param); + } + } MethodDeclaration update = new MethodDeclaration("update" + srcResName, false, typeVoid, vars); for (ChannelMember cm: re.getChannelGenerator().getOutputChannelMembers()) { if (cm.getIdentifierTemplate() == rn.getIdentifierTemplate()) { @@ -124,23 +130,23 @@ } } - // Declare a client field to connect to the source resource of reference transfer. - if (!bDeclareClientField) { - for (ChannelGenerator cg : model.getChannelGenerators()) { - DataflowChannelGenerator dcg = ((DataflowChannelGenerator) cg); - for (ChannelMember cm : dcg.getOutputChannelMembers()) { - if (cm.getIdentifierTemplate().getResourceName().equals(type.getTypeName().toLowerCase())) { - if (dcg.getReferenceChannelMembers().size() > 0) { - // If there exists one or more reference channel member. - type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; - break; - } - } - } - if (bDeclareClientField) break; - } - } +// // Declare a client field to connect to the source resource of reference transfer. +// if (!bDeclareClientField) { +// for (ChannelGenerator cg : model.getChannelGenerators()) { +// DataflowChannelGenerator dcg = ((DataflowChannelGenerator) cg); +// for (ChannelMember cm : dcg.getOutputChannelMembers()) { +// if (cm.getIdentifierTemplate().getResourceName().equals(type.getTypeName().toLowerCase())) { +// if (dcg.getReferenceChannelMembers().size() > 0) { +// // If there exists one or more reference channel member. +// type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); +// bDeclareClientField = true; +// break; +// } +// } +// } +// if (bDeclareClientField) break; +// } +// } // Declare input methods in resources. for (ChannelGenerator cg : model.getIOChannelGenerators()) { diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java index 580df67..b691e8a 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java @@ -53,6 +53,7 @@ // Generate the body of each update or getter method. try { Set chainedCalls = new HashSet<>(); + Map> referredResources = new HashMap<>(); for (Edge e: graph.getEdges()) { ResourceDependency d = (ResourceDependency) e; PushPullAttribute pushPull = (PushPullAttribute) d.getAttribute(); @@ -95,14 +96,6 @@ if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { // add an update statement of the state of dst side resource. update.addFirstStatement(updateStatement); - if (d.getChannelGenerator().getReferenceChannelMembers().size() > 0) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - for (ChannelMember c: d.getChannelGenerator().getReferenceChannelMembers()) { - String refResourceName = c.getIdentifierTemplate().getResourceName(); - Type refResourceType = c.getIdentifierTemplate().getResourceStateType(); - generatePullDataTransfer(update, refResourceName, refResourceType); - } - } } } if (dst.getIndegree() > 1) { @@ -112,7 +105,7 @@ update.addFirstStatement(cashStatement); } } - // to convert a json param to a tuple or pair object. + // to convert a json param to a tuple, pair or map object. for (VariableDeclaration param: update.getParameters()) { Type paramType = param.getType(); String paramName = param.getName(); @@ -139,6 +132,9 @@ paramConverter += "\t" + paramName + ".add(" + getCodeForConversionFromMapToPair(compType, "i") + ");\n"; paramConverter += "}"; update.addThrow("JsonProcessingException"); + } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { + param.setType(DataConstraintModel.typeListStr); + // To do. } } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType)) { param.setType(DataConstraintModel.typeString); @@ -160,6 +156,16 @@ paramConverter += "\t" + paramName + " = " + getCodeForConversionFromMapToPair(paramType, "i") + ";\n"; paramConverter += "}"; update.addThrow("JsonProcessingException"); + } else if (DataConstraintModel.typeMap.isAncestorOf(paramType)) { + param.setType(DataConstraintModel.typeString); + param.setName(paramName + "_json"); + paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = " + "new " + paramType.getImplementationTypeName() + "();\n"; + paramConverter += "{\n"; + String mapTypeName = convertFromEntryToMapType(paramType); + paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; + paramConverter += "\t" + getCodeForConversionFromMapToMap(paramType, "i", paramName) + "\n"; + paramConverter += "}"; + update.addThrow("JsonProcessingException"); } if (paramConverter.length() > 0) update.addFirstStatement(paramConverter); } @@ -179,30 +185,86 @@ } for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { if (srcUpdate != null) { + List>> params = new ArrayList<>(); + Set referredSet = referredResources.get(srcUpdate); + if (d.getChannelGenerator().getReferenceChannelMembers().size() > 0) { + for (ChannelMember rc: d.getChannelGenerator().getReferenceChannelMembers()) { + // For each reference channel member, get the current state of the reference side resource by pull data transfer. + IdentifierTemplate ref = rc.getIdentifierTemplate(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(srcUpdate, referredSet); + } + if (ref != dst.getIdentifierTemplate()) { + String refResourceName = ref.getResourceName(); + Type refResourceType = ref.getResourceStateType(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + generatePullDataTransfer(srcUpdate, refResourceName, refResourceType); + } + // Value of a reference side resource. + params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); + } + } + } String srcResName = null; if (dst.getIndegree() > 1) { srcResName = srcResourceName; } if (!chainedCalls.contains(srcUpdate)) { - srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), src.getIdentifierTemplate().getResourceStateType(), srcResourceName, "this.value")); + // The first call to an update method in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, true)); srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); chainedCalls.add(srcUpdate); } else { + // After the second time of call to update methods in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, false)); srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); } srcUpdate.addThrow("JsonProcessingException"); } } for (MethodDeclaration srcInput: getInputMethods(srcType, src, model)) { + List>> params = new ArrayList<>(); + Set referredSet = referredResources.get(srcInput); + for (ChannelMember rc: d.getChannelGenerator().getReferenceChannelMembers()) { + // For each reference channel member, get the current state of the reference side resource by pull data transfer. + IdentifierTemplate ref = rc.getIdentifierTemplate(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(srcInput, referredSet); + } + if (ref != dst.getIdentifierTemplate()) { + String refResourceName = ref.getResourceName(); + Type refResourceType = ref.getResourceStateType(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + generatePullDataTransfer(srcInput, refResourceName, refResourceType); + } + // Value of a reference side resource. + params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); + } + } String srcResName = null; if (dst.getIndegree() > 1) { srcResName = srcResourceName; } if (!chainedCalls.contains(srcInput)) { - srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), src.getIdentifierTemplate().getResourceStateType(), srcResourceName, "this.value")); + // First call to an update method in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, true)); srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); chainedCalls.add(srcInput); } else { + // After the second time of call to update methods in this method + // Value of the source side (input side) resource. + params.add(0, new AbstractMap.SimpleEntry<>(src.getIdentifierTemplate().getResourceStateType(), new AbstractMap.SimpleEntry<>(srcResourceName, "this.value"))); + srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), params, false)); srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); } srcInput.addThrow("JsonProcessingException"); @@ -287,6 +349,8 @@ respConverter += "\t" + fromResourceName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i") + ");\n"; respConverter += "}"; methodBody.addThrow("JsonProcessingException"); + } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { + // To do. } } else if (DataConstraintModel.typeTuple.isAncestorOf(fromResourceType)) { varName += "_json"; @@ -298,6 +362,12 @@ respTypeName = convertFromEntryToMapType(fromResourceType); respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = " + getCodeForConversionFromMapToPair(fromResourceType, varName) + ";"; respImplTypeName = "HashMap"; + } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { + varName += "_json"; + respTypeName = convertFromEntryToMapType(fromResourceType); + respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = new " + fromResourceType.getImplementationTypeName() + "();\n"; + respConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName); + respImplTypeName = "HashMap"; } if (respConverter.length() > 0) { methodBody.addFirstStatement(respConverter); @@ -315,6 +385,14 @@ } else { mapTypeName = "Map"; } + } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { + List compTypes = TypeInference.getMapComponentTypes(type); + String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); + if (wrapperType != null) { + mapTypeName = "Map"; + } else { + mapTypeName = "Map"; + } } else { mapTypeName = type.getInterfaceTypeName(); mapTypeName = mapTypeName.replace("Map.Entry", "Map"); @@ -359,31 +437,65 @@ return decoded; } - private static String getHttpMethodParamsStatement(String callerResourceName, Type paramType, String paramName, String value) { - if (DataConstraintModel.typeList.isAncestorOf(paramType)) { - Type compType = TypeInference.getListComponentType(paramType); - String statements = "Form form = new Form();\n"; - String wrapperType = DataConstraintModel.getWrapperType(compType); - if (wrapperType == null) { - statements += "for (" + compType.getInterfaceTypeName() + " i: " + value + ") {\n"; - } else { - statements += "for (" + wrapperType + " i: " + value + ") {\n"; - } - if (DataConstraintModel.typeTuple.isAncestorOf(compType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeList.isAncestorOf(compType)) { - statements += "\tform.param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(i));\n"; // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} - } else { - statements += "\tform.param(\"" + paramName + "\", i.toString());\n"; - } - statements += "}\n"; - statements += "Entity
entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED);"; - return statements; -// return "Entity entity = Entity.entity(" + paramName + ".toString(), MediaType.APPLICATION_JSON);"; - } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType) || DataConstraintModel.typePair.isAncestorOf(paramType)) { - // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} - return "Entity entity = Entity.entity(new Form().param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(" + value + ")), MediaType.APPLICATION_FORM_URLENCODED_TYPE);"; - } else { - return "Entity entity = Entity.entity(new Form().param(\"" + paramName + "\", " + CodeUtil.getToStringExp(paramType.getImplementationTypeName(), value) + "), MediaType.APPLICATION_FORM_URLENCODED_TYPE);"; + private static String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar) { + List elementsTypes = TypeInference.getMapComponentTypes(mapType); + Type keyType = elementsTypes.get(0); + Type valType = elementsTypes.get(1); + String keyVal = null; + String decoded = ""; + if (keyType == DataConstraintModel.typeBoolean + || keyType == DataConstraintModel.typeInt + || keyType == DataConstraintModel.typeLong + || keyType == DataConstraintModel.typeFloat + || keyType == DataConstraintModel.typeDouble) { + decoded += "for (String k: " + mapVal + ".keySet()) {\n"; + decoded += "\t" + mapVar + ".put("; + keyVal = CodeUtil.getToValueExp(keyType.getImplementationTypeName(), "k"); + decoded += keyVal + ", " + mapVal + ".get(" + keyVal + ")" + ");\n"; + decoded += "}"; + } else if (keyType == DataConstraintModel.typeString) { + decoded += mapVar + " = " + mapVal + ";"; } + return decoded; + } + + private static String getHttpMethodParamsStatement(String callerResourceName, List>> params, boolean isFirstCall) { + String statements = ""; + if (isFirstCall) { + statements += "Form "; + } + statements += "form = new Form();\n"; + for (Map.Entry> param: params) { + Type paramType = param.getKey(); + String paramName = param.getValue().getKey(); + String value = param.getValue().getValue(); + if (DataConstraintModel.typeList.isAncestorOf(paramType)) { + Type compType = TypeInference.getListComponentType(paramType); + String wrapperType = DataConstraintModel.getWrapperType(compType); + if (wrapperType == null) { + statements += "for (" + compType.getInterfaceTypeName() + " i: " + value + ") {\n"; + } else { + statements += "for (" + wrapperType + " i: " + value + ") {\n"; + } + if (DataConstraintModel.typeTuple.isAncestorOf(compType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeList.isAncestorOf(compType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { + statements += "\tform.param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(i));\n"; // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + } else { + statements += "\tform.param(\"" + paramName + "\", i.toString());\n"; + } + statements += "}\n"; +// return "Entity entity = Entity.entity(" + paramName + ".toString(), MediaType.APPLICATION_JSON);"; + } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { + // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + statements += "form.param(\"" + paramName + "\", new ObjectMapper().writeValueAsString(" + value + "));\n"; + } else { + statements += "form.param(\"" + paramName + "\", " + CodeUtil.getToStringExp(paramType.getImplementationTypeName(), value) + ");\n"; + } + } + if (isFirstCall) { + statements += "Entity "; + } + statements += "entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED);"; + return statements; } private static String getHttpMethodCallStatement(String baseURL, String resourceName, String srcResName, String httpMethod) { diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index df93e13..706841f 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java @@ -513,7 +513,18 @@ if (argType == DataConstraintModel.typeTuple && t.getType() != null) { List compTypeList = new ArrayList<>(); compTypeList.add(null); - compTypeList.add(t.getType()); + if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { + List sndTypes = tupleComponentTypes.get(t.getType()); + if (sndTypes != null) { + for (Type t2: sndTypes) { + compTypeList.add(t2); + } + } else { + compTypeList.add(t.getType()); + } + } else { + compTypeList.add(t.getType()); + } newTupleType = tupleTypes.get(compTypeList); if (newTupleType == null) { // Create new tuple type; @@ -1012,6 +1023,23 @@ } } } + } else { + Map updateVars = getUpdateSet(updateFromVariable, sameVariable); + for (Expression v : sameVariable) { + if (v instanceof Variable) { + Type orgVarType = ((Variable) v).getType(); + if (orgVarType != varType && compareTypes(orgVarType, varType)) { + ((Variable) v).setType(varType); + updateVars.put(System.identityHashCode(v), v); + } + } else if (v instanceof Term) { + Type orgVarType = ((Term) v).getType(); + if (orgVarType != varType && compareTypes(orgVarType, varType)) { + ((Term) v).setType(varType); + updateVars.put(System.identityHashCode(v), v); + } + } + } } } @@ -1147,14 +1175,58 @@ for (int i = 1; i < tupleComponentGroup.size(); i++) { Expression compExp = tupleComponentGroup.get(i); if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), componentTypes.get(i - 1))) { - ((Variable) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); + Type compType = ((Variable) compExp).getType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + // If the type of one component (compExp) is also tuple. + Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); + if (newExpType == null) { + // Create new tuple type; + newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); + } + if (compareTypes(compType, newExpType)) { + ((Variable) compExp).setType(newExpType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + if (i - 1 < componentTypes.size()) { + if (compareTypes(compType, componentTypes.get(i - 1))) { + ((Variable) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + // for insert + if (compareTypes(compType, newTupleType)) { + ((Variable) compExp).setType(newTupleType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } } } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), componentTypes.get(i - 1))) { - ((Term) compExp).setType(componentTypes.get(i - 1)); - updateExps.put(System.identityHashCode(compExp), compExp); + Type compType = ((Term) compExp).getType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + // If the type of one component (compExp) is also tuple. + Type newExpType = tupleTypes.get(componentTypes.subList(i - 1, componentTypes.size())); + if (newExpType == null) { + // Create new tuple type; + newExpType = createNewTupleType(componentTypes.subList(i - 1, componentTypes.size()), compType); + } + if (compareTypes(compType, newExpType)) { + ((Term) compExp).setType(newExpType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + if (i - 1 < componentTypes.size()) { + if (compareTypes(compType, componentTypes.get(i - 1))) { + ((Term) compExp).setType(componentTypes.get(i - 1)); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else { + // for insert + if (compareTypes(compType, newTupleType)) { + ((Term) compExp).setType(newTupleType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } } } } @@ -1162,12 +1234,47 @@ } else { Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); List componentTypes = tupleComponentTypes.get(tupleType); - Type compType = componentTypes.get(idx - 1); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { + boolean updated = false; + if (idx == 1) { + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + updated = true; + } + } else { + Type expType = null; + if (exp instanceof Term) { + expType = ((Term) exp).getType(); + } else if (exp instanceof Variable) { + expType = ((Variable) exp).getType(); + } + if (expType != null && DataConstraintModel.typeTuple.isAncestorOf(expType)) { + // If the type of the updated component (exp) is also tuple. + List subCompTypes = tupleComponentTypes.get(expType); + componentTypes = new ArrayList<>(componentTypes); + for (int i = 0; i < subCompTypes.size(); i++) { + if (componentTypes.size() < i + 2) { + componentTypes.add(subCompTypes.get(i)); + updated = true; + } else if (compareTypes(componentTypes.get(i + 1), subCompTypes.get(i))) { + componentTypes.set(i + 1, subCompTypes.get(i)); + updated = true; + } + } + } else { + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + updated = true; + } + } + } + if (updated) { // Propagate an update of a component's type to its container's (tuple's) type. - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); Type newTupleType = tupleTypes.get(componentTypes); if (newTupleType == null) { // Create new tuple type; @@ -1271,7 +1378,7 @@ } // Propagate an update of a map's type to another map's type. Expression compExp = null; - if (idx == 0 && mapComponentGroup.size() == 4) { // for lookup + if (idx == 0 && mapComponentGroup.size() == 4) { // for insert compExp = mapComponentGroup.get(3); } else if (idx == 3) { compExp = mapComponentGroup.get(0); @@ -1313,7 +1420,7 @@ ((Term) mapExp).setType(newMapType); updateExps.put(System.identityHashCode(mapExp), mapExp); } - if (mapComponentGroup.size() == 4) { // for lookup + if (mapComponentGroup.size() == 4) { // for insert mapExp = mapComponentGroup.get(3); if (mapExp instanceof Variable) { ((Variable) mapExp).setType(newMapType); @@ -1471,21 +1578,18 @@ * of the new type, false: otherwise */ private static boolean compareTypes(Type originalType, Type newType) { - if (originalType == null) - return true; + if (originalType == null) return true; if (originalType != newType && newType != null) { - if (originalType.isAncestorOf(newType)) - return true; + if (originalType.isAncestorOf(newType)) return true; + if (newType.isAncestorOf(originalType)) return false; if (DataConstraintModel.typeMap.isAncestorOf(originalType) && DataConstraintModel.typeMap.isAncestorOf(newType)) { List originalCompTypes = mapComponentTypes.get(originalType); List newCompTypes = mapComponentTypes.get(newType); - if (originalCompTypes == null) - return true; + if (originalCompTypes == null) return true; for (int i = 0; i < originalCompTypes.size(); i++) { - if (originalCompTypes.get(i) != null && (newCompTypes.get(i) == null - || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i)))) - return false; + if (originalCompTypes.get(i) != null && + (newCompTypes.get(i) == null || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i)))) return false; } return true; } @@ -1493,12 +1597,26 @@ && DataConstraintModel.typeTuple.isAncestorOf(newType)) { List originalCompTypes = tupleComponentTypes.get(originalType); List newCompTypes = tupleComponentTypes.get(newType); - if (originalCompTypes == null) - return true; + if (originalCompTypes == null) return true; + originalCompTypes = new ArrayList<>(originalCompTypes); + newCompTypes = new ArrayList<>(newCompTypes); for (int i = 0; i < originalCompTypes.size(); i++) { - if (originalCompTypes.get(i) != null && (newCompTypes.get(i) == null - || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i)))) - return false; + if (originalCompTypes.get(i) != null) { + if (DataConstraintModel.typeTuple.isAncestorOf(originalCompTypes.get(i))) { + Type tupleType = originalCompTypes.remove(i); + for (Type t: tupleComponentTypes.get(tupleType)) { + originalCompTypes.add(t); + } + } + if (newCompTypes.size() - 1 < i) return false; + if (newCompTypes.get(i) != null && DataConstraintModel.typeTuple.isAncestorOf(newCompTypes.get(i))) { + Type tupleType = newCompTypes.remove(i); + for (Type t: tupleComponentTypes.get(tupleType)) { + newCompTypes.add(t); + } + } + if (newCompTypes.get(i) == null || !originalCompTypes.get(i).isAncestorOf(newCompTypes.get(i))) return false; + } } return true; } @@ -1506,8 +1624,7 @@ && DataConstraintModel.typeList.isAncestorOf(newType)) { Type originalCompType = listComponentTypes.get(originalType); Type newCompType = listComponentTypes.get(newType); - if (originalCompType != null && (newCompType == null || !originalCompType.isAncestorOf(newCompType))) - return false; + if (originalCompType != null && (newCompType == null || !originalCompType.isAncestorOf(newCompType))) return false; return true; } }