diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/FinalDecisionOfStoringResourceStates.java b/AlgebraicDataflowArchitectureModel/src/algorithms/FinalDecisionOfStoringResourceStates.java index 999e9c1..715fdd2 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/FinalDecisionOfStoringResourceStates.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/FinalDecisionOfStoringResourceStates.java @@ -9,10 +9,10 @@ import models.dataFlowModel.*; public class FinalDecisionOfStoringResourceStates { - static private HashSet arrivedNode = new HashSet<>(); + static private HashSet reachableNodes = new HashSet<>(); static public void doDecide(ResourceDependencyGraph graph) { - arrivedNode.clear(); + reachableNodes.clear(); for (Node n : graph.getNodes()) { ResourceNode resource = (ResourceNode) n; trackNode(resource); @@ -20,27 +20,26 @@ } static private void trackNode(ResourceNode resource) { - if (arrivedNode.contains(resource)) + if (reachableNodes.contains(resource)) return; - arrivedNode.add(resource); - boolean flag = false; + reachableNodes.add(resource); + boolean flag = true; for (Edge e : resource.getInEdges()) { - if (((PushPullAttribute) e.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + if (((PushPullAttribute) e.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + // Traverse pull edges only. trackNode((ResourceNode) e.getSource()); - flag = true; + flag = false; } } - if (resource.getInEdges().size() == 0) - flag = true; +// if (resource.getInEdges().size() == 0) +// flag = true; ((StoreAttribute) resource.getAttribute()).setStored(flag); if (resource.getIdentifierTemplate().getResourceStateType() == null) { for (Edge e : resource.getInEdges()) { for (ChannelMember cm : ((ResourceDependency) e).getChannelGenerator().getChannelMembers()) { - if (((PushPullAttribute) ((ResourceDependency) e).getAttribute()).getOptions() - .get(0) == PushPullValue.PUSH + if (((PushPullAttribute) ((ResourceDependency) e).getAttribute()).getOptions().get(0) == PushPullValue.PUSH && cm.getStateTransition().getNextStateExpression().getClass() == Term.class) { - if (((Term) cm.getStateTransition().getNextStateExpression()).getSymbol().getName() - .equals("cons")) { + if (((Term) cm.getStateTransition().getNextStateExpression()).getSymbol().getName().equals("cons")) { resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeList); } } @@ -49,11 +48,9 @@ } for (Edge e : resource.getOutEdges()) { for (ChannelMember cm : ((ResourceDependency) e).getChannelGenerator().getChannelMembers()) { - if (((PushPullAttribute) ((ResourceDependency) e).getAttribute()).getOptions() - .get(0) != PushPullValue.PUSH + if (((PushPullAttribute) ((ResourceDependency) e).getAttribute()).getOptions().get(0) != PushPullValue.PUSH && cm.getStateTransition().getNextStateExpression().getClass() == Term.class) { - if (((Term) cm.getStateTransition().getNextStateExpression()).getSymbol().getName() - .equals("cons")) { + if (((Term) cm.getStateTransition().getNextStateExpression()).getSymbol().getName().equals("cons")) { resource.getIdentifierTemplate().setResourceStateType(DataConstraintModel.typeList); } } diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java index 25de41f..74acd2b 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaCodeGenerator.java @@ -89,10 +89,12 @@ fieldInitializer += rename.toLowerCase() + ","; f = true; } else { - if (rn.getIndegree() > 1) + if (rn.getIndegree() > 1) { + // Declare a field to cash the state of the source resource in the type of the destination resource. type.addField(new FieldDeclaration( ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceStateType(), ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName())); + } } } if (f) @@ -135,7 +137,7 @@ block.addStatement("this." + srcResName.toLowerCase() + " = " + srcResName.toLowerCase() + ";"); constructor.setBody(block); } else { - // Declare an update method in the type of each resource. + // Declare an update method in the type of the destination resource. ArrayList vars = new ArrayList<>(); vars.add(new VariableDeclaration( ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceStateType(), diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java index 650fa06..b612a08 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JavaMethodBodyGenerator.java @@ -3,6 +3,7 @@ import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import code.ast.CompilationUnit; @@ -19,8 +20,10 @@ import models.algebra.ValueUndefined; import models.dataConstraintModel.ChannelGenerator; import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.IdentifierTemplate; import models.dataFlowModel.DataFlowModel; import models.dataFlowModel.DataflowChannelGenerator; +import models.dataFlowModel.DataflowChannelGenerator.IResourceStateAccessor; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; @@ -92,8 +95,11 @@ } } MethodDeclaration getter = getGetterMethod(dstType); - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - getter.addStatement("return " + dstResourceName + ";"); + if (((StoreAttribute) dst.getAttribute()).isStored()) { + // returns the current state stored in a field. + if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { + getter.addStatement("return " + dstResourceName + ";"); + } } // src side (for a chain of update method invocations) for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { @@ -105,8 +111,26 @@ // for pull (or push/pull) data transfer MethodDeclaration getter = getGetterMethod(dstType); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - String curState = d.getChannelGenerator().deriveUpdateExpressionOf(out, JavaCodeGenerator.pullAccessor).toImplementation(); - getter.addStatement("return " + curState + ";"); + boolean isContainedPush = false; + HashMap inputIdentifierToStateAccessor = new HashMap<>(); + for (Edge eIn: dst.getInEdges()) { + ResourceDependency dIn = (ResourceDependency) eIn; + if (((PushPullAttribute) dIn.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + isContainedPush = true; + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), JavaCodeGenerator.pushAccessor); + } else { + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), JavaCodeGenerator.pullAccessor); + } + } + if (!isContainedPush) { + // All incoming edges are in PULL style. + String curState = d.getChannelGenerator().deriveUpdateExpressionOf(out, JavaCodeGenerator.pullAccessor).toImplementation(); + getter.addStatement("return " + curState + ";"); + } else { + // At least one incoming edge is in PUSH style. + String curState = d.getChannelGenerator().deriveUpdateExpressionOf(out, JavaCodeGenerator.pullAccessor, inputIdentifierToStateAccessor).toImplementation(); + getter.addStatement("return " + curState + ";"); + } } } } @@ -170,8 +194,8 @@ return null; } - private static ArrayList getUpdateMethods(TypeDeclaration type) { - ArrayList updates = new ArrayList<>(); + private static List getUpdateMethods(TypeDeclaration type) { + List updates = new ArrayList<>(); for (MethodDeclaration m: type.getMethods()) { if (m.getName().startsWith("update")) { updates.add(m); diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java index 8cf0ab2..36b376d 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyCodeGenerator.java @@ -84,12 +84,14 @@ String srcResName = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName() .substring(0, 1).toUpperCase() + ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName().substring(1); - if (!bDeclareClientField && ((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - // Declare a client field to connect to the source resource of pull transfer. - type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); - bDeclareClientField = true; + if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + if (!bDeclareClientField) { + // Declare a client field to connect to the source resource of pull transfer. + type.addField(new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()")); + bDeclareClientField = true; + } } else { - // Declare an update method in the type of each resource. + // Declare an update method in the type of the destination resource. ArrayList vars = new ArrayList<>(); String srcName = ((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceName(); VariableDeclaration param = new VariableDeclaration(((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceStateType(), srcName); @@ -101,6 +103,12 @@ } else { update.addAnnotation(new Annotation("PUT")); } + if (rn.getInEdges().size() > 1) { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); + // Declare a field to cash the state of the source resource in the type of the destination resource. + type.addField(new FieldDeclaration(((ResourceNode) re.getSource()).getIdentifierTemplate().getResourceStateType(), srcName)); + } type.addMethod(update); } } diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java index e0f426e..ff6e7de 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/JerseyMethodBodyGenerator.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -34,6 +35,8 @@ import models.dataFlowModel.StoreAttribute; public class JerseyMethodBodyGenerator { + private static String baseURL = "http://localhost:8080"; + public static ArrayList doGenerate(ResourceDependencyGraph graph, DataFlowModel model, ArrayList codes) { Symbol floor = model.getSymbol("floor"); Symbol.Memento floorMem = null; @@ -74,7 +77,7 @@ if (out.getIdentifierTemplate() == dst.getIdentifierTemplate()) { if (pushPull.getOptions().get(0) == PushPullValue.PUSH && srcType != null) { // for push data transfer - MethodDeclaration update = getUpdateMethod(dstType); + MethodDeclaration update = getUpdateMethod(dstType, srcType); if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst resource (when every incoming edge is in push style) Expression updateExp = d.getChannelGenerator().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor); @@ -97,8 +100,11 @@ } } MethodDeclaration getter = getGetterMethod(dstType); - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - getter.addStatement("return " + dstResourceName + ";"); + if (((StoreAttribute) dst.getAttribute()).isStored()) { + // returns the state stored in a field. + if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { + getter.addStatement("return " + dstResourceName + ";"); + } } // src side (for a chain of update method invocations) String httpMethod = null; @@ -107,34 +113,43 @@ } else { httpMethod = "put"; } - MethodDeclaration srcUpdate = getUpdateMethod(srcType); - if (srcUpdate != null) { - if (!chainedCalls.contains(srcUpdate)) { - srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), src.getIdentifierTemplate().getResourceStateType(), srcResourceName)); - srcUpdate.addStatement("String result = " + getHttpMethodCallStatement("http://localhost:8080", dstResourceName, httpMethod)); - chainedCalls.add(srcUpdate); - } else { - srcUpdate.addStatement("result = " + getHttpMethodCallStatement("http://localhost:8080", dstResourceName, httpMethod)); + for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { + if (srcUpdate != null) { + String srcResName = null; + if (dst.getIndegree() > 1) { + srcResName = srcResourceName; + } + if (!chainedCalls.contains(srcUpdate)) { + srcUpdate.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), src.getIdentifierTemplate().getResourceStateType(), srcResourceName)); + srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); + chainedCalls.add(srcUpdate); + } else { + srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); + } } } MethodDeclaration srcInput = getInputMethod(srcType, src, model); if (srcInput != null) { + String srcResName = null; + if (dst.getIndegree() > 1) { + srcResName = srcResourceName; + } if (!chainedCalls.contains(srcInput)) { srcInput.addStatement(getHttpMethodParamsStatement(srcType.getTypeName(), src.getIdentifierTemplate().getResourceStateType(), srcResourceName)); - srcInput.addStatement("String result = " + getHttpMethodCallStatement("http://localhost:8080", dstResourceName, httpMethod)); + srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); chainedCalls.add(srcInput); } else { - srcInput.addStatement("result = " + getHttpMethodCallStatement("http://localhost:8080", dstResourceName, httpMethod)); + srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstResourceName, srcResName, httpMethod)); } } } else { // for pull (or push/pull) data transfer MethodDeclaration getter = getGetterMethod(dstType); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - getter.addStatement(getHttpMethodCallStatement("http://localhost:8080", srcResourceName, "get", src.getIdentifierTemplate().getResourceStateType())); String curState = d.getChannelGenerator().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pullAccessor).toImplementation(); getter.addStatement("return " + curState + ";"); } + getter.addFirstStatement(getHttpMethodCallStatement(baseURL, srcResourceName, "get", src.getIdentifierTemplate().getResourceStateType())); } } } @@ -195,8 +210,13 @@ return "Entity
entity = Entity.entity(new Form().param(\"" + paramName + "\", " + CodeUtil.getToStringExp(paramType.getImplementationTypeName(), paramName) + "), MediaType.APPLICATION_FORM_URLENCODED_TYPE);"; } - private static String getHttpMethodCallStatement(String baseURL, String resourceName, String httpMethod) { - return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(entity, String.class);"; + private static String getHttpMethodCallStatement(String baseURL, String resourceName, String srcResName, String httpMethod) { + if (srcResName == null) { + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(entity, String.class);"; + } else { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "/" + srcResName + "\").request()." + httpMethod + "(entity, String.class);"; + } } private static String getHttpMethodCallStatement(String baseURL, String resourceName, String httpMethod, Type responseType) { @@ -208,12 +228,22 @@ return responseTypeName + " " + resourceName + " = client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(" + responseShortTypeName + ".class);"; } - private static MethodDeclaration getUpdateMethod(TypeDeclaration type) { + private static MethodDeclaration getUpdateMethod(TypeDeclaration type, TypeDeclaration from) { for (MethodDeclaration m: type.getMethods()) { - if (m.getName().startsWith("update")) return m; + if (m.getName().equals("update" + from.getTypeName())) return m; } return null; } + + private static List getUpdateMethods(TypeDeclaration type) { + List updates = new ArrayList<>(); + for (MethodDeclaration m: type.getMethods()) { + if (m.getName().startsWith("update")) { + updates.add(m); + } + } + return updates; + } private static MethodDeclaration getGetterMethod(TypeDeclaration type) { for (MethodDeclaration m: type.getMethods()) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java index 35c63ff..a04eefb 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataflowChannelGenerator.java @@ -104,9 +104,14 @@ }; return deriveUpdateExpressionOf(targetMember, defaultStateAccessor); } - + public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + return deriveUpdateExpressionOf(targetMember, stateAccessor, null); + } + + public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, HashMap inputIdentifierToStateAccessor) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { if (!getOutputChannelMembers().contains(targetMember)) return null; HashSet messageConstraints = new HashSet<>(); @@ -116,8 +121,15 @@ if (inputIdentifier.getNumberOfParameters() > 0) { throw new ParameterizedIdentifierIsFutureWork(); } - Expression curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); - Expression nextInputStateAccessor = stateAccessor.getNextStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); + Expression curInputStateAccessor = null; + Expression nextInputStateAccessor = null; + if (inputIdentifierToStateAccessor == null) { + curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); + nextInputStateAccessor = stateAccessor.getNextStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); + } else { + curInputStateAccessor = inputIdentifierToStateAccessor.get(inputIdentifier).getCurrentStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); + nextInputStateAccessor = inputIdentifierToStateAccessor.get(inputIdentifier).getNextStateAccessorFor(inputIdentifier, targetMember.getIdentifierTemplate()); + } Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor); messageConstraints.add((Term) messageConstraintByInput); }